im having some problems... code is below:
delegate void SetCanvasDelegate(PictureBox canvas);
public void SetCanvas(PictureBox canvas)
{
if (this.canvas.InvokeRequired)
this.canvas.Invoke(new SetCanvasDelegate(SetCanvas), new object[] { canvas });
else
this.canvas = canvas;
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
PictureBox canvas = new PictureBox();
Graphics g = Graphics.FromHwnd(canvas.Handle);
RadarElement player = new RadarElement(new Point(150, 150), RadarElementType.Player);
List<Enemy> enemies = new List<Enemy>();
ores.Add(new Enemy(new Point(100, 100)));
g.DrawLine(new Pen(Color.Black), new Point(0, 0), new Point(100, 100));
if (trackEnemies.Checked)
foreach (Enemy e in enemies)
g.DrawImage(Image.FromFile("enemy.png"), e.Position);
SetCanvas(canvas);
Thread.Sleep(500);
}
}
this.canvas is the PictureBox in my Form1.
All of this is within my Form1 class... but the pictureBox in my form is not updated to show enemy.png as above in the code. What is wrong and how do i correct it?
Looks like you're trying to replace the PictureBox of your form with one that's being created within your bw_DoWork method. This won't work the way you expect it to. You need to do your painting on an image object and then stick that painted image into your form's picturebox. If it still doesn't show, use Invalidate as Daren Thomas suggested.
You probably need to do something along the lines of
Bitmap canvas = new Bitmap(width, height);
using(Graphics g = Graphics.FromImage(canvas))
{
// paint here
}
SetCanvas(canvas);
and then modify your SetCanvas method accordingly to accept an Image instead of a PictureBox.
Did you Invalidate the pictureBox?
Related
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 made an user control and I draw a rectangle directly in the window, like this (this is a simplified version):
private int rec_len = 200;
private void Draw_()
{
Pen pn = new Pen( Color.Black, WIDTH_LINE );
Graphics graph = this.CreateGraphics();
graph.Clear( Color.Transparent );
this.Refresh();
graph.DrawRectangle( pn, 20, 10, rec_len, 40 );
this.Refresh();
graph.Dispose();
}
public void button_Build_Click( object sender, EventArgs e )
{ rec_len += 10; Draw_(); }
The strange thing is that the second refresh actually poses a problem: if I comment it out, the rectangle is visible, if I let it in the code, the rectangle is not visible. In the real code I have to draw more than a rectangle and I want the refresh at the end, otherwise the background is visible between the moment I erase old drawing and the moment the new one is ready.
The surface of a control is not stored: When you paint on a control, the drawing is not saved and need to be redrawn each time the control is repainted (After a refresh for example). To create a persistante graphic, you can create a bitmap, draw on the bitmap and assign this bitmap to the BackgroundImage property.
Bitmap bmp = new Bitmap(WIDTH, HEIGHT);
void Initialize()
{
this.BackgroundImage = bmp;
}
private int rec_len = 200;
private void Draw_()
{
Pen pn = new Pen(Color.Black, WIDTH_LINE);
using (Graphics graph = Graphics.FromImage(bmp))
{
graph.Clear(Color.Transparent);
this.Refresh();
graph.DrawRectangle(pn, 20, 10, rec_len, 40);
this.Refresh();
}
}
public void button_Build_Click(object sender, EventArgs e) { rec_len += 10; Draw_(); }
i tried to draw some boxes right after form is Initialized
however they didn't appeared.
i put the code under the InitializeComponent();
like this
public Form2()
{ InitializeComponent();
System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.LimeGreen);
System.Drawing.Graphics formGraphics = this.CreateGraphics();
formGraphics.FillRectangle(myBrush, new Rectangle(0, 0, 200, 300)); }
but when i drew them after the form is initialized they worked!
So i thought i should wait a moment and draw the boxes.
Then i put the thread to make the draw function wait for 10ms
In short i modified the code like this
public Form2()
{
InitializeComponent();
Thread t1 = new Thread(new ThreadStart(Run));
t1.Start();
}
void Run()
{
Thread.Sleep(10);
System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.LimeGreen);
System.Drawing.Graphics formGraphics = this.CreateGraphics();
formGraphics.FillRectangle(myBrush, new Rectangle(0, 0, 200, 300));
}
and i succeed
So my question is why i have to wait for a moment to draw something right after the form is initialized?
and is there any way to solve this problem not using thread?
I find your question interesting and did some experiments myself. I managed to get it to work in Form1_Paint callback :)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.LimeGreen);
System.Drawing.Graphics formGraphics = e.Graphics; //this.CreateGraphics();
formGraphics.FillRectangle(myBrush, new Rectangle(0, 0, 200, 300));
}
}
Edit: Edited based on Idle_Mind's comment
using paint event works
plus don't use CreateGraphics instead use e.Graphics
I am adding one panel to another panel it works but circle which is in inspanel not shown. how can i solved this.
I am using below code. It works but not show circle
public static int xTemp = 0;
public static int yTemp = 0;
private void button1_Click(object sender, EventArgs e)
{
Panel insPanel = new Panel();
Random xRandom = new Random();
xTemp= xRandom.Next(20,100);
Random yRandom = new Random();
yTemp = yRandom.Next(20, 100);
insPanel.Location = new Point(xTemp, yTemp);
insPanel.Width=40;
insPanel.Height = 40;
insPanel.Visible = true;
insPanel.BorderStyle = BorderStyle.FixedSingle;
insPanel.Paint += new PaintEventHandler(insPanel_Paint);
panel1.Controls.Add(insPanel);
}
void insPanel_Paint(object sender, PaintEventArgs e)
{
System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Red);
System.Drawing.Graphics formGraphics =this.CreateGraphics();
formGraphics.FillEllipse(myBrush, new Rectangle(xTemp,yTemp, 10, 10));
myBrush.Dispose();
formGraphics.Dispose();
}
Main issue: you're trying to draw your circle at wrong coordinates.
xTemp and yTemp are coordinates of insPanel relative to panel1. But when you drawing your circle, you should use coordinates relative to panel you're drawing at - insPanel.
Another issue: there is no need to create and dispose graphics each time you're drawing something on your panel. You can use e.Graphics from Paint eventhandler arguments.
Based on above, your code could look like:
void insPanel_Paint(object sender, PaintEventArgs e)
{
using (var myBrush = new SolidBrush(Color.Red))
{
e.Graphics.FillEllipse(myBrush, new Rectangle(0, 0, 10, 10));
}
}
Also note - since paint event can occur very frequently, it could be a good idea not to create and dispose brush every time, but use brush cached in your class private field.
Use e.Graphics instead of this.CreateGraphics:
System.Drawing.Graphics formGraphics = e.Graphics;
One more issue is you're getting coordinates in range of 20 - 100 (xRandom.Next(20,100)) and your panel dimensions are just 40, 40.
Given the following code example from MSDN:
private void GetPixel_Example(PaintEventArgs e)
{
// Create a Bitmap object from an image file.
Bitmap myBitmap = new Bitmap(#"C:\Users\tanyalebershtein\Desktop\Sample Pictures\Tulips.jpg");
// Get the color of a pixel within myBitmap.
Color pixelColor = myBitmap.GetPixel(50, 50);
// Fill a rectangle with pixelColor.
SolidBrush pixelBrush = new SolidBrush(pixelColor);
e.Graphics.FillRectangle(pixelBrush, 0, 0, 100, 100);
}
How can one call the Paint function?
from the paint event something like this
private PictureBox pictureBox1 = new PictureBox();
pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint);
private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
GetPixel_Example(e) ;
}
You can call this method from a PaintEvent of a form e.g.
public class Form1 : Form
{
public Form1()
{
this.Paint += new PaintEventHandler(Form1_Paint);
}
//....
private void Form1_Paint(object sender, PaintEventArgs e)
{
GetPixel_Example(e);
}
private void GetPixel_Example(PaintEventArgs e)
{
// Create a Bitmap object from an image file.
Bitmap myBitmap = new Bitmap(#"C:\Users\tanyalebershtein\Desktop\Sample Pictures\Tulips.jpg");
// Get the color of a pixel within myBitmap.
Color pixelColor = myBitmap.GetPixel(50, 50);
// Fill a rectangle with pixelColor.
SolidBrush pixelBrush = new SolidBrush(pixelColor);
e.Graphics.FillRectangle(pixelBrush, 0, 0, 100, 100);
}
}
Loads the image
Get the color of the pixel at x=50,y=50
Draw a filled rectangle with that color at 0,0 with a size of 100,100
on the Graphics-Object of the form
You should't call the Paint method yourself. The Paint method will be called by the .NET framework whenever your component needs to be painted. This typically happens when the window is moved, minimized, etc.
If you want to tell the .NET framework to repaint your component, call Refresh() on either the component or one of its parents.