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.
Related
I have a host class which inherits from Form. I use it to embed an WPF user control to use it in a winform application. This is customizable, I mean, you can choose to make form borderless or not.
If borderless, you cannot move the window, so I need to implement it manually. In this case I subscribe to some event which do the trick (I have removed the not necessary things from the class to focus only on the important parts):
public class MyHostDialog : Form
{
public MyDialogHost()
{
InitializeComponent();
}
public MyHostDialog(MyDialog myDialog) : this()
{
this.ElementHost.Child = new MyHostDialogView(myDialog);
if (this.Borderless)
{
this.ElementHost.Child.MouseDown += Child_MouseDown;
this.ElementHost.Child.MouseUp += Child_MouseUp;
this.ElementHost.Child.MouseMove += Child_MouseMove;
}
}
// BELOW CODE DOES NOT WORK, IT WOULD WORK IF Input.MouseButtonEventArgs and Input.MouseEventArgs WERE
// System.Windows.FORMS.MouseEventArgs INSTEAD.
private bool dragging = false;
private System.Drawing.Point startPoint = new System.Drawing.Point(0,0);
private void Child_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
dragging = true;
startPoint = new System.Drawing.Point(e.X, e.Y);
}
private void Child_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
dragging = false;
}
private void Child_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (dragging)
{
System.Drawing.Point p= PointToScreen(e.Location);
Location = new System.Drawing.Point(p.X - this.startPoint.X, p.Y - this.startPoint.Y);
}
}
}
Above code would work if instead of using Input.MouseButtonEventArgs and Input.MouseEventArgs, they were System.Windows.FORMS.MouseEventArgs. So, how to convert that code to work with MouseButtonEventArgs?
I haven't been learning C# for very long and was wondering if it is possible to create a mouse event from another class?
The intention is that when a mousedown happens, something is drawn on a panel. I would like to do all this from a different class is this possible?
This is what I've already tried:
class Circle: Form1
{
Graphics g;
Pen pen = new Pen(Color.Black);
// Making a event ?
public event EventHandler<MouseEventArgs> MouseDown;
protected void OnClick(MouseEventArgs e)
{
EventHandler<MouseEventArgs> handler = MouseDown;
if (handler != null)
{
handler(this, e);
}
}
public Circle()
{
g = this.panel1.CreateGraphics();
}
public void Mouse_Down(object sender, MouseEventArgs e)
{
// Draw something
g.DrawLine(pen, 0, 0, 50, 50);
}
}
}
So instead of calling the panel1_MouseDown event in this class I want to call it from the circle class:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
// So instead of calling the panel1_MouseDown event in this class I want to call it from the circle class
}
}
}
Yes, you can "do all this from a different class"
Referring to the the example below:
In Form1 constructor create initializes the instance of the Circle class and passes to its constructor an instance of Form1.
Make sure that the control you want to draw on is public (panel1 in the example).
Add MouseDown and Paint events to panel1.
Always use the Paint event to draw graphics - it's the best practice.
More info on Control.Paint Event please: read here
Form1:
public partial class Form1 : Form
{
Circle circle;
public Form1()
{
InitializeComponent();
// Start the measuring time for reauthentication
circle = new Circle(this);
}
}
Circle Class:
class Circle
{
private Form1 Instance;
public Circle(Form1 instance)
{
this.Instance = instance;
// Make sure the access modifier of panel1 is Public and add mousedown event
Instance.panel1.MouseDown += panel1_MouseDown;
// Add a paint event - this is the best practice to draw graphics
Instance.panel1.Paint += panel1_Paint;
}
private int X;
private int Y;
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
this.X = e.X;
this.Y = e.Y;
// Redraw the panel when mouse is down
Instance.panel1.Refresh();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
if (this.X > 0 && this.Y > 0)
{
Graphics g = e.Graphics;
Pen p = new Pen(Color.Red);
g.DrawEllipse(p, X, Y, 50, 50);
}
}
}
Output:
I had a task to move an element(Button, Label...) around a panel within Winforms with C#.
I solved it like this, it works:
private void button1_Click(object sender, EventArgs e)
{
// System.Threading.Thread.Sleep(100 - auto.Geschwindigkeit);
for (int i = 0; i < panel1.Width; i++)
{
label1.Location = new Point(i, label1.Location.Y);
label2.Location = new Point(i, label2.Location.Y);
System.Threading.Thread.Sleep(50);//speed
Application.DoEvents();
}
}
But is there another way to do this, for example when I want to programm a game and I have 10 Labels(which represent a driving car), I think this would be to overloaded to work with Threads, because the CPU goes higher and higher ?! "System.Threading.Thread.Sleep(50);" would be the speed of an element, I think I need something which is more performant ?!
Thank You
Do not use Thread.Sleep for timing. Use a timer instead:
private void btnStart_Click(object sender, EventArgs e)
{
timer1.Interval = 100; // animation speed
timer1.Enabled = true; // starting animation
}
private void timer1_Tick(object sender, EventArgs e)
{
// do the replacements here
}
But honestly, I would not use controls to represent animated objects. They have a million of properties, events and other data that you do not need. Instead, I would use dedicated Car objects and custom drawing.
public class Car
{
public Size Size { get; set; }
public Color Color { get; set; }
public Point Location { get; set; }
public int Speed { get; set; }
// and whatever you need, eg. direction, etc.
}
private List<Car> cars;
public Form1()
{
InitializeComponent();
cars = new List<Car>
{
new Car { Size = new Size(30, 15), Color = Color.Blue, Location = new Point(100, 100), Speed = 1 },
new Car { Size = new Size(50, 20), Color = Color.Red, Location = new Point(200, 150), Speed = 3 },
};
}
private void btnStart_Click(object sender, EventArgs e)
{
timer1.Interval = 100; // animation speed
timer1.Enabled = true; // starting animation
}
private void timer1_Tick(object sender, EventArgs e)
{
foreach (Car car in cars)
RecalculateLocation(car); // update Location by speed here
panel1.Invalidate();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
// now we are just drawing colored rectangles but you can draw car.Image or anything you want
foreach (Car car in cars)
{
using (Brush brush = new SolidBrush(car.Color))
{
e.Graphics.FillRectangle(brush, new Rectangle(car.Location, car.Size));
}
}
}
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 have a little project in C#, (Windows Forms Application). I have on the form 77 PictureBoxes (pictureBox1, pictureBox2, pictureBox3, ...) and I want to control them but from a new class (Access.cs), by declaring a new one picturebox in the class to control all the pictures.
Because it would be too long if I pass through each pictureBox and add a click method and Copy + Paste the code and change the pictureBox number each time.
I've set the pictures as public and tried the following code:
Access.cs:
using System.Windows.Forms;
public class Access
{
PictureBox picBox = new PictureBox();
public void PictureClicked()
{
picBox.Image = Properties.Resources.apple;
}
}
Form1.cs:
private void pictureBox1_Click(object sender, EventArgs e)
{
Access ac = new Access();
ac.PictureClicked();
}
but the code didn't work!!
I dont really get what you want to do but you could try to send the object to your Access class:
private void pictureBox1_Click(object sender, EventArgs e)
{
Access ac = new Access();
ac.PictureClicked(sender);
}
public void PictureClicked(Object Sender)
{
picBox = (PictureBox)Sender;
picBox.Image = Properties.Resources.apple;
}
Access.Cs
public void pictureBox1_Click(object sender, EventArgs e)
{
PictureBox pi = (PictureBox)sender;
pi.Image = Properties.Resources.alert__2_;
}
Form1.Cs
private void pictureBox2_Click(object sender, EventArgs e)
{
Form1 c =new Form1();
c.pictureBox1_Click(sender, e);
}
Here pictureBox2_Click this event for all picturebox