This question already has answers here:
Can I use Graphics object in any other event than Paint event?
(4 answers)
Closed 2 years ago.
I want to draw an circle from a method in another Class. But it says invalid parameters on line 41 and 42 in my class. When im done whith this project it should be an analog clock. and this is my first Project im unsing the drawing Event.Im undersatnding a shit and dont know how to fix my Problem. Im new in Forms. I allready tried to draw the circle in the main and it works fine but however it didnt work putting into a class. Im sorry for my classnames they might seem strange because im german. Thanks for your help.
Thats my class:
class Ziffernblatt
{
Size RectSize;
Point RectPoint = new Point(5, 10);
Rectangle Myrect;
Rectangle MyCircle;
Pen MyPen = new Pen(Color.Black, 1);
Pen Invpen = new Pen(Color.White, 1);
Graphics gObject;
public Ziffernblatt(Graphics NgObject)
{
gObject = NgObject;
}
public void Draw(int PosX, int PosY)
{
RectSize.Width = PosX / 2;
RectSize.Height = PosY / 2;
RectPoint.X = PosX / 2 - RectSize.Width / 2;
RectPoint.Y = PosY / 2 - RectSize.Height / 2;
Myrect = new Rectangle(RectPoint, RectSize);
MyCircle = new Rectangle(RectPoint, RectSize);
gObject.DrawRectangle(Pens.Red, Myrect);
gObject.DrawEllipse(Pens.Black, MyCircle);
}
and this is my main:
public partial class Form1 : Form
{
Ziffernblatt[] Ziffern = new Ziffernblatt[1];
Graphics gObject;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
gObject = e.Graphics;
Ziffern[0] = new Ziffernblatt(gObject);
}
private void Form1_SizeChanged(object sender, EventArgs e)
{
Ziffern[0].Draw(this.ClientSize.Width, this.ClientSize.Height);
Invalidate();
}
}
You received this error because of you encapsulated the Graphics object to you class. Just call your draw method from the paint event.
The best practice when drawing is performed from the paint method of the Form1. Take to account that the Graphics object will be changed for each paint event.
Your code might look like this:
public partial class Form1 : Form
{
Ziffernblatt[] Ziffern = new Ziffernblatt[1];
public Form1()
{
InitializeComponent();
Ziffern[0] = new Ziffernblatt();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Ziffern[0].Draw(e.Graphics, this.ClientSize.Width, this.ClientSize.Height);
}
private void Form1_SizeChanged(object sender, EventArgs e)
{
//Ziffern[0].Draw(this.ClientSize.Width, this.ClientSize.Height);
Invalidate();
}
}
public class Ziffernblatt
{
Size RectSize;
Point RectPoint = new Point(5, 10);
Rectangle Myrect;
Rectangle MyCircle;
Pen MyPen = new Pen(Color.Black, 1);
Pen Invpen = new Pen(Color.White, 1);
public Ziffernblatt() //Graphics NgObject)
{
//gObject = NgObject;
}
public void Draw(Graphics g, int PosX, int PosY)
{
RectSize.Width = PosX / 2;
RectSize.Height = PosY / 2;
RectPoint.X = PosX / 2 - RectSize.Width / 2;
RectPoint.Y = PosY / 2 - RectSize.Height / 2;
Myrect = new Rectangle(RectPoint, RectSize);
MyCircle = new Rectangle(RectPoint, RectSize);
g.DrawRectangle(Pens.Red, Myrect);
g.DrawEllipse(Pens.Black, MyCircle);
}
}
For additional information about the paint event see Control.Paint
Event
Related
Before starting a project, I want to know beforehand whether the following would work.
The application creates a System.Drawing.Bitmap and paints on it.
The Bitmap is much larger than the PictureBox. The Height of the Bitmap and the PictureBox are the same. Now I would like to be able to move the Image from left to right within (along) the PictureBox by pressing the left mouse button and moving it.
See the drawing:
I just realized that I haven't answered yet, which I am trying to make up for.
As a solution, I use Jimi's solution. I've shortened the code here to meet my needs.
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Windows.Forms;
namespace Zoom_an_image_from_the_mouse_location
{
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
string imagePath = "C:\\Users\\yourPath\\Pictures\\....jpeg";
drawingImage = (Bitmap)Image.FromStream(new MemoryStream(File.ReadAllBytes(imagePath)));
imageRect = new RectangleF(Point.Empty, drawingImage.Size);
canvas = new PictureBoxEx(new Size(525,700));
canvas.Location = new Point(10, 10);
canvas.MouseMove += this.canvas_MouseMove;
canvas.MouseDown += this.canvas_MouseDown;
canvas.MouseUp += this.canvas_MouseUp;
canvas.Paint += this.canvas_Paint;
this.Controls.Add(canvas);
}
private void FormMain_Load(object sender, EventArgs e)
{
this.BackColor = Color.FromArgb(174, 184, 177);
}
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
}
private float rotationAngle = 0.0f;
private float zoomFactor = 1.0f;
private RectangleF imageRect = RectangleF.Empty;
private PointF imageLocation = PointF.Empty;
private PointF mouseLocation = PointF.Empty;
private Bitmap drawingImage = null;
private PictureBoxEx canvas = null;
private void canvas_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
mouseLocation = e.Location;
imageLocation = imageRect.Location;
canvas.Cursor = Cursors.NoMove2D;
}
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
imageRect.Location =
new PointF(imageLocation.X + (e.Location.X - mouseLocation.X),
imageLocation.Y); //+ (e.Location.Y - mouseLocation.Y));
canvas.Invalidate();
}
private void canvas_MouseUp(object sender, MouseEventArgs e) =>
canvas.Cursor = Cursors.Default;
private void canvas_Paint(object sender, PaintEventArgs e)
{
var drawingRect = GetDrawingImageRect(imageRect);
using (var mxRotation = new Matrix())
using (var mxTransform = new Matrix())
{
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
mxRotation.RotateAt(rotationAngle, GetDrawingImageCenterPoint(drawingRect));
mxTransform.Multiply(mxRotation);
e.Graphics.Transform = mxTransform;
e.Graphics.DrawImage(drawingImage, drawingRect);
}
}
#region Drawing Methods
public RectangleF GetScaledRect(RectangleF rect, float scaleFactor) =>
new RectangleF(rect.Location,
new SizeF(rect.Width * scaleFactor, rect.Height * scaleFactor));
public RectangleF GetDrawingImageRect(RectangleF rect) =>
GetScaledRect(rect, zoomFactor);
public PointF GetDrawingImageCenterPoint(RectangleF rect) =>
new PointF(rect.X + rect.Width / 2f, rect.Y + rect.Height / 2f);
#endregion
}
}
[DesignerCategory("Code")]
public class PictureBoxEx : PictureBox
{
public PictureBoxEx() : this(new Size(525, 700)) { }
public PictureBoxEx(Size size)
{
SetStyle(ControlStyles.Selectable | ControlStyles.UserMouse, true);
this.BorderStyle = BorderStyle.FixedSingle;
this.Size = size;
}
}
I want to click on points that I drew.
It would be also cool if a window would popup and I could do something with that. But the general thing i want to do is clicking on a drawn point. I want to make it work, that i can click on the map on points that I drew.
Example image:
public partial class Form1 : Form
{
Graphics g;
Pen p;
Point cursor;
int k = 0;
Point[] points = new Point[50];
public Form1()
{
InitializeComponent();
g = pbxkarte.CreateGraphics();
p = new Pen(Color.DeepSkyBlue, 3);
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Pbxkarte_Click(object sender, EventArgs e)
{
if (drawmodecbx.Checked == true)
{
g.DrawEllipse(p, cursor.X - 10, cursor.Y - 10, 20, 20);
points[k++] = new Point(cursor.X, cursor.Y);
lbxDrawnPoints.Items.Add("X:" + cursor.X + "Y:" + cursor.Y);
}
}
private void Pbxkarte_MouseMove(object sender, MouseEventArgs e)
{
cursor = this.PointToClient(Cursor.Position);
xydisplay.Text = "X:" + cursor.X + "Y:" + cursor.Y;
}
}
}
Example code:
Two class level variables and a helper function:
List<Point> dots = new List<Point>();
int dotSize = 12;
Rectangle fromPoint(Point pt, int size)
{
return new Rectangle(pt.X - size/ 2, pt.Y - size / 2, size, size);
}
The mouseclick (as opposed to the click event) contains the location:
private void Pbxkarte_MouseClick(object sender, MouseEventArgs e)
{
if (!dots.Contains(e.Location))
{
dots.Add(e.Location);
Pbxkarte.Invalidate(); // show the dots
}
}
You could add code to remove dots or change the properties, esp. if you create a dot class. - If you want to avoid overlapping dots you can to use code like the one in the mousemove to detect this. But. Don't repeat the code! Instead factor out a boolOrPoint IsDotAt(Point) function you can use both times!!
In the mousemove I only show the hit state. You do your thing..
private void Pbxkarte_MouseMove(object sender, MouseEventArgs e)
{
bool hit = false;
foreach (var dot in dots)
{
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddEllipse(fromPoint(dot, dotSize));
if (gp.IsVisible(e.Location))
{
hit = true; break;
}
}
}
Cursor = hit ? Cursors.Hand : Cursors.Default;
}
All dot in the list must get shown every time anything changes, both in the list or in the system.:
private void Pbxkarte_Paint(object sender, PaintEventArgs e)
{
foreach (var dot in dots)
{
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddEllipse(fromPoint(dot, dotSize));
e.Graphics.FillPath(Brushes.Red, gp);
}
}
}
If you want more properties, like texts or colors do create a class dot and use a List<dot> !
I need to draw random shapes with a random color and random position.
Now i figured out how to use a paint event but it only seems to work when I initialize then Pen within the paint event
private void ShapesPanel_Paint(object sender, PaintEventArgs e)
{
_graphics = ShapesPanel.CreateGraphics();
_pen = new Pen(Color.Black, 1);
}
This works, but I want the random colors and every shape has it own generated random color.
I have this foreach which works:
foreach (var shape in _shapes)
{
shape.DrawAble(_graphics);
}
Now I want to have the drawing to have to shapes color:
foreach (var shape in _shapes)
{
_pen = new Pen(shape.Color, 3);
shape.DrawAble(_graphics);
}
And this will give no drawings at all.
Someone familiar?
Thanks
form class
public partial class ShapesForm : Form
{
private Shape _shape;
private Graphics _graphics;
private Pen _pen;
private Random _random;
private int _red, _blue, _green;
private Color _color;
private int _x, _y;
private Point _point;
private int _randomShape;
private double _size;
private double _radius;
private List<Shape> _shapes;
public ShapesForm()
{
InitializeComponent();
_shapes = new List<Shape>();
_random = new Random();
}
private void ShapesPanel_Paint(object sender, PaintEventArgs e)
{
_graphics = ShapesPanel.CreateGraphics();
_pen = new Pen(Color.Black, 1);
}
private void AddShapeButton_Click(object sender, EventArgs e)
{
_red = _random.Next(0, 255);
_green = _random.Next(0, 255);
_blue = _random.Next(0, 255);
_color = Color.FromArgb(1, _red, _green, _blue);
_x = _random.Next(0, 100);
_y = _random.Next(0, 100);
_point = new Point(_x, _y);
_radius = _random.Next(0, 20);
_size = _random.Next(0, 20);
_randomShape = _random.Next(0, 2);
switch(_randomShape)
{
case 0:
_shape = new Circle(_point, _color, _radius);
_shapes.Add(_shape);
UpdateShapeListBox();
DrawShapes();
break;
case 1:
_shape = new Square(_point, _color, _size);
_shapes.Add(_shape);
UpdateShapeListBox();
DrawShapes();
break;
}
}
public void UpdateShapeListBox()
{
ShapesListBox.Items.Clear();
foreach (var shape in _shapes)
{
ShapesListBox.Items.Add(shape.ToString());
}
}
public void DrawShapes()
{
ShapesPanel.Refresh();
foreach (var shape in _shapes)
{
_pen = new Pen(shape.Color, 3);
shape.DrawAble(_graphics);
}
}
}
This is the sort of logic you want to implement:
private void ShapesPanel_Paint(object sender, PaintEventArgs e)
{
foreach (var shape in _shapes)
{
shape.DrawAble(e.Graphics);
}
}
// in the Shape class
public void DrawAble(Graphics g)
{
var pen = new Pen(this.Color, 3);
g.DrawRect( ... ); // or whatever
}
You should use e.Graphics from the paint handler, and only while the paint handler is running.
The paint handler will normally be called whenever necessary. If you want to repaint because your shapes have changed, call ShapesPanel.Invalidate().
You need to do all of your drawing in the Paint handler only, using e.Graphics.
If you want to draw something, call Invalidate() to raise a Paint event, then make sure your Paint handler will draw everything you want.
I am a beginner at this so cut me a little slack please. I am trying to draw a dot on the form window at the location where the mouse is clicked. I keep getting a Null Exception at g.FillEllipse is called. What am I missing or doing wrong?
namespace ConvexHullScan
{
public partial class convexHullForm : Form
{
Graphics g;
//Brush blue = new SolidBrush(Color.Blue);
Pen bluePen = new Pen(Color.Blue, 10);
Pen redPen = new Pen(Color.Red);
public convexHullForm()
{
InitializeComponent();
}
private void mainForm_Load(object sender, EventArgs e)
{
Graphics g = this.CreateGraphics();
}
private void convexHullForm_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
int x, y;
Brush blue = new SolidBrush(Color.Blue);
x = e.X;
y = e.Y;
**g.FillEllipse(blue, x, y, 20, 20);**
}
}
}
}
Replace Graphics g = this.CreateGraphics(); with just g = this.CreateGraphics(); because otherwise you are defining a new variable that lives only inside the scope of the mainForm_Load function rather than assigning a value to the variable defined at the higher-level scope of convexHullForm
It's not clear what your end goal is, but those dots drawn with CreateGraphics() will only be temporary. They will get erased when the form repaints itself, such as when you minimize and restore, or if another window obscures yours. To make them "persistent", use the supplied e.Graphics in the Paint() Event of the Form:
public partial class convexHullForm : Form
{
private List<Point> Points = new List<Point>();
public convexHullForm()
{
InitializeComponent();
this.Paint += new PaintEventHandler(convexHullForm_Paint);
this.MouseDown += new MouseEventHandler(convexHullForm_MouseDown);
}
private void convexHullForm_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
Points.Add(new Point(e.X, e.Y));
this.Refresh();
}
}
void convexHullForm_Paint(object sender, PaintEventArgs e)
{
foreach (Point pt in Points)
{
e.Graphics.FillEllipse(Brushes.Blue, pt.X, pt.Y, 20, 20);
}
}
}
I'm trying to draw a single line using OnMouseMove() event. My Problem is that everytime I move the mouse It leaves a trail. I tried to use the refresh method, but when I stop moving the mouse the line is gone. I don't want the line to be drawn OnPaint();, Just want to draw it OnMouseMove().
EDIT: I'm using a transparent panel(cp.ExStyle |= 0x20;), so I cant use the graphics.Clear() and BackColor()
Here's a Sample Image without the Refresh():
Here's my code:
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
Graphics g = panel1.CreateGraphics();
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
using (var p = new Pen(Color.Black, 3))
{
p.StartCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
p.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
g.DrawLine(p, st, e.Location);
}
Thread.Sleep(30);
Invalidate();
//this.Refresh();
g.Dispose();
}
Regards
The following works for me. Basically keep track of the last line drawn and draw over it with the background color of the panel (gives the effect of clearing it).
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private const int PEN_WIDTH = 3;
private const LineCap START_CAP = LineCap.ArrowAnchor;
private const LineCap END_CAP = LineCap.ArrowAnchor;
Point mAnchorPoint = new Point(10, 10);
Point mPreviousPoint = Point.Empty;
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
using (Graphics g = panel1.CreateGraphics())
{
// Clear last line drawn
using (Pen clear_pen = new Pen(panel1.BackColor, PEN_WIDTH))
{
clear_pen.StartCap = START_CAP;
clear_pen.EndCap = END_CAP;
g.DrawLine(clear_pen, mAnchorPoint, mPreviousPoint);
}
// Update previous point
mPreviousPoint = e.Location;
// Draw the new line
using (Pen draw_pen = new Pen(Color.Black, PEN_WIDTH))
{
draw_pen.StartCap = START_CAP;
draw_pen.EndCap = END_CAP;
g.DrawLine(draw_pen, mAnchorPoint, e.Location);
}
}
}
}
If you panel's background color is set to Transparent, you will need to change panel1.BackColor to panel1.Parent.BackColor
If the Transparent Panel is not working, you could use the DrawReversibleLine function (although this doesn't allow the color or thickness of the line to be changed, it should have no issues with drawing/erasing even if the panel is Transparent:
Point mAnchorPoint = new Point(200, 200);
Point mPreviousPoint = Point.Empty;
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (mPreviousPoint != Point.Empty)
{
// Clear last line drawn
ControlPaint.DrawReversibleLine(PointToScreen(mAnchorPoint), PointToScreen(mPreviousPoint), Color.Pink);
}
// Update previous point
mPreviousPoint = e.Location;
mPreviousPoint.Offset(myPanel1.Location);
// Draw the new line
ControlPaint.DrawReversibleLine(PointToScreen(mAnchorPoint), PointToScreen(mPreviousPoint), Color.Pink);
}
Another simple way to draw a line with mouse in C#:
public partial class Form1 : Form
{
Options_c o = new Options_c();
public Form1()
{
InitializeComponent();
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
o.Allow = false;
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
o.Allow = true;
o.X = e.X;
o.Y = e.Y;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (o.Allow == true)
{
Graphics g = pictureBox1.CreateGraphics();
Pen p1 = new Pen(o.color, 5);
g.DrawLine(p1, o.X,o.Y, e.X, e.Y);
o.X = e.X;
o.Y = e.Y;
}
}
}
class Options_c
{
public Boolean Allow = false;
public Int32 X;
public Int32 Y;
public Color color = Color.Bisque;
}
After
g.DrawLine(p, st, e.Location);
put:
st = e.Location;
Does that fix the problem?
The problem with the line disappearing is that when the panel is repainted, the line is not redrawn. What you really need is to update the end-point of the line-segment when the mouse is moved across the panel and to invalidate the panel. Of course, this will mean that you do handle the Paint event on the panel.
Code here, without the event-handler registration:
Point endPoint;
private void panel1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
using (var p = new Pen(Color.Black, 3))
{
p.StartCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
p.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
g.DrawLine(p, st, endPoint);
}
Thread.Sleep(30);
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
endPoint = e.Location;
panel1.Invalidate();
}
OKaie, i got it! If you have to draw a line between two geopoint
location on tocuhing these two location, then u have to use the
overlay class in this shape... MY CODE IS :
in Main activity write this code also:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mapView = (MapView) findViewById(R.id.mapView1);
mapView.setBuiltInZoomControls(true);
mapOverlays = mapView.getOverlays();//it get the mapview all overlays...
mc = mapView.getController();
mc.setZoom(13);
GeoPoint p = new GeoPoint(34159000,73220000);//starting point Abbottabad
GeoPoint p1 = new GeoPoint(41159000,43220000);//starting point Abbottabad
List<Overlay> mapOverlays2 ;
mapOverlays2 = mapView.getOverlays();
projection = mapView.getProjection();
myoverlay = new MarkerOverlay(p,p1);
mapOverlays2.add(myoverlay);//*/
}
class MarkerOverlay extends Overlay
{
GeoPoint p,p1;
private GeoPoint pa;
public MarkerOverlay(GeoPoint p,GeoPoint p1)
{
this.p = p;
this.p1=p1;
Toast.makeText(GoogleMapShowActivity.this, "point value is "+p +"-->"+p1, Toast.LENGTH_LONG).show();
}
public void draw(Canvas canvas, MapView mapView,boolean shadow)//), long when)
{
super.draw(canvas, mapView, shadow);
Paint mPaint = new Paint();
mPaint.setDither(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(4);
GeoPoint gP1 = new GeoPoint(p.getLatitudeE6(),p.getLongitudeE6());//starting point Abbottabad
GeoPoint gP2 = new GeoPoint(p1.getLatitudeE6(),p1.getLongitudeE6());//(33695043,73050000);//End point Islamabad
Point p1 = new Point();
Point p2 = new Point();
Path path1 = new Path();
projection.toPixels(gP1, p1); //changing the latitude into the screen pixels.
projection.toPixels(gP2, p2);
path1.moveTo(p1.x, p1.y);//Moving to Abbottabad location
path1.lineTo(p2.x,p2.y);//Path till Islamabad
canvas.drawPath(path1, mPaint);//Actually drawing the path from Abbottabad to Islamabad
}
//--------------------------//
public boolean onTouchEvent(MotionEvent event, MapView mapView)
{
location_touch++;//this is called two times before executing other codes in thsi method(),
// Toast.makeText(GoogleMapShowActivity.this, "this is mmmm"+location_touch, Toast.LENGTH_LONG).show();
if (event.getAction() == 1)
{
// Toast.makeText(GoogleMapShowActivity.this, "this is me ..."+location_touch, Toast.LENGTH_LONG).show();
GeoPoint p = mapView.getProjection().fromPixels((int) event.getX(), (int) event.getY());
if((location_touch%2)!=0)
{
location_touch=0;
Toast.makeText(GoogleMapShowActivity.this, "VALUE 2..."+location_touch+"gp is "+p+",,"+p1, Toast.LENGTH_LONG).show();
mapView.getOverlays().add(new MarkerOverlay(p,pa));
mapView.invalidate();
}
else //if((location_touch==0 ))
{
pa=p;
Toast.makeText(GoogleMapShowActivity.this, "VALUE 1.."+location_touch+",,,"+p1, Toast.LENGTH_LONG).show();
location_touch++;
}