Following is my code. i am trying to draw line, filled rectangle, etc.....
Problem is that, lets suppose i draw a line but when i try to draw an other line first drawn line disappears. so i want help that i'll be able to draw multiple shapes on a form and first draw lines don't disappears.
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;
namespace finalPaint
{
public partial class Form1 : Form
{
List<Point> points = new List<Point>();
Rectangle rect;
Point first;
Point last;
string op;
public Form1()
{
InitializeComponent();
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
points.Add(e.Location);
rect = new Rectangle(rect.Left, rect.Top, e.X - rect.Left, e.Y - rect.Top);
last = e.Location;
this.Invalidate();
this.Update();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
switch (op)
{
case "toolStripButton1":
{
if (points.Count > 2)
{
e.Graphics.DrawLines(Pens.Black, points.ToArray());
}
}
break;
case "toolStripButton2":
{
using (Pen pen = new Pen(Color.Red, 2))
{
e.Graphics.DrawRectangle(pen, rect);
}
}
break;
case "toolStripButton3":
{
Pen pen = new Pen(Color.Red, 2);
e.Graphics.DrawLine(pen, first, last);
this.Update();
}
break;
case "toolStripButton4":
{
using (SolidBrush pen = new SolidBrush(Color.Red))
{
e.Graphics.FillRectangle(pen, rect);
}
}
break;
case "toolStripButton5":
{
using (SolidBrush pen = new SolidBrush(Color.Red))
{
e.Graphics.FillEllipse(pen, rect);
}
}
break;
case "toolStripButton6":
{
using (Pen pen = new Pen(Color.Red,2))
{
e.Graphics.DrawEllipse(pen, rect);
}
}
break;
default:
break;
}
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
rect = new Rectangle(e.X, e.Y, 0, 0);
first = e.Location;
this.Invalidate();
}
private void toolStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
}
private void selectedButton(object sender, EventArgs e)
{
foreach (ToolStripButton btn in toolStrip1.Items)
{
btn.Checked = false;
}
ToolStripButton btnClicked = sender as ToolStripButton;
btnClicked.Checked = true;
op = btnClicked.Name;
}
}
}
On each Paint event, you need to paint all of the objects you want on the screen. You are not just painting on top of what is already there. You are repainting the entire scene.
The reason for this is that your control may be obscured from view at some point, and Windows will repaint it when it is revealed again.
If you want to keep a memory of all the the objects, you need to store them in your code. Since each object is different (lines, rectangles, ellipses) you will want to store them in a manner that lets you differentiate. You could create classes like this:
public class DrawingShape
{
public string Name { get; set; }
public DrawingShapeType Type { get; set; }
// other shared properties
public virtual void Draw(Graphics g)
{
}
}
public class DrawingRectangle : DrawingShape
{
public DrawingRectangle()
{
Name = "Rectangle";
Type = DrawingShapeType.Rectangle;
}
public override void Draw(Graphics g)
{
// draw this shape
}
}
public enum DrawingShapeType
{
Rectangle,
Ellipse,
Line,
}
Then you can just store all your objects in a List. The order of the items in the list is your z-order, so you add items to the list and you enumerate through the list in your Paint event and draw each one differently depending on the type.
From here you can store pen and brush information in the class and other info. Your Paint event can tell each class to paint itself and it doesn't need to know which type they are.
You need a possibility to store all your shapes, in order to draw them all in the Paint event, since the background of the form is repainted before each call to Paint. Let us define a base class from which we will derive all the shapes
abstract class Shape
{
public abstract void Paint(PaintEventArgs e);
public abstract void UpdateShape(Point newLocation);
}
Here we declare the abstract methods Paint and UpdateShape that we will have to override in the derived classes. UpdateShape will be called in MouseMove.
Let us start with the freeform line
class FreeformLine : Shape
{
private List<Point> _points = new List<Point>();
public FreeformLine(Point startLocation)
{
_points.Add(startLocation);
}
public override void Paint(PaintEventArgs e)
{
if (_points.Count >= 2) {
e.Graphics.DrawLines(Pens.Black, _points.ToArray());
}
}
public override void UpdateShape(Point newLocation)
{
const int minDist = 3;
// Add new point only if it has a minimal distance from the last one.
// This creates a smoother line.
Point last = _points[_points.Count - 1];
if (Math.Abs(newLocation.X - last.X) >= minDist ||
Math.Abs(newLocation.Y - last.Y) >= minDist)
{
_points.Add(newLocation);
}
}
}
Here we need a list of points. In the constructor, we pass the first point. The Paint method just executes the paint logic that you had already defined and the UpdateShape method adds new points to our points list.
The straight line works in a very similar way, but defines only the first and the last point.
class StraightLine : Shape
{
private Point _first;
private Point _last;
public StraightLine(Point startLocation)
{
_first = startLocation;
}
public override void Paint(PaintEventArgs e)
{
if (!_last.IsEmpty) {
Pen pen2 = new Pen(Color.Red, 2);
e.Graphics.DrawLine(pen2, _first, _last);
}
}
public override void UpdateShape(Point newLocation)
{
_last = newLocation;
}
}
We define only one rectangle class and add a variable in order to remember if the shape is filled or not.
class RectangleShape : Shape
{
protected bool _filled;
protected Rectangle _rect;
protected Point _start;
public RectangleShape(Point startLocation, bool filled)
{
_start = startLocation;
_rect = new Rectangle(startLocation.X, startLocation.Y, 0, 0);
_filled = filled;
}
public override void Paint(PaintEventArgs e)
{
if (_filled) {
using (SolidBrush brush = new SolidBrush(Color.Red)) {
e.Graphics.FillRectangle(brush, _rect);
}
} else {
using (Pen pen = new Pen(Color.Red, 2)) {
e.Graphics.DrawRectangle(pen, _rect);
}
}
}
public override void UpdateShape(Point newLocation)
{
int x = Math.Min(_start.X, newLocation.X);
int y = Math.Min(_start.Y, newLocation.Y);
int width = Math.Abs(newLocation.X - _start.X);
int height = Math.Abs(newLocation.Y - _start.Y);
_rect = new Rectangle(x, y, width, height);
}
}
Finally, we declare the ellipse class. Since this one uses a rectangle as well, we just derive it from our rectangle class.
class Ellipse : RectangleShape
{
public Ellipse(Point startLocation, bool filled)
: base(startLocation, filled)
{
}
public override void Paint(PaintEventArgs e)
{
if (_filled) {
using (SolidBrush brush = new SolidBrush(Color.Red)) {
e.Graphics.FillEllipse(brush, _rect);
}
} else {
using (Pen pen = new Pen(Color.Red, 2)) {
e.Graphics.DrawEllipse(pen, _rect);
}
}
}
}
Here we only override the Paint method. All the rectangle update logic remains the same.
Now to the form. Here we declare the global variables
List<Shape> _shapes = new List<Shape>();
Shape _lastShape;
string op;
In the mouse down event we create a new shape and add it to the list like this
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
switch (op) {
case "toolStripButton1":
_lastShape = new FreeformLine(e.Location);
break;
case "toolStripButton2":
_lastShape = new RectangleShape(e.Location, false);
break;
case "toolStripButton3":
_lastShape = new StraightLine(e.Location);
break;
case "toolStripButton4":
_lastShape = new RectangleShape(e.Location, true);
break;
case "toolStripButton5":
_lastShape = new Ellipse(e.Location, true);
break;
case "toolStripButton6":
_lastShape = new Ellipse(e.Location, false);
break;
default:
break;
}
_shapes.Add(_lastShape);
Refresh();
}
In the MouseMove we update the last shape like this
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && _lastShape != null) {
_lastShape.UpdateShape(e.Location);
this.Refresh();
}
}
The Paint method is now much simpler
private void Form1_Paint(object sender, PaintEventArgs e)
{
foreach (Shape shape in _shapes) {
shape.Paint(e);
}
}
Note that we do all the shape specific things in the shape classes, instead of doing them in the form. The only place in the form where have to care about the different shapes, is where we create the different shapes. This is a typical object-oriented approach. It is easier to maintain and to extend. You could add new shapes, with only a minimum changes in the form itself.
Related
I have an abstract class "Element" which its instances have to use the function DrawRectangle() from System.Drawing.
The problem is that because the class is abstract it can't inherit from FORM so the program doesn't recognize the classes..
How can I solve this?
I've tried puting a variable of type Form inside Element and didn't work.
I also tried the opposite, puting an Element variable inside Form.
It is my first time with Winform and C#...
It is supposed to be a mouse race game, the objects drawn in page are supposed to chase the mouse or go in other directions but I need it to be object oriented.
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace MyMouseGame
{
public abstract class Element
{
//Form1 myForm = new Form1();// not sure I need it
public enum EnumShape { Square, Circle, Triangle }
public enum EnumType { Chase, Escape, Random }
//variables
private double X { get; set; }
private double Y { get; set; }
private int Size { get; }
private int Speed { get; }
private EnumShape Shape { get; set; }
protected EnumType Type { get; set; }
private static Random R = new Random();
//methods
public int generateRandomNum()
{
int randomNum = R.Next(20, 100);
return randomNum;
}
public Element()
{
X= 0;
Y = 0;
Shape = 0;
Size = generateRandomNum();
Speed = generateRandomNum();
Type = 0;
}
public void ElementsFactory()
{
}
public void hitTarget(e) { }
public abstract void Draw(Form1 g); //here I tried to pass a form inside
public abstract void Move();
}
}
//example of one of the instances classes of element
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace MyMouseGame
{
class E_Escape : Element
{
int move_circleX = 0;
int move_circleY = 0;
bool flag = false;
Rectangle circle = new Rectangle(10, 70, 35, 35);
Pen p = new Pen(Color.Black);
//circle
public E_Escape()
{
}
public override void Draw(Form1 g) {
g.DrawEllipse(p, circle);
g.FillEllipse(new SolidBrush(Color.Red), circle);
}
public override void Move() {
if (!flag)
{
if (circle.X >= panel1.Width - 2)
flag = true;
circle.X += 10;
}
else
{
if (circle.X <= 30)
flag = false;
circle.X -= 10;
}
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
namespace MyMouseGame
{
public partial class Form1 : Form
{
Graphics g;
Element [] elements= new Element[3];
public Form1()
{
this.DoubleBuffered = true;
InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
g = panel1.CreateGraphics();
//timer set
t.Interval = 100;
t.Tick += new EventHandler(timer1_Tick);
t.Start();
}
private void recThreadTracker()
{
//move rectangle
while (true)//here I tried to call element finction draw
{
elements[0].Draw(g);
elements[1].Draw(g);
elements[2].Draw(g);
}
}
public void threadCounter()
{
long counter = 0;
while (true)
{
counter++;
this.Invoke(new Action(() =>
{
lcountRes.Text = counter.ToString();
}));
Thread.Sleep(1000);
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
Thread counterThread = new Thread(threadCounter);
counterThread.Start();
Thread recTrackThread = new Thread(recThreadTracker);
recTrackThread.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
foreach (Element elements in elements)
{
elements.Move();
}
//Refresh();
Invalidate();
}
}
}
The drawing routine needs two things. A Graphics object, and the Size of the drawing area.
For example, to draw a circle on the center of the graphics area
public void Draw(Graphics g, Size target)
{
int diameter = 16;
g.DrawEllipse(Pens.Black, target.Width/2 - diameter/2, target.Height/2 - diameter/2, diameter, diameter);
}
And in your form's paint event you call all the draw functions
void panel1_Paint(object sender, PaintEventArgs e)
{
foreach(var item in Elements)
{
item.Draw(e.Graphics, pictureBox1.ClientSize);
}
}
my drawings are deleted in the code I wrote. If "refresh" is not used, the drawing does not appear. Is there a mistake in my drawing? I don't understand
How can I draw a new line without erasing my lines ?
Here's the code
Pen pen;
Point startXY;
Point endXY;
bool ismoving = false;
string choice = "Line";
public Form1(){
InitializeComponent();}
private void drawArea_MouseDown(object sender, MouseEventArgs e){
startXY = e.Location;
ismoving = true;}
private void drawArea_MouseMove(object sender, MouseEventArgs e){
if (ismoving == true){
endXY = e.Location;
drawArea.Refresh();}}
private void drawArea_MouseUp(object sender, MouseEventArgs e){
endXY = e.Location;
ismoving = false;}
private void Form1_Load(object sender, EventArgs e){
//Graphics graph = drawArea.CreateGraphics();
//graph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
pen = new Pen(Color.White,1);
pen.StartCap = pen.EndCap = System.Drawing.Drawing2D.LineCap.Round;}
private void drawArea_Paint(object sender, PaintEventArgs e){
switch (choice){
case "Line":{
e.Graphics.DrawLine(pen, startXY, endXY);
break;}}}
Your code needs to know how to recreate the entire graphics window at any time, because windows may ask it to redraw at any time.
So you need to keep track of the things to be drawn in a list and use this list in the Paint event to render to the screen.
Below is an example code that does this. The result looks like this
public enum Tool
{
Line,
PolyLine,
Circle,
}
public partial class Form1 : Form
{
Point startXY;
Point endXY;
bool isMoving;
Tool next;
public Form1()
{
InitializeComponent();
this.Drawing = new List<IDrawObject>();
this.isMoving = false;
this.next = Tool.Line;
this.drawArea.BackColor = Color.Black;
this.drawArea.BorderStyle = BorderStyle.FixedSingle;
}
public List<IDrawObject> Drawing { get; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
drawArea.Resize += (s, ev) => drawArea.Refresh();
drawArea.Paint += pictureBox1_Paint;
drawArea.MouseDown += PictureBox1_MouseDown;
drawArea.MouseMove += PictureBox1_MouseMove;
drawArea.MouseUp += PictureBox1_MouseUp;
this.KeyDown += (s, ev) =>
{
switch (ev.KeyCode)
{
case Keys.Space:
next = NextTool(next);
UpdateFormTitle();
break;
}
};
UpdateFormTitle();
}
public void UpdateFormTitle()
{
this.Text = $"Draw Area. Tool={next}. Press [SPACE] to switch.";
}
private void PictureBox1_MouseUp(object sender, MouseEventArgs e)
{
isMoving = false;
endXY = e.Location;
Drawing.Add(NextDrawObject());
drawArea.Invalidate();
}
private void PictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (isMoving)
{
endXY = e.Location;
drawArea.Invalidate();
}
}
private void PictureBox1_MouseDown(object sender, MouseEventArgs e)
{
isMoving = true;
startXY = e.Location;
}
protected void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var pen = new Pen(Color.White, 1))
{
pen.EndCap = LineCap.Round;
pen.StartCap = LineCap.Round;
foreach (var item in Drawing)
{
item.Draw(e.Graphics, pen);
}
if (isMoving)
{
pen.Color = Color.SteelBlue;
pen.DashStyle = DashStyle.Dash;
NextDrawObject().Draw(e.Graphics, pen);
}
}
}
public static float Distance(Point from, Point to)
{
var dx = (float)(to.X-from.X);
var dy = (float)(to.Y-from.Y);
return (float)Math.Sqrt(dx*dx+dy*dy);
}
public Tool NextTool(Tool current)
{
switch (current)
{
case Tool.Line:
return Tool.Circle;
case Tool.Circle:
return Tool.Line;
case Tool.PolyLine:
throw new NotImplementedException();
default:
throw new NotSupportedException();
}
}
public IDrawObject NextDrawObject()
{
switch (next)
{
case Tool.Line:
return new Line(startXY, endXY);
case Tool.PolyLine:
throw new NotImplementedException();
case Tool.Circle:
var radius = Distance(startXY, endXY);
return new Circle(startXY, radius);
default:
throw new NotSupportedException();
}
}
}
public interface IDrawObject
{
void Draw(Graphics g, Pen pen);
}
public struct Line : IDrawObject
{
public Line(PointF from, PointF to)
{
this.From=from;
this.To=to;
}
public PointF From { get; }
public PointF To { get; }
public void Draw(Graphics g, Pen pen)
{
g.DrawLine(pen, From, To);
}
}
public struct PolyLine : IDrawObject
{
public PolyLine(params PointF[] nodes)
{
this.Nodes=nodes;
}
public PointF[] Nodes { get; }
public void Draw(Graphics g, Pen pen)
{
g.DrawLines(pen, Nodes);
}
}
public struct Circle : IDrawObject
{
public Circle(PointF center, float radius)
{
this.Center=center;
this.Radius=radius;
}
public PointF Center { get; }
public float Radius { get; }
public void Draw(Graphics g, Pen pen)
{
g.DrawEllipse(pen, Center.X-Radius, Center.Y-Radius, 2*Radius, 2*Radius);
}
}
How do we make a Panel control scroll whatever's inside of it? I'm not talking about controls or user controls or custom controls. I'm talking only about pixels; drawn with GDI+:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace GDITEST
{
public partial class Form1 : Form
{
public class Item
{
public int Height { get; set; }
public int Width { get; set; }
public int Top { get; set; }
}
internal List<Item> items = new List<Item>();
public Form1()
{
InitializeComponent();
}
private void panel_Paint(object sender, PaintEventArgs e)
{
if (items != null)
{
if (items.Count >= 1)
{
foreach (Item item in items)
{
using (Pen pen = new Pen(Color.Blue, 1))
{
int count;
count = items.Count;
count = count >= 1 ? count : 1;
e.Graphics.DrawRectangle(pen, 0, item.Top, (item.Width - SystemInformation.VerticalScrollBarWidth), item.Height);
}
}
}
}
}
private void button1_Click(object sender, EventArgs e)
{
items.Add(new Item() { Width = this.Width, Height = 25, Top = (items.Count * 25) });
panel.Refresh();
}
}
}
The above code draws a blue rectangle (kinda like a vertical list). When the number of rectangles extends the height of the panel, I want the panel to scroll.
I've not been able to find out how to do this, since most of the results only return stuff related to scrolling custom controls.
I did read somewhere (which I can no longer find) that you can use some translateX or translateY methods... Yet I am having a hard time trying to find out anything more about those methods.
There's a simple bug in your code, you forgot to offset what you draw by the scroll amount. The Panel class has two other quirks, it was optimized to be a container control and cuts corners on the way it paints. You get rid of all three issues by creating your derived class from Panel. Project > Add Class > paste the code shown below. Build > Build and drop the new control from the top of the toolbox onto your form.
using System;
using System.Windows.Forms;
class MyPanel : Panel {
public MyPanel() {
this.DoubleBuffered = this.ResizeRedraw = true;
}
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.TranslateTransform(this.AutoScrollPosition.X, this.AutoScrollPosition.Y);
base.OnPaint(e);
}
}
You can further optimize your Paint event handler by paying attention to the e.ClipRectangle property and skip drawing an item when it is clipped. Just in case: assign the AutoScrollMinSize property to fit the items.
Here's a rough example on how to manually show the scrollbars. The panel contains a red rectangle, which can be clicked and dragged. If the rectangle is moved outside the viewable area, the scrollbars appear.
public class DrawPanel : Panel {
public Rectangle rect = new Rectangle(0, 0, 200, 100);
int offsetX = 0;
int offsetY = 0;
bool grabbing = false;
public DrawPanel() {
Dock = DockStyle.Fill;
AutoScroll = true;
}
protected override void OnMouseDown(MouseEventArgs e) {
base.OnMouseDown(e);
var p = e.Location;
if (rect.Contains(p)) {
grabbing = true;
offsetX = rect.X - p.X;
offsetY = rect.Y - p.Y;
}
}
protected override void OnMouseUp(MouseEventArgs e) {
base.OnMouseUp(e);
grabbing = false;
}
protected override void OnMouseMove(MouseEventArgs e) {
base.OnMouseMove(e);
if (grabbing) {
var p = e.Location;
rect.Location = new Point(p.X + offsetX, p.Y + offsetY);
Invalidate();
int right = rect.X + rect.Width;
int bottom = rect.Y + rect.Height;
if (right > Width || bottom > Height) {
this.AutoScrollMinSize = new Size(right + 1, bottom + 1);
}
}
}
protected override void OnScroll(ScrollEventArgs se) {
base.OnScroll(se);
Invalidate();
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
var g = e.Graphics;
var p = AutoScrollPosition;
Rectangle r = rect;
r.X += p.X;
r.Y += p.Y;
g.DrawRectangle(Pens.Red, r);
}
}
I'm plowing through the Dietle C# book one page at a time and I'm stuck.
On page 555, there's the most basic drawing program you can imagine. As you move your mouse around, it's supposed to draw an ellipse on the screen.
Well, mine doesn't.
I've checked everything possible. I've gone onto the Dietel website and downloaded the code and tried that. I think I'm doing something wrong outside of the text-based programming. I mean, there are settings and stuff in the properties windows.
I think I got it all right, but nothing seems to work. But obviously I don't have it all right or it would work.
The full code is a bit longer than what I have below, but even this simplified code doesn't work. It's supposed to draw ellipses any time you have the mouse on the screen. Studio Express does a nice job of catching a lot of syntax errors, but of course it can't catch logic errors. Any ideas as to what's wrong?
using System;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication6
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
using (Graphics graphics = CreateGraphics())
{
graphics.FillEllipse(
new SolidBrush(Color.Blue), e.X, e.Y, 20, 20);
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
MouseMove Event??
public Form1()
{
InitializeComponent();
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseMove);
}
I would do it like this:
public partial class Form1 : Form
{
private List<IDrawAble> shapes = new List<IDrawAble>();
private MyEllipse currentlyDrawing;
public Form1()
{
InitializeComponent();
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
currentlyDrawing = new MyEllipse() { X1 = e.X, Y1 = e.Y, X2 = e.X, Y2 = e.Y };
Invalidate();
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
shapes.Add(currentlyDrawing);
currentlyDrawing = null;
Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.White);
foreach (var item in shapes)
{
item.Draw(e.Graphics);
}
if (currentlyDrawing != null)
{
currentlyDrawing.Draw(e.Graphics);
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (currentlyDrawing != null)
{
currentlyDrawing.X2 = e.X;
currentlyDrawing.Y2 = e.Y;
Invalidate();
}
}
}
class MyEllipse : IDrawAble
{
public int X1 { get; set; }
public int Y1 { get; set; }
public int X2 { get; set; }
public int Y2 { get; set; }
public void Draw(Graphics g)
{
g.FillEllipse(new SolidBrush(Color.Blue), X1, Y1, X2 - X1, Y2 - Y1);
}
}
interface IDrawAble
{
void Draw(Graphics g);
}
Make sure all eventhandlers are hooked to the events of the form.
To get rid of the flickering set the DoubleBuffered Property of the Form to true.
What is it doing now?
Just to Add.
Make sure your event MouseMove is mapped with the Method Form1_MouseMove
In the Method Hieght and weight are 20 which means it is circle and not eclipse.
for to debug first replace e.X and e.Y with number in below snippet it is 0
SolidBrush redBrush = new SolidBrush(Color.Red);
// Create location and size of ellipse.
float x = 0.0F;
float y = 0.0F;
float width = 200.0F;
float height = 100.0F;
using (Graphics graphics = CreateGraphics())
{
graphics.FillEllipse(redBrush, x, y, width, height);
}
I want to paint a graphics object from a method (paint) I created in a separate class (Paintball). I want it to paint in a picturebox only when I left-click with my mouse and I want the point where I shoot to be stored in a List. When I try the code below, it doesn't shoot. Below is the class Paintball.
{
private List<Point> myClick;
public Paintball()
{
myClick = new List<Point>();
}
public void add(Point location)
{
myClick.Add(location);
}
public void paint(Graphics g, Point point)
{
g.FillEllipse(Brushes.Blue, point.X, point.Y, 20, 20);
}
}
}
This is form1 below.
namespace AmazingPaintball
{
public partial class Form1 : Form
{
Random positionX = new Random();
Random positionY = new Random();
Target einstein;
int count;
List<Point> ballList = new List<Point>();
Paintball gun;
public Form1()
{
InitializeComponent();
Point point = new Point(positionX.Next(0, 638), positionY.Next(0, 404));
einstein = new Target(point);
ptrEinstein.Location = point;
gun = new Paintball();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
ptrEinstein.Location = einstein.Move(e.KeyData);
pictureBox1.Update();
pictureBox1.Refresh();
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
count++;
gun.add(e.Location);
pictureBox1.Refresh();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
foreach (var Paintball in ballList)
{
gun.paint(e.Graphics, this.PointToClient(Cursor.Position));
pictureBox1.Refresh();
}
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Start();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
pictureBox1.Refresh();
}
}
}
Please let me know if you know what has to be edited/created. Thank You
Your original code has many mistakes. Let's try to simplify what you are doing and tackle simply storing a list of points and drawing them to the picturebox.
public partial class Form1 : Form
{
List<Point> ballList = new List<Point>();
public Form1()
{
InitializeComponent();
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
ballList.Add(e.Location);
pictureBox1.Refresh();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
foreach (Point pBall in ballList)
{
e.Graphics.FillEllipse(Brushes.Blue, pBall.X, pBall.Y, 20, 20);
}
}
}
Here we have a list, we add the click points to it in the click handler and paint them in the paint handler. Once you get comfortable with this, perhaps move to the next task in your program and ask a new question if you get stuck with the next feature.
Ok, I've got a bit of time, so let's look at your paintball class. I've renamed it Paintballs since it contains many of them and this name is more appropriate. If you want to keep the list of points private that's ok. You are trying to implement a Paint method in the class, but it takes a Point as argument and does not operate on any of the class's instance state - this probably isn't what you want. Consider now :
public class Paintballs
{
private List<Point> myClick;
public Paintballs()
{
myClick = new List<Point>();
}
public void Add(Point location)
{
myClick.Add(location);
}
public void Paint(Graphics g)
{
foreach (Point p in myClick)
{
g.FillEllipse(Brushes.Blue, p.X, p.Y, 20, 20);
}
}
}
Here we have a public Paint method that will draw all of the paintballs in the class to any graphics instance you pass to it. Now your form code would look like :
public partial class Form1 : Form
{
Paintballs pBalls = new Paintballs();
public Form1()
{
InitializeComponent();
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
pBalls.Add(e.Location);
pictureBox1.Refresh();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
pBalls.Paint(e.Graphics);
}
}
So we've simplified the form code by pushing the painting method into the paintballs class itself. This makes the class responsible for knowing what the paintballs look like, how many there are, where they are, and how to draw them to a Graphics object. This is step 1 in encapsulating responsibility.
You're drawing from a list of points stored in that ballList variable. However, you've never added any points to that list.
Make the myClick list in Paintball public and, in the pictureBox1_Paint method, iterate through that list instead of ballList.