I want to display graphic file in PictureBox I have:
private void btnLoad_Click(object sender, EventArgs e)
{
if (dgOpenFile.ShowDialog() == DialogResult.OK)
{
Bitmap img = new Bitmap(dgOpenFile.FileName);
picture.Width = img.Height;
picture.Height = img.Height;
g.DrawImage(img, 0f, 0f);
}
}
That's g
private void Form1_Load(object sender, EventArgs e)
{
g = picture.CreateGraphics();
}
But when I move my Form outside the window my picture disappears. How can I prevent that?
You should do any custom drawing in the OnPaint event of the control to make it persistent. This causes your drawing to be redrawn every time the control is painted.
However, in this case it would be easier to use the picture box as it was designed:
picture.Image = img;
Windows uses a Paint-on-Request principle.
So when it sends a WM_PAINT message to your Control, it's OnPaint() is called. You should be ready to draw the image (again) in an overridden OnPaint() or in a Paint event handler.
But a Picturebox will do all this for you.
Related
I'm having a problem with refreshing graphics on panels and forms.
When I draw the image it works fine but when I want to replace it with another image using Panel.Refresh it makes the event handler auto activate itself without end. If I use Panel.Update it will just draw the second image onto the first. A lot of people recommended that I use the Invalidate method but that has the same infinite loop problem.
Bitmap bitmap = new Bitmap(Resources.Image1);
private void panel1_Paint(object sender, PaintEventArgs e)
{
if (parameter == 0) { bitmap = new Bitmap(Resources.Image1); }
if (parameter >= 2) { bitmap = new Bitmap(Resources.Image2); }
e.Graphics.DrawImage(bitmap, 60, 10);
panel1.Refresh();
}
panel1.Refresh();
Causes the paint event to trigger. I put the refresh code where the parameter value is changed.
I am drawing something, let us assume an image over the panel in Windows form.
I can able to draw i I follow the below steps:
1) added panel to the Form
2) used the below code:
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(im, leftTop);
}
Is this the only way to draw over the panel.
I have a plan to draw withoutusing this event
I tried by the below code, results negative.
this.panel1.CreateGraphics().DrawImage(im, leftTop);
in both the case im is an Image.
.. can I able to draw. ?
Yes, you can draw it, however if the Paint event is raised, the default stuff will be re-drawn and all the thing you have drawn will be covered/erased/cleared.
So to draw your image, the best approach is to add drawing code in Paint event handler as the first code you posted does.
Otherwise, you have to draw your image periodically which is not efficient, because we just need to re-draw it when we need. The system provides the Paint event to notify when we need to repaint the control (beside the default drawing).
Here is the way in which you use a timer to draw your image periodically, but this is not recommended, just for demonstrative purpose:
Timer t = new Timer();
t.Interval = 10;
Graphics g = null;
panel1.HandleCreated += (s,e) => {
g = panel1.CreateGraphics();
};
t.Tick += (s,e) => {
if(g == null) return;
g.DrawImage(im,leftPoint);
};
//
t.Start();
In fact, the Paint event is raised when the WM_PAINT is sent to your Panel, you can catch this message to draw the image instead of draw it when Paint is raised.
public class MyPanel : Panel {
Graphics g;
public MyPanel(){
HandleCreated += (s,e) => {
g = panel1.CreateGraphics();
};
}
protected override void WndProc(ref Message m){
base.WndProc(ref m);
if(m.Msg == 0xf&&g!=null)//WM_PAINT = 0xf
g.DrawImage(im,leftTop);
}
//.... suppose somehow you pass im and leftTop in...
}
Question:
How do you properly draw on a winform from a method other than the OnPaint() method?
Additional Information:
The code I have now draws some background lines for a TicTacToe game in the OnPaint() method. Then I use the Mouse_Click event and am running this code which apparently is not proper:
private void TicTacToe_MouseClick(object sender, MouseEventArgs e)
Graphics g = this.CreateGraphics();
g.DrawEllipse(this.penRed, this.Rectangle);
For reasons I do not understand, it does draw the circle, but when minimizing or moving the form off screen it erases the circles but not the lines from the OnPaint() method.
You are doing a lot of "view" but no "model".
When you want to create a shape, when the mouse button goes down/up, create some DATA representing the shape.
Your data structures represent the persistent information (it is the data that allows you to save and load this information between sessions).
All your paint function needs to do is look at the DATA structures and paint it. This will therefore persist between sizing/hiding/showing.
The problem is that Windows windows (that includes WinForms) have no graphical memory of their own unless their creator provides such memory and it is only a matter of time before that particular window wilk get overwritten or hidden and eventually need to be repainted. You're painting to the screen ( you might say ) and others can do the same. The only convention you can rely on is that the OnPaint will get called when needed. Basically it's alright to use your philosophy and draw whenever you need to (not on some misterious and unpredictable schedule). For that check out my solution.
You should use a "backbuffer bitmap" like:
private Bitmap bb;
protected override void OnResize(EventArgs e) {
this.bb = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
this.InitBackBuffer();
}
private void InitBackBuffer() {
using (var g = Graphics.FromImage(this.bb)) {
// do any of the "non dissapearing line" drawing here
}
}
private void TicTacToe_MouseClick(object sender, MouseEventArgs e)
using (Graphics g = Graphics.FromImage(this.bb))
g.DrawEllipse(this.penRed, this.Rectangle);
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
e.Graphics.DrawImageUnscaled(this.bb);
}
Try that. That should do it :)
What you are doing is drawing on the form "asynchronously" (from the OnPaint method). You see, the OnPaint method is what Windows Forms relies on to draw your entire form. When something happens to your From, it is invalidated and OnPaint is called again. If something isn't drawn in that method, then it will not be there after that happens.
If you want a button to trigger something to appear permanently then what you need to do is Add that object to a collection somewhere, or set a variable related to it. Then call Refresh() which calls Invalidate() and Update() Then, during OnPaint, draw that object (ellipis).
If you want it to still be there after something happens to your form, such as minimize, you have to draw it during OnPaint.
Here's my suggestion:
public partial class Form1 : Form
{
Rectangle r = Rectangle.Empty;
Pen redPen = new Pen(Color.Red);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
r = new Rectangle(50, 50, 100, 100);
Refresh();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (r != Rectangle.Empty)
{
e.Graphics.DrawRectangle(redPen, r);
}
}
}
I have a form with a MenuStrip and a PictureBox. I subscribe to the PictureBox's Paint event with the following code:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
// other code but the above line demonstrates the problem
}
This for some reason causes the MenuStrip to white out--I can't see the text until I hover over it--even though the PictureBox does not overlap the MenuStrip at all. I can put a menuStrip1.Update() at the end of the function above, but that causes other problems.
Instead of directly assigning to the PictureBox while in the event, use the provided PaintEventArgs to do any drawing.
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.Gray);
}
I'm trying to draw a text on a panel(The panel has a background picture).
It works brilliant,but when I minimize and then maximize the application the text is gone.
My code:
using (Graphics gfx = Panel1.CreateGraphics())
{
gfx.DrawString("a", new Font("Tahoma", 5), Brushes.White, new PointF(1, 1));
}
How do I keep it static so it doesn't get lost?
Inherit from Panel, add a property that represents the text you need to write, and override the OnPaintMethod():
public class MyPanel : Panel
{
public string TextToRender
{
get;
set;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawString(this.TextToRender, new Font("Tahoma", 5), Brushes.White, new PointF(1, 1));
}
}
This way, each Panel will know what it needs to render, and will know how to paint itself.
Just add a handler for the Paint event:
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawString("a", new Font("Tahoma", 5), Brushes.White, new PointF(1, 1));
}
If you don't use a Paint event, you are just drawing on the screen where the control happens to be. The control is not aware of this, so it has no idea that you intended for the text to stay there...
If you put the value that you want drawn on the panel in it's Tag property, you can use the same paint event handler for all the panels.
Also, you need to dispose of the Font object properly, or you will be having a lot of them waiting to be finalized before they return their resources to the system.
private void panel1_Paint(object sender, PaintEventArgs e) {
Control c = sender as Control;
using (Font f = new Font("Tahoma", 5)) {
e.Graphics.DrawString(c.Tag.ToString(), f, Brushes.White, new PointF(1, 1));
}
}
When you draw something, it only remains until the next time the form is refreshed.
When the form is refreshed, the Paint event is called. So if you want to ensure your text doesn't disappear, you need to include the code that draws it in the Paint event.
You can trigger a repaint using Control.Invalidate, but you otherwise cannot predict when they will happen.