I played with some custom Controls created by me and I wanted to draw some Graphics for them.
I achieved everything I wanted but I have a question because something seems strange to me.
I tried for example to make a new control like this:
public class Square : Control
{
public Square(Point location)
{
this.Size = new Size(100, 100);
this.Location = location;
Draw();
}
public void Draw()
{
Graphics g = this.CreateGraphics();
g.DrawRectangle(Pens.Black, 5, 5, 20, 20);
}
}
This doesn't draw anything, but, if I call the "Draw" method from another action like a button press on the form it works.
It also works if I override the OnPaint method of my control and call the "Draw" method here. (I know that I should make all the drawing in the Paint/OnPaint but I did this just to try other things)
What's the difference ? Why can't I just call my "Draw" method anywhere I want?
When you call Draw() method in constructor, the control has not yet been added to the parent, is just an object in memory, so the call has no effect.
If you make the call as you say in the OnPaint() method, then is drawed since this method is called whenever render the control is needed.
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 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.
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).
I have made a draw method in a separate class to that of the form.
public class Object : Form1
{
public void Draw()
{
SolidBrush brush = new SolidBrush(Color.Yellow);
Graphics mapGraphics = this.CreateGraphics();
mapGraphics.FillEllipse(brush, new Rectangle(0, 0, 12, 12));
pacBrush.Dispose();
mapGraphics.Dispose();
}
}
There are no exceptions thrown, nor errors. I have tried to call the Draw method from the Form_Paint method, but nothing happens at all. How can I fix this?
Thanks
To draw into a window, you need to use the Graphics object for that window. Your method creates a new Graphics object, so it draws "somewhere else".
Pass the e.Graphics object that you have in your Form_Paint handler into the method as a parameter, and draw using that instead.
I am using Cairo in a GTK# application for drawing. When another window covers part of the drawn content, the overlapped part of the drawn content is lost. Is there a way to make it permanent?
Here is my simplified method for drawing the content:
void UpdateConnectionLines ()
{
GdkWindow myWindow = GetGdkWindow();
myWindow.Clear ();
using (Context g = Gdk.CairoHelper.Create (myWindow))
{
g.Save ();
g.MoveTo (0, 20);
g.LineTo (100, 20);
g.Restore ();
g.Color = new Color (0, 0, 0);
g.LineWidth = 1;
g.Stroke();
}
}
If you are drawing directly on the form, then you need to do it in the Form's paint event, to ensure it is there every time the form get's painted (i.e. when another window covers it and then moves, when it is resized, ...)
Evaluating John Koerner's answer, I have found a solution, that works for every GTK# widget. I use the generic WidgetEvent ExposeEvent (thanks, ptomato) and redraw.
I append my event handler with
this.ExposeEvent += new global::Gtk.ExposeEventHandler (this.Handle_ExposeEvent);
and then the handler just calls my method:
protected virtual void Handle_ExposeEvent (object o, Gtk.ExposeEventArgs args)
{
UpdateConnectionLines();
}
EDIT:
Actually, I have not RTFM correctly, as it explicitely states:
The best place to create and use the
Context is the ExposeEvent for the
given widget. Usually you'll want to
use the Gtk.DrawingArea for this task.
An example implementation of the
Expose event method: