Draw three Rectangles in C# - c#

I got one class "Making" that draw one Rectangle into Form1 class.
The problem is that i have to create two more rectangle in different position in the form1 but i dont know how to draw two more rectangles in same class
Making.cs:
class Making
{
public Rectangle[] makingRec;
private SolidBrush brush;
private int x, y, width, height;
public Making()
{
makingRec = new Rectangle[7];
brush = new SolidBrush(Color.Red);
x = 50;
y = 50;
width = 10;
height = 10;
for (int i = 0; i < makingRec.Length; i++)
{
makingRec[i] = new Rectangle(x, y, width, height);
x -= 10;
}
}
public void drawMaking(Graphics paper)
{
foreach (Rectangle making in makingRec)
{
paper.FillRectangle(brush, making);
}
}}
}
Form1.cs:
public partial class Form1 : Form
{
Graphics paper;
Making making = new Making();
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
paper = e.Graphics;
making.drawMaking(paper);

The problem isn't that the rectangles aren't being drawn, it's that all the rectangles are in a line, so you'll end up with three overlapping rectangles of the same height and color. They'll appear to look like one longer rectangle from x = 30 to 60.

Related

C# draw in panel and shift left the drawn objects

I'm drawing rectangles in a panel starting from the left side.
When I reach the right side of the panel I'd like to shift left the rectangles previously drawn to have the space to draw another one, and so on.
Which is the simplest way to do it?
I'm drawing using System.Drawings.Graphics.
I'm using Winforms. The code is:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace FFViewer
{
public partial class Form1 : Form
{
[DllImport("shlwapi.dll")]
public static extern int ColorHLSToRGB(int H, int L, int S);
int x=0;
int y=300;
int h = 0;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
panel_Paint();
x = x + 40;
h = h + 40;
if (h >= 240)
h = 0;
}
private void panel_Paint()
{
int val;
Color color;
val = ColorHLSToRGB(h, 128, 240);
Graphics g = panel1.CreateGraphics();
color = ColorTranslator.FromWin32(val);
SolidBrush sb = new SolidBrush( color );
g.FillRectangle(sb, x, y, 40, 100);
}
}
}
So, when I draw the latest rectangle on the right side, I'd like to shift left all the rectangles to leave the space to draw another one on the right side.
P.S. I don't have enough reputation to post images :(
Here's the "old school" way of doing it. This is basically what was done when a continuous graph of a real-time value needed to be displayed AND you didn't want to store the any of the values anywhere. This has severe limitations as it copies from the screen and the drawing will be erased the when window repaints itself. This first example is simply here to demonstrate the process, and is an extension of the way you created the initial blocks:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("shlwapi.dll")]
public static extern int ColorHLSToRGB(int H, int L, int S);
int x = 0;
int width = 40;
int y = 300;
int height = 100;
int h = 0;
private void button1_Click(object sender, EventArgs e)
{
if (x + width > panel1.ClientSize.Width) // if drawing the next block would exceed the panel width...
{
// capture what's currently on the screen
Bitmap bmp = new Bitmap(x, height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.CopyFromScreen(panel1.PointToScreen(new Point(0, y)), new Point(0, 0), bmp.Size);
}
// draw it shifted to the left
using (Graphics g = panel1.CreateGraphics())
{
g.DrawImage(bmp, new Point(-width, y));
}
// move x back so the new rectangle will draw where the last one was previously
x = x - width;
}
// draw the new block and increment values
panel_Paint();
x = x + width;
h = h + width;
if (h >= 240)
{
h = 0;
}
}
private void panel_Paint()
{
int val;
Color color;
val = ColorHLSToRGB(h, 128, 240);
color = ColorTranslator.FromWin32(val);
using (Graphics g = panel1.CreateGraphics())
{
using (SolidBrush sb = new SolidBrush(color))
{
g.FillRectangle(sb, x, y, width, height);
}
}
}
}
This could be fixed by creating a Bitmap of the correct size and drawing to that instead. Then you shift everything and draw the new block on the right side. Finally, you'd draw that Bitmap in the Paint() event. So this is doing the same thing as above except we aren't copying from the screen, and the panel will properly redraw itself when requested:
public partial class Form1 : Form
{
[DllImport("shlwapi.dll")]
public static extern int ColorHLSToRGB(int H, int L, int S);
int x = 0;
int width = 40;
int y = 300;
int height = 100;
int h = 0;
Bitmap bmp;
public Form1()
{
InitializeComponent();
this.Load += Form1_Load;
panel1.Paint += Panel1_Paint;
}
private void Form1_Load(object sender, EventArgs e)
{
int numBlocks = (int)(panel1.Width / width);
bmp = new Bitmap(numBlocks * width, height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(panel1.BackColor);
}
}
private void Panel1_Paint(object sender, PaintEventArgs e)
{
if (bmp != null)
{
e.Graphics.DrawImage(bmp, new Point(0, y));
}
}
private void button1_Click(object sender, EventArgs e)
{
using (Graphics g = Graphics.FromImage(bmp))
{
if (x + width > bmp.Width) // if drawing the next block would exceed the bmp width...
{
g.DrawImage(bmp, new Point(-width, 0)); // draw ourself shifted to the left
x = x - width;
}
// draw the new block
int val;
Color color;
val = ColorHLSToRGB(h, 128, 240);
color = ColorTranslator.FromWin32(val);
using (SolidBrush sb = new SolidBrush(color))
{
g.FillRectangle(sb, x, 0, width, height);
}
}
x = x + width;
h = h + width;
if (h >= 240)
{
h = 0;
}
panel1.Invalidate(); // force panel1 to redraw itself
}
}
You should not use panel1.CreateGraphics(), but instead handle the Paint event of the panel, otherwise the rectangles might disappear, for instance after a popup appears in front of your form:
panel1.Paint += new PaintEventHandler(panel1_paint);
You'll need to paint all (visible) rectangles in the paint handler; you could keep a List<Rectangle> in your form to store the rectangles you have added:
private List<Rectangle> rectangles = new List<Rectangle>();
...
private void button1_Click(object sender, EventArgs e)
{
rectangles.Add(new Rectangle(x, y, width, height));
panel1.Invalidate(); // cause the paint event to be called
// todo increment x/y
}
Then, in the panel1_Paint handler you can simply draw the rectangles, after having called Graphics.TranslateTransform() to shift the whole drawing area:
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.TranslateTransform(-x, 0);
foreach (Rectangle rectangle in rectangles)
{
// paint em
}
e.Graphics.ResetTransform();
}

