Hey people I have a problem I am writing a custom control. My control inherits from Windows.Forms.Control and I am trying to override the OnPaint method. The problem is kind of weird because it works only if I include one control in my form if I add another control then the second one does not get draw, however the OnPaint method gets called for all the controls. So what I want is that all my custom controls get draw not only one here is my code:
If you run the code you will see that only one red rectangle appears in the screen.
public partial class Form1 : Form
{
myControl one = new myControl(0, 0);
myControl two = new myControl(100, 0);
public Form1()
{
InitializeComponent();
Controls.Add(one);
Controls.Add(two);
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
public class myControl:Control
{
public myControl(int x, int y)
{
Location = new Point(x, y);
Size = new Size(100, 20);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Pen myPen = new Pen(Color.Red);
e.Graphics.DrawRectangle(myPen, new Rectangle(Location, new Size(Size.Width - 1, Size.Height - 1)));
}
}
I'm guessing you are looking for something like this:
e.Graphics.DrawRectangle(Pens.Red, new Rectangle(0, 0,
this.ClientSize.Width - 1,
this.ClientSize.Height - 1));
Your Graphic object is for the interior of your control, so using Location isn't really effective here. The coordinate system starts at 0,0 from the upper-left corner of the client area of the control.
Also, you can just use the built-in Pens for colors, otherwise, if you are creating your own "new" pen, be sure to dispose of them.
LarsTech beat me to it, but you should understand why:
All drawing inside of a control is made to a "canvas" (properly called a Device Context in Windows) who coordinates are self-relative. The upper-left corner is always 0, 0.
The Width and Height are found in ClientSize or ClientRectangle. This is because a window (a control is a window in Windows), has two areas: Client area and non-client area. For your borderless/titlebar-less control those areas are one and the same, but for future-proofing you always want to paint in the client area (unless the rare occasion occurs where you want to paint non-client bits that the OS normally paints for you).
Related
I have the problem that I want to draw on a pictureBox with an image loaded before the user gets to see it. The drawing in principle works, but if I do it in the constructor it doesn't show up. It does work if I call the same function with a button.
public Form1()
{
InitializeComponent();
draw();
}
public void draw()
{
pictureBox1.Refresh();
Graphics g = pictureBox1.CreateGraphics();
Rectangle rect = new Rectangle(new Point(20, 20), new Size(40, 40));
rect.Offset(8, 8);
g.DrawEllipse(new Pen(Brushes.Black, 2), rect);
g.Dispose();
}
private void button1_Click(object sender, EventArgs e)
{
draw();
}
I would have assumed that the circle would show up when the Form loads but it only does when I press the button. The code itself gets executed, as tested with a Message box.
The control paints itself in its Paint event, so as soon as it's shown on screen (ie, after your code), it will paint itself in dull gray as normal.
If you want to custom paint a control, any control, you either override its OnPaint function or subscribe to its exposed Paint event.
A hint should be the fact that you had to create your own Graphics object, as opposed to using the object constructed during normal painting operations, that also includes proper clipping handling.
I want to create Rounded button using class instead of XAML style
This code work in WinForms app, how i can convert it to WPF code?
public class RoundButton : Button
{
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
GraphicsPath grPath = new GraphicsPath();
grPath.AddEllipse(0, 0, ClientSize.Width, ClientSize.Height);
this.Region = new System.Drawing.Region(grPath);
base.OnPaint(e);
}
}
Assuming you have a really good reason for doing this (like if you really want to custom draw in more complex scenarios like drawing diagrams or similar), you could do something like:
public class RoundButton : Button
{
public RoundButton()
{
DefaultStyleKey = typeof(RoundButton);
}
protected override void OnRender(DrawingContext dc)
{
double radius = 10;
double borderThickness = 1; // Could get this value from any of the this.BorderThickness values
dc.DrawRoundedRectangle(Background, new Pen(BorderBrush, borderThickness), new Rect(0, 0, Width, Height), radius, radius);
}
}
But I really, really recommend going down the XAML route instead in this case. Custom drawing does not make sense here at all.
One obvious issue with the above code, for instance, is that for it to work, you have to disable the default button style or a button will be drawn on top of your drawing.
In this case a style for RoundButton doesn't exist and the control does not define a placeholder for where text or other content should go. If you want this, you are better off defining this style with a control template and could just as well put in the visuals there.
I have created a customized textbox which has border in red color. I then launch my application but this OnPaint never gets called.
My code is this:
public partial class UserControl1 : TextBox
{
public string disable, disableFlag;
public string Disable
{
get
{
return disable;
}
set
{
disable = value;
disableFlag = disable;
//OnPaint(PaintEventArgs.Empty);
}
}
public UserControl1()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
this.Text = "testing 1";
if (disable == "true")
{
Pen redPen = new Pen(Color.Red);
Graphics graphics = this.CreateGraphics();
graphics.DrawRectangle(redPen, this.Location.X,
this.Location.Y, this.Width, this.Height);
// base.DrawFrame(e.Graphics);
}
}
}
Please let me know what is the problem (Here is the snapshot of the winform http://prntscr.com/ceq7x5 )?
You shouldn't create a new Graphics object. Use e.Graphics.DrawRectangle to be able to draw on the control using the already existing Graphics object like this:
Pen redPen = new Pen(Color.Red);
e.Graphics.DrawRectangle(redPen, this.Location.X,
this.Location.Y, this.Width, this.Height);
Also, to repeat my comment here about the Disabled flag. There's no point adding a custom Disable flag. Use the Enabled property that is already provided by the Windows Forms TextBox control.
Edit: Please notice that the above code doesn't work in TextBox's case, because it handles drawing differently. TextBox is basically just a wrapper around the native Win32 TextBox so you need to listen to quite a few messages that tell it to repaint itself. You also need to get the handle to the device context and transform it to a managed Graphics object to be able to draw.
Take a look at this article for code and explanations on how to draw on top of TextBox. Especially part 2. Drawing Onto the TextBox on the bottom of the page.
I have created a button using the code below. Adding the start.Text="Start"; statement does nothing. How do I add a label to my button?
public MainForm()
{
InitializeComponent();
myButtonObject start = new myButtonObject();
EventHandler myHandler = new EventHandler(start_Click);
start.Click += myHandler;
start.Location = new System.Drawing.Point(200, 500);
start.Size = new System.Drawing.Size(101, 101);
start.Text="Start";
// start.TextAlign = new System.Drawing.ContentAlignment.MiddleCenter;
this.Controls.Add(start);
}
public class myButtonObject : UserControl
{
// Draw the new button.
protected override void OnPaint(PaintEventArgs e)
{
Graphics graphics = e.Graphics;
Pen myPen = new Pen(Color.Black);
// Draw the button in the form of a circle
graphics.FillEllipse(Brushes.Goldenrod, 0, 0, 100, 100);
graphics.DrawEllipse(myPen, 0, 0, 100, 100);
myPen.Dispose();
}
}
You have implemented your own button as a user control. Since you are implementing OnPaint to provide your own draw functionality, you need to implement all the functionality like drawing the text too.
If you want to go down this route then you also need to add the logic to draw the text on the control in your OnPaint method. This can be done using the graphics.DrawString method.
See http://msdn.microsoft.com/en-us/library/system.drawing.graphics.drawstring.aspx
You also need to call graphics.dispose.
If you aren't familiar with this, then it might be simpler to use a UserControl and add a label to it, or something similar, and then to draw your circle shape on the top of that.
You should draw the button's text yourself in the OnPaint method:
TextRenderer.DrawText(graphics, Text, Font, new Point(5, 5), SystemColors.ControlText);
Where new Point(5, 5) - is a top left position of the text.
You paint the button ok but you don't draw the text.
A usercontrol doesn't do this by itself.
Just add something like this to the paint commands:
graphics.DrawString(Text, yourfont, yourBrush, x, y);
you must and may have to decide freely on x, y font and brush.
Imagine I use the .NET graphic classes to draw a rectangle.
How could I then assign an event so that if the user clicks a certain point, or a certain point range, something happens (a click event handler)?
I was reading CLR via C# and the event section, and I thought of this scenario from what I had read.
A code example of this would really improve my understanding of events in C#/.NET.
Thanks
You can assign Click event handler to control whose surface will be used to draw rectangle.
Here is a small example:
When you click on form inside of rectangle it will be drawn with red border when you click outside it will be drawn with black border.
public partial class Form1 : Form
{
private Rectangle rect;
private Pen pen = Pens.Black;
public Form1()
{
InitializeComponent();
rect = new Rectangle(10, 10, Width - 30, Height - 60);
Click += Form1_Click;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawRectangle(pen, rect);
}
void Form1_Click(object sender, EventArgs e)
{
Point cursorPos = this.PointToClient(Cursor.Position);
if (rect.Contains(cursorPos))
{
pen = Pens.Red;
}
else
{
pen = Pens.Black;
}
Invalidate();
}
}
PointToClient method translates cursor coordinates to control-relative coordinates. I.e. if you cursor is at (screenX, screenY) position on the screen it can be at (formX, formY) position relatively to form's top-left corner. We need to call it to bring cursor position into coordinate system used by our rectangle.
Invalidate method makes control to redraw itself. In our case it triggers OnPaint event handler to redraw rectangle with a new border color.