I want to customize ToolStripMenuItem by overriding OnPaint function. This is a MyToolStripMenuItem:
public class MyToolStripMenuItem : ToolStripMenuItem
{
public MyToolStripMenuItem()
:base()
{
}
public MyToolStripMenuItem(string t)
:base(t)
{
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle r = this.Bounds;
g.FillRectangle(Brushes.Blue, r);
g.DrawString(this.Text, this.Font, Brushes.Red, r);
}
}
In my code, I will fill a blue color in item's bound. Now, I will create a list of items on menustrip:
MyToolStripMenuItem1
|___MyToolStripMenuItem2
|___MyToolStripMenuItem3
I don't know why MyToolStripMenuItem3 don't have a blue background.
This is my source code:
http://www.mediafire.com/?2qhmjzzfzzn
Please help me. Thanks.
It's not the way it is done with a ToolStripMenuItem. You give the MenuStrip a custom renderer. For example:
For example:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
menuStrip1.Renderer = new MyRenderer();
}
private class MyRenderer : ToolStripProfessionalRenderer {
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e) {
if (!e.Item.Selected) base.OnRenderMenuItemBackground(e);
else {
Rectangle rc = new Rectangle(Point.Empty, e.Item.Size);
e.Graphics.FillRectangle(Brushes.Beige, rc);
e.Graphics.DrawRectangle(Pens.Black, 1, 0, rc.Width - 2, rc.Height - 1);
}
}
}
}
The problem with using OnRenderMenuItemBackground() is that it applies to the whole menu and not just the one ToolStripMenuItem.
The error in the code lies in Rectangle r = this.Bounds; which produces the wrong area. Change this to Rectangle r = e.ClipRectangle and it should work ok. (For some reason the Bounds has the wrong Y component).
Related
I'm interested in learning about C# GDI+ and have googled many tutorials. I'm attempting to create a simple windows form that has two textbox controls and a button. I simply want to put a length dimension in one textbox and a height dimension in the other, click the button and have the app draw the rectangle on the window using those two entered dimensions. To date, all I have been able to do is locate tutorials where the rectangle parameters are hardcoded into the Form_Load and Form_Paint. How would I take the user input from the textboxes and pass them to make the app refresh and draw the rectangles on the button click?
Please let me know if more info is needed.
Thanks in advance for your knowledge!
public partial class Form1 : Form
{
Bitmap drwBitmap;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Graphics graphicObj;
drwBitmap = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
graphicObj = Graphics.FromImage(drwBitmap);
graphicObj.Clear(Color.White);
Pen myPen = new Pen(System.Drawing.Color.Red, 3);
Rectangle rectObj;
rectObj = new Rectangle(10, 10, 100, 200);
graphicObj.DrawEllipse(myPen, rectObj);
graphicObj.Dispose();
}
private void Form1_Paint(object sender, PaintEventArgs e, Graphics graphicsObj)
{
Graphics graphicsObj1 = graphicsObj;
graphicsObj1.DrawImage(drwBitmap, 0, 0, drwBitmap.Width, drwBitmap.Height);
graphicsObj.Dispose();
}
The current approach is quite strange as it draws directly to the form. It's difficult to modify as a bitmap is created early on and then must somehow be changed. Furthermore, there is no need for a bitmap.
A better approach is to create a custom control:
public class EllipseControl : Control
{
private float m_ellipseWidth = 200;
private float m_ellipseHeight = 120;
public float EllipseWidth
{
get { return m_ellipseWidth; }
set
{
m_ellipseWidth = value;
Invalidate();
}
}
public float EllipseHeight
{
get { return m_ellipseHeight; }
set
{
m_ellipseHeight = value;
Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var graphics = e.Graphics;
using Pen pen = new Pen(System.Drawing.Color.Red, 3);
graphics.DrawEllipse(pen, 0, 0, EllipseWidth, EllipseHeight);
}
}
This control can then be placed on the form. It has two properties: EllipseWidth and EllipseHeight.
In the event handler for the button click, you can take the values from the text fields and set them on the ellipse control.
I am creating a Graphics Form where objects with coordinates x,y are being drawn into the Graphics. It works properly for small x and y, but when I want to draw them in different place (f.e. x = 500, y = 300) they disappear.
public WindowHandler()
{
dc = this.CreateGraphics();
this.Size = new Size(sizeX, sizeY); // 800x600
startSimulation = new Button
{
// button properties
};
this.Controls.Add(startSimulation);
startSimulation.Click += new EventHandler(StartSimulationClick);
}
private void CreationsMethods()
{
creations.PaintAllAnimals(dc);
}
public void PaintAllAnimals(Graphics g)
{
foreach (var animal in ecoStructure.world.animals)
{
animal.PaintAnimal(g);
}
}
public void PaintAnimal(Graphics graphics)
{
Rectangle rectangle = new Rectangle(x, y, 3, 3);
Pen pen = new Pen(colour);
graphics.DrawRectangle(pen, rectangle);
graphics.FillRectangle(colour, rectangle);
}
I want to put all the objects onto the window. Is there any way to make the Graphics "bigger"? Do I need to make another one? Or should I use different tool to draw rectangles?
Thanks to #Chris Dunaway for posting an answer in comment.
So I deleted the CreateCraphics, and instead of that i am now using an OnPaint method. It works slowly, but works. So I will try to make it as fast as i can. For now, I just created this. NextStepClick is how I use the OnPaint to paint the rectangles.
private void CreationsMethods(object sender, PaintEventArgs e)
{
dc = e.Graphics;
base.OnPaint(e);
creations.PaintAllAnimals(dc);
}
private void NextStepClick(object sender, EventArgs e)
{
this.Refresh();
picBox.Paint += new System.Windows.Forms.PaintEventHandler(CreationsMethods);
}
I have a WinForms application that interacts with a connection. If the connection is fine I want to show a green ("everything is fine") filled circle, if not I want to show a red filled circle.
I found no circle element in the toolbox so I think I have to draw it on my own.
I created a picture box called picBoxClientState and started with this code
public partial class FrmMain : Form
{
public void CheckSignedInState()
{
// some other code
DrawClientStateIcon(client.IsSignedIn);
}
private void DrawClientStateIcon(bool isSignedIn)
{
Point rectangleLocation = picBoxClientState.Location;
Size rectangleSize = picBoxClientState.Size;
Rectangle rectangle = new Rectangle(rectangleLocation, rectangleSize);
Color iconColor = isSignedIn ? Color.Green : Color.Red;
SolidBrush iconBrush = new SolidBrush(iconColor);
Graphics graphics = picBoxClientState.CreateGraphics();
graphics.FillEllipse(iconBrush, rectangle);
}
}
How can I draw on this picturebox whenever I call CheckSignedInState() ?
Maybe there is a better way instead of drawing? (I don't want to toggle two images because there might be more states to draw)
A simple example using a Label control to draw an ellipse.
You can use any control that has a Paint event to draw shapes.
It could also be a Panel, a PictureBox, a Button...
A bool variable (clientIsSignedIn) declared at Class scope is used to keep track of the current status, as reported by your client.IsSignedIn value.
When the status changes, update clientIsSignedIn and Invalidate() the Control that provides the visual aid.
bool clientIsSignedIn = false;
public void CheckSignedInState()
{
// some other code
clientIsSignedIn = client.IsSignedIn;
lblVisualStatus.Invalidate();
}
private void lblVisualStatus_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.FillEllipse((clientIsSignedIn) ? Brushes.Green : Brushes.Red, ((Control)sender).ClientRectangle);
}
I don't think picture box is necessary. You can try something like this:
private void button1_Click(object sender, EventArgs e)
{
System.Drawing.SolidBrush myBrush = new
System.Drawing.SolidBrush(System.Drawing.Color.Red);
System.Drawing.Graphics formGraphics;
formGraphics = this.CreateGraphics();
formGraphics.FillEllipse(myBrush, new Rectangle(200, 200, 30, 30));
myBrush.Dispose();
formGraphics.Dispose();
}
If you need to draw on picturebox be sure to call picturebox.Invalidate();
your code works, it did seem to draw a bit off center though but also the fact that you weren't disposing of the object could potentially cause issues too. Try using the code below as your DrawClientStateIcon method
Edit: full code example below. I added a button to toggle the state of the client and this works for me.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public class Client
{
public bool IsSignedIn { get; set; }
}
Client client = new Client()
{
IsSignedIn = false
};
public Form1()
{
InitializeComponent();
}
public void CheckSignedInState()
{
// some other code
DrawClientStateIcon(client.IsSignedIn);
}
private void DrawClientStateIcon(bool isSignedIn)
{
Point rectangleLocation = picBoxClientState.Location;
Size rectangleSize = picBoxClientState.Size;
Rectangle rectangle = new Rectangle(rectangleLocation, new Size(rectangleSize.Width / 2, rectangleSize.Height / 2));
Color iconColor = isSignedIn ? Color.Green : Color.Red;
using (SolidBrush iconBrush = new SolidBrush(iconColor))
{
using (Graphics graphics = picBoxClientState.CreateGraphics())
{
graphics.FillEllipse(iconBrush, rectangle);
}
}
}
private void button1_Click(object sender, EventArgs e)
{
client.IsSignedIn = !client.IsSignedIn;
CheckSignedInState();
}
}
}
You need to call it in Form Shown event.
private void FrmGraphics_Shown(object sender, EventArgs e)
{
DrawClientStateIcon(true);
}
private void DrawClientStateIcon(bool isSignedIn)
{
Point rectangleLocation = picBoxClientState.Location;
Size rectangleSize = picBoxClientState.Size;
Rectangle rectangle = new Rectangle(rectangleLocation, rectangleSize);
Color iconColor = isSignedIn ? Color.Green : Color.Red;
SolidBrush iconBrush = new SolidBrush(iconColor);
Graphics graphics = base.CreateGraphics();
graphics.FillEllipse(iconBrush, rectangle);
}
I need some help on removing extra padding around the edges of a custom button control in C#.
The width of this button is 68, and I'd like to keep it that way. If I change it to 70, then the text fits all on one line.
Button control code:
public partial class FlatButton : System.Windows.Forms.Button
{
public FlatButton() : base()
{
FlatAppearance.BorderSize = 0;
FlatStyle = System.Windows.Forms.FlatStyle.Flat;
BackColor = Color.FromArgb(58, 58, 58);
ForeColor = Color.White;
}
protected override bool ShowFocusCues
{
get
{
return false;
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Pen pen = new Pen(FlatAppearance.BorderColor, 1);
Rectangle rectangle = new Rectangle(0, 0, Size.Width, Size.Height);
e.Graphics.DrawRectangle(pen, rectangle);
}
public override void NotifyDefault(bool value)
{
}
}
Any ideas on how to remove the extra padding and allow the text to fit all in one line?
I'm in need of a way to make TextBox appear like a parallelogram but i can't figure out how to do so. I currently have this code:
private void IOBox_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Point cursor = PointToClient(Cursor.Position);
Point[] points = { cursor, new Point(cursor.X + 50, cursor.Y), new Point(cursor.X + 30, cursor.Y - 20),
new Point(cursor.X - 20, cursor.Y - 20) };
Pen pen = new Pen(SystemColors.MenuHighlight, 2);
g.DrawLines(pen, points);
}
But apparently it's not working. Either i misplaced/misused it or i'm not doing something right.
This is the method that i use to add it.
int IOCounter = 0;
private void inputOutput_Click(object sender, EventArgs e)
{
IOBox box = new IOBox();
box.Name = "IOBox" + IOCounter;
IOCounter++;
box.Location = PointToClient(Cursor.Position);
this.Controls.Add(box);
}
Any idea how i can fix it? IOBox is a UserControl made by me which contains a TextBox. Is that rightful to do?
If its possible, you should make your application using WPF. WPF is designed to do exactly what you are trying to do.
However, it can be done in WinForms, though not easily. You will need to make a new class that inherits the TextBox WinForm control. Here is an example that makes a TextBox look like a circle:
public class MyTextBox : TextBox
{
public MyTextBox() : base()
{
SetStyle(ControlStyles.UserPaint, true);
Multiline = true;
Width = 130;
Height = 119;
}
public override sealed bool Multiline
{
get { return base.Multiline; }
set { base.Multiline = value; }
}
protected override void OnPaintBackground(PaintEventArgs e)
{
var buttonPath = new System.Drawing.Drawing2D.GraphicsPath();
var newRectangle = ClientRectangle;
newRectangle.Inflate(-10, -10);
e.Graphics.DrawEllipse(System.Drawing.Pens.Black, newRectangle);
newRectangle.Inflate(1, 1);
buttonPath.AddEllipse(newRectangle);
Region = new System.Drawing.Region(buttonPath);
base.OnPaintBackground(e);
}
}
Keep in mind that you will still have to do other things, such as clipping the text, etc. But this should get you started.