Control not drawn on panel

I'm trying to add a control to my Panel. At mouseDown on the panel the point is saved and at mouseUp the point is saved. But at panel mouseUp nothing is drawn. How to solve it?
Ellipse class:
class Ellipse : Control
{
private int x;
private int y;
private int width;
private int height;
public Ellipse(int x, int y, int width, int height)
{
setY(y);
setX(x);
setWidth(width);
setHeight(height);
}
public int getX() { return x;}
public int getY() { return y; }
public int getWidth() { return width; }
public int getHeight() { return height; }
public void setX(int newx) { x = newx; }
public void setY(int newy) { y = newy; }
public void setWidth(int newwidth) { width = newwidth; }
public void setHeight(int newheight) { height = newheight; }
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Call methods of the System.Drawing.Graphics object.
// Declare and instantiate a new pen.
System.Drawing.Pen myPen = new System.Drawing.Pen(Color.Aqua);
// Draw an aqua rectangle in the rectangle represented by the control.
e.Graphics.FillEllipse(Brushes.Black,x,y,width,height);
}
}
Form1 class
private void panel_MouseDown(object sender, MouseEventArgs e)
{
draw = true;
x = e.X;
y = e.Y;
}
private void panel_MouseUp(object sender, MouseEventArgs e)
{
draw = false;
xe = e.X;
ye = e.Y;
Item item;
Enum.TryParse<Item>(menuComboBoxShape.ComboBox.SelectedValue.ToString(), out item);
switch (item)
{
case Item.Pencil:
using (Graphics g = panel.CreateGraphics())
using (var pen = new Pen(System.Drawing.Color.Black)) //Create the pen used to draw the line (using statement makes sure the pen is disposed)
{
g.DrawLine(pen,new Point(x, y), new Point(xe, ye));
}
break;
case Item.Rectangle:
break;
case Item.Ellipse:
Ellipse el = new Ellipse(x,y,xe-x,ye-y);
panel.Controls.Add(el);
break;
default:
break;
}
}
You are inheriting your Ellipse class from Control, but in fact you're not using it as a control - you're not adding it in Controls collection of form, so in fact it is invisible, inactive and not receiving any events from form.
Also painting the control from outer code looks like a bad design. Control should paint itself, and you should set it bounds from outer code.
Here is snippet to drive you to the right way:
class Ellipse : Control
{
Point mDown { get; set; }
public Ellipse()
{
MouseDown += shape_MouseDown;
MouseMove += shape_MouseMove;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillEllipse(Brushes.Black, this.Bounds);
}
private void shape_MouseDown(object sender, MouseEventArgs e)
{
mDown = e.Location;
}
private void shape_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Location = new Point(e.X + Left - mDown.X, e.Y + Top - mDown.Y);
}
}
}
And in the form you should create it like:
el = new Ellipse();
el.Bounds = new Rectangle(0, 0, 100, 100);
Controls.Add(el);
Update
Based on your updated code, I can see a couple of issues:
You actually don't need x, y, width, height properties of your Ellipse class and according getter/setter methods, since it's Control, and it has its own Location and Width, Height public properties.
You are drawing your ellipse incorrectly. Assuming it should fill all the area, painting should be e.Graphics.FillEllipse(Brushes.Black,0,0,Width,Height) (here I assuming using Control.Width instead of your width and so on). Otherwise you're additionally shifting your painted ellipse.
Code in panel_MouseUp concerning ellipse creation should be something like
var el = new Ellipse();
panel.Controls.Add(el);
el.Location = new Point(x, y);
el.Width = (xe - x);
el.Height = (ye - y);
Or, if it should be one single ellipse (right now you're creating new one each time) - create this one outside of mouseUp handler and inside of handler just change it's size and location.

System.NullReferenceException error in C# [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 years ago.
For school we are trying to draw a car in a windows form application, it needs to be OOP. We have 4 buttons in the form, one to draw a circle, one to draw a square, one to draw the complete car and one to make the car ride. We make a Car class which makes two circles and a square which is supposed to make the shape of a car. When we instantiate a new circle in the car class, we get a System.NullReferenceException error. How do we fix this? Button 3 is the create car class. Here is our code:
This is our form:
namespace Maissan_Autootje_V1
{
public partial class Form1 : Form
{
Graphics g;
public Form1()
{
InitializeComponent();
g = this.CreateGraphics();
}
private void button1_Click(object sender, EventArgs e)
{
Refresh();
Square square = new Square(150, 200, 150, 100);
square.Draw(g);
}
private void button2_Click(object sender, EventArgs e)
{
Refresh();
Circle circle = new Circle(100, 250, 100, 100);
Circle circle2 = new Circle(280, 250, 100, 100);
circle.Draw(g);
circle2.Draw(g);
}
private void button3_Click(object sender, EventArgs e)
{
Auto auto = new Auto();
}
private void button4_Click(object sender, EventArgs e)
{
}
}
}
This is our circle (the square is pretty much the same as the circle class):
namespace Maissan_Autootje_V1
{
public class Circle
{
public Pen myPen = new Pen(Color.Blue, 5);
int x;
int y;
int width;
int height;
public Circle(int x, int y, int width, int height)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public void Draw(Graphics g)
{
g.DrawEllipse(myPen, x, y, width, height);
}
}
}
And this is supposed to be the class that draws the car:
namespace Maissan_Autootje_V1
{
class Auto : Form1
{
Graphics g;
public Auto()
{
Circle circle = new Circle(100, 250, 100, 100);
Circle circle2 = new Circle(280, 250, 100, 100);
Square square = new Square(150, 200, 150, 100);
circle.Draw(g);
circle2.Draw(g);
square.Draw(g);
}
}
}
Thanks in advance!
You need to give the Auto an instance of the Graphics object.
Graphics g == null
So.. for example:
class Auto
{
public Auto(Graphics g)
{
Circle circle = new Circle(100, 250, 100, 100);
Circle circle2 = new Circle(280, 250, 100, 100);
Square square = new Square(150, 200, 150, 100);
circle.Draw(g);
circle2.Draw(g);
square.Draw(g);
}
}

How can I make a concentric pattern of circles in my WinForms application?

i am having trouble trying to make the circles into concentric pattern. For example, the next circle bigger, then bigger and so on. A bit like the core, inner core, outer core, and crust of the earth.
Below is all of my code:
namespace ClickAppearBalls
{
public partial class Form1 : Form
{
private Random randClick;
private Graphics paper;
private Pen pen;
public Form1()
{
InitializeComponent();
randClick = new Random();
paper = picCanvas.CreateGraphics();
}
private void picCanvas_Click(object sender, EventArgs e)
{
int x, y, size1, size2;
x = picCanvas.Height / 2;
y = picCanvas.Width / 2;
Color color = Color.FromArgb(randClick.Next(0, 256), randClick.Next(0, 256), randClick.Next(0, 256));
Pen pen = new Pen(color);
pen.Width = 3;
size1 = 30;
size2 = 30;
paper.DrawEllipse(pen, x, y, size1, size2);
}
}
}
You need to define the size variable on the class so that it can be used on consecutive clicks. Then you need to increase it with every click.
namespace ClickAppearBalls
{
public partial class Form1 : Form
{
private Random randClick;
private Graphics paper;
private Pen pen;
private int circleSize = 30;
public Form1()
{
InitializeComponent();
randClick = new Random();
paper = picCanvas.CreateGraphics();
}
private void picCanvas_Click(object sender, EventArgs e)
{
int x, y;
x = picCanvas.Height / 2;
y = picCanvas.Width / 2;
Color color = Color.FromArgb(randClick.Next(0, 256), randClick.Next(0, 256), randClick.Next(0, 256));
Pen pen = new Pen(color);
pen.Width = 3;
paper.DrawEllipse(pen, x - circleSize/2, y - circleSize/2, circleSize, circleSize);
circleSize += 10; // increase size here
}
}
}

Drawing Multiple Rectangles c#

What would be the best way to draw 25 rectangles (5*5) in c#?
I later need to be able to reach a specific rectangle and change its color, for instance change the color to red if the user inputs the incorrect word.
Would it be more suitable to create an array of rectangles in this case?
This is what i have so far
Graphics g = pictureBox1.CreateGraphics();
int x =0;
int y= 0;
int width = 20;
int height = 20;
for (int i = 0; i < 25; i++)
{
if (i <= 4)
{
g.FillRectangle(Brushes.Blue, x, y, width, height);
x += 50;
}
else if (i > 4)
{
y = 50;
g.FillRectangle(Brushes.Blue, x, y, width, height);
x += 50;
}
}
This should get you started, not the complete code. You will need to add a PictureBox control and use the default name (picurebox1). EDIT: Need to add a button too :)
public partial class Form1 : Form
{
public List<Rectangle> listRec = new List<Rectangle>();
Graphics g;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Rectangle rect = new Rectangle();
rect.Size = new Size(100,20);
for (int x = 0; x < 5; x++)
{
rect.X = x * rect.Width;
for (int y = 0; y < 5; y++)
{
rect.Y = y * rect.Height;
listRec.Add(rect);
}
}
foreach (Rectangle rec in listRec)
{
g = pictureBox1.CreateGraphics();
Pen p = new Pen(Color.Blue);
g.DrawRectangle(p, rec);
}
}
public void ChangeColor(Rectangle target, Color targetColor)
{
Pen p = new Pen(targetColor);
g.DrawRectangle(p, target.X, target.Y, target.Width, target.Height);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.D0: ChangeColor(listRec[0], Color.Red);
break;
case Keys.D1: ChangeColor(listRec[1], Color.Red);
break;
//..more code to handle all keys..
}
}
}
If you're not concerned with performance or the looks, then the easiest approach would be to create a List of Lists of Panels in your Form_Load event as one of the comments mentions.
List<List<Panel>> panelGrid = new List<List<Panel>>();
for (var i = 0; i < 5; i++)
{
var panelRow = new List<Panel>();
for (var j = 0; j < 5; j++)
{
panelRow.Add(new Panel());
// add positioning logic here
}
panelGrid.Add(panelRow);
}
Then you will be able to reference each individual one at a later stage...
If you have to use Graphics class (which is the better approach), then you should setup something similar however replacing Panel with a class of your own. Then in Form_Paint event you would iterate through the list of objects and render them.
class MyPanel
{
public Size size;
public Color color;
}
...
foreach (var myPanelRow in myPanelGrid)
foreach (var myPanel in myPanelRow)
g.FillRectangle(myPanel.color, myPanel.size); // this obviously won't work as is, but you get the idea
Then when you need to change a color, you do something like:
myPanelsGrid[0][0].color = Color.Blue;
myForm.Invalidate();
The second line will result in Paint in event being called again.

Categories

Resources