C# Graphics not drawing rectangles where required - c#

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);
}

Related

How to pass parameters in C# GDI+ Windows Desktop

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.

C# Forms - How to draw shape over existing panels

Trying to draw a shape over existing panels for a good while, but by now out of ideas. Could somebody help me out, please? It ends up always behind the panels (and pictureBox /the grey one/). I tried 3 different ways, whithout success. this is my code:
namespace DrawingOnFront
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void panel11_MouseClick(object sender, MouseEventArgs e)
{
DrawIt(90, 70);
}
private void DrawIt(int x, int y)
{
Rectangle Circle = new Rectangle(x,y,40,40);
SolidBrush Red = new SolidBrush(Color.Red);
Graphics g = this.CreateGraphics();
g.FillEllipse(Red, Circle);
/*
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics g = Graphics.FromImage(bmp);
int width = pictureBox1.Width /4;
int height = pictureBox1.Height /2;
int diameter = Math.Min(width, height);
g.FillEllipse(Red, x, y, width, height);
pictureBox1.Image = bmp;
*/
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (Graphics g = e.Graphics)
{
Rectangle Circle = ClientRectangle;
Circle.Location = new Point(100, 60);
Circle.Size = new Size(40, 40);
using (SolidBrush Green = new SolidBrush(Color.Green))
{
g.FillEllipse(Green, Circle);
}
}
}
}
}
Sorry for this basic lama question, probably for most of you it is very easy, I am still learning it. Thanks a lot in advance.
My comments above apply. Here is an example of how to draw onto each control and the form separately:
We best have a common drawing routine that we can call from the Paint event of each participating element, in our case a Panel, a PictureBox and the Form.
The trick is for all nested elements to draw the circle shifted by their own location. To do so we pass these things into the drawing routine:
a valid Graphics object. We get it from the Paint events.
and a reference to the control; we use it to offset the drawing on each control (except the form) with Graphics.TranslateTransform..:
Result:
As you can see it looks as if we painted one circle over all elements but actually we drew three circles, each onto one element..:
private void canvasForm_Paint(object sender, PaintEventArgs e)
{
draw(sender as Control, e.Graphics);
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
draw(sender as Control, e.Graphics);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
draw(sender as Control, e.Graphics);
}
private void draw(Control ctl, Graphics g)
{
Rectangle r = new Rectangle(200, 100, 75, 75);
if (ctl != canvasForm) g.TranslateTransform(-ctl.Left, -ctl.Top);
g.FillEllipse(Brushes.Green, r);
g.ResetTransform();
}
Note that the same result could be created with three calls, one FillRectangle, one DrawImage and one FillEllipse :-)

ZOOM-IN & ZOOM-OUT 2D graphics C#

i have to ZOOM-IN & ZOOM-OUT specific portion of 2D-graphics like (line, Rectangle, circle) which i have drawn on winform.
I am not used any picture box, panel.
I crated simple program to draw circle & on button click try to zoom
but it showing error "parameter is not valid"
in method Drawing() # Line- DeviceContexct.Transform = mainViewTransform;
public Graphics DeviceContexct;
public Matrix mainViewTransform = new Matrix();
private void ScalingCircle_Paint( object sender, PaintEventArgs e )
{
Pen myPen = new Pen(Color.Blue, 1);
e.Graphics.DrawRectangle(myPen, 50, 50, 100, 100);
mainViewTransform.Scale(3, 2);
DeviceContexct = e.Graphics;
}
private void Drawing(Graphics gr)
{
Pen myPen2 = new Pen(Color.Red, 1);
DeviceContexct.Transform = mainViewTransform;
DeviceContexct.DrawRectangle(myPen2, 50, 50, 100, 100);
}
private void button1_Click( object sender, EventArgs e )
{
Drawing(DeviceContexct);
}
I prefer to draw into Bitmaps with System.Drawing.Graphics object.
Then you can use your graphics object with "go.DrawImage(...)" to draw the bitmap directly into your winforms and actually give it a scale.
https://msdn.microsoft.com/en-us//library/ms142040(v=vs.110).aspx
I got the solution, thanks for your help.
I only need to call refresh/invalidate etc on button click.
public partial class ScalingCircle : Form
{
public Graphics DeviceContexct;
// current transformation matrix of main view (offset & scaling)
public Matrix mainViewTransform = new Matrix();
public int scale = 1;
public ScalingCircle()
{
InitializeComponent();
DeviceContexct = Graphics.FromHwnd(this.Handle);
DeviceContexct = this.CreateGraphics();
}
public void ScalingCircle_Paint(object sender, PaintEventArgs e)
{
DeviceContexct = e.Graphics;
DeviceContexct.PageUnit = GraphicsUnit.Pixel;
DeviceContexct.Transform = mainViewTransform;
ScalingCircle1(scale);
}
private void ScalingCircle1(int x )
{
Pen myPen2 = new Pen(Color.Black, 1);
DeviceContexct.Transform = mainViewTransform;
Rectangle myRectangle = new Rectangle(50, 50, 100 * x, 100 * x);
DeviceContexct.FillRectangle(new SolidBrush(Color.BurlyWood), myRectangle);
}
private void ScalingCircle_Load( object sender, EventArgs e )
{
this.ResizeRedraw = true;
}
private void button1_Click( object sender, EventArgs e )
{
scale += 5;
this.Refresh();
}
private void button2_Click( object sender, EventArgs e )
{
if (scale > 1)
{
scale -= 5;
this.Refresh();
}
}
}
You can use transformations for that. The graphics object you use for painting things has a Transformation property of type System.Drawing.Drawing2D.Matrix.
Graphics also has the ScaleTransform method.
I haven't used it myself, but that is how microsofts Chart does it.
https://msdn.microsoft.com/de-de/library/system.drawing.drawing2d.matrix(v=vs.110).aspx
https://msdn.microsoft.com/de-de/library/system.drawing.graphics.scaletransform(v=vs.110).aspx

Refresh does not refresh

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_(); }

Adding element to another element win forms

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.

Categories