**i draw ellipse at runtime using following code.in that code i used graphics path for drawing(actually this is project requirement )and used widen method for graphics path.
but it gives runtime exception "out of memory".can i use this method in the case of ellipse?
while using widen method in the case of drawing rectangle at runtime, its working properly.
please solve this problem and give me some suggestion?**
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
Rectangle r;
bool isDown = false;
int initialX;
int initialY;
bool IsDrowing =true;
GraphicsPath gp1;
GraphicsPath gp2;
GraphicsPath gp3;
GraphicsPath gp;
Graphics g;
bool contained;
bool containedE;
bool containedC;
private void Form2_MouseDown(object sender, MouseEventArgs e)
{
isDown = true;
IsDrowing = true;
initialX = e.X;
initialY = e.Y;
}
private void Form2_MouseMove(object sender, MouseEventArgs e)
{
//IsDrowing = true;
if (isDown == true)
{
int width = e.X - initialX, height = e.Y - initialY;
r = new Rectangle(Math.Min(e.X, initialX),
Math.Min(e.Y, initialY),
Math.Abs(e.X - initialX),
Math.Abs(e.Y - initialY));
this.Invalidate();
}
}
private void Form2_Paint(object sender, PaintEventArgs e)
{
g = this.CreateGraphics();
gp = new GraphicsPath();
Pen pen = new Pen(Color.Red);
gp.AddEllipse(r);
gp.Widen(pen);
pen.DashStyle = DashStyle.Dash;
if (IsDrowing)
{
g.DrawPath(pen, gp);
}
private void Form2_MouseUp(object sender, MouseEventArgs e)
{
IsDrowing = false;
this.Refresh();
}
}
Basically: Avoid the GraphicsPath.Widen Method. It's buggy, search for "spirograph bug"
In your case this manifests because you try to widen a 0 by 0 rectangle. Modify your code like this:
private void Form2_Paint(object sender, PaintEventArgs e)
{
if (IsDrowing)
{
g = e.Graphics;
gp = new GraphicsPath();
gp.AddEllipse(r);
gp.Widen(new Pen(Color.Red, 10));
Pen pen = new Pen(Color.Red, 1);
pen.DashStyle = DashStyle.Dash;
g.DrawPath(pen, gp);
}
}
It may need additional work, but avoid the widening of an empty rectangle/ellipse.
Related
My problem is:
When I try to save the graphics object to a bitmap image it does not save correctly, instead the image is black in color and there is nothing else in the file.
I've seen other answers, but I think it's different when you draw multiple times in the graphics object.
So, here's my attempt, please let me know where my issue is.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace PenFlip
{
public partial class Match : Form
{
Graphics g;
private int x = -1;
private int y = -1;
private bool moving;
private Pen pen;
private Bitmap testBmp;
public Match()
{
InitializeComponent();
g = panel1.CreateGraphics();
g.SmoothingMode = SmoothingMode.AntiAlias;
pen = new Pen(Color.Black, 5);
pen.StartCap = pen.EndCap = LineCap.Round;
}
private void pictureBox1_Click(object sender, EventArgs e)
{
PictureBox pictureBox = (PictureBox) sender;
pen.Color = pictureBox.BackColor;
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
moving = true;
x = e.X;
y = e.Y;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (moving && x != -1 && y != -1)
{
g.DrawLine(pen, new Point(x, y), e.Location);
x = e.X;
y = e.Y;
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
moving = false;
x = -1;
y = -1;
g.Save();
}
private void button1_Click(object sender, EventArgs e)
{
// prints out the black image
testBmp = new Bitmap(400, 200, g);
testBmp.Save(#"test.bmp", ImageFormat.Bmp);
}
}
}
Uh, usage of Bitmap is tricky and has a lot of pitfalls (that's why it's use is deprecated, btw). Try to create the Graphics object from an in-memory bitmap, instead of grabbing it from a control. The bitmap should be the primary object, not the Graphics instance. You don't know what the control does to your bitmap.
So in the constructor, do something like:
public Match()
{
InitializeComponent();
bitmap = new Bitmap(panel1.Width, panel1.Height, PixelFormat.Format32bppArgb);
pen = new Pen(Color.Black, 5);
pen.StartCap = pen.EndCap = LineCap.Round;
}
and in each function, create a graphics object from the bitmap:
using (var graphics = Graphics.FromImage(image))
{
graphics.Draw(...);
}
You need to update the panel manually now, e.g. by attaching to it's OnPaint event.
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
I am working on a project where I should draw a line between two picture box.
Please note that I know how to get the coordinates of each picture box, but I don't know what method to use to draw a line between them.
Here is my code so far:
Point p1, p2;
public Form1()
{
InitializeComponent();
int x = pictureBox1.Location.X;
MessageBox.Show(x.ToString());
p1.X = pictureBox1.Location.X;
p1.Y = pictureBox1.Location.Y;
p2.X = pictureBox2.Location.X;
p2.Y = pictureBox2.Location.Y;
}
Appreciate any help!
Hope this will help you
pointArray[iNumberofClicks].X = e.X;
pointArray[iNumberofClicks].Y = e.Y;
Pen PenSpikes = new Pen(Color.Green);
SolidBrush solidBrush = new SolidBrush(Color.Blue);
iNumberofClicks++;
if (iNumberofClicks > 1)
{
Point[] CurrentpointArray = new Point[iNumberofClicks];
for (int i = 0; i < iNumberofClicks; i++)
{
CurrentpointArray[i].X = pointArray[i].X;
CurrentpointArray[i].Y = pointArray[i].Y;
}
Bitmap canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics offScreenDC = Graphics.FromImage(canvas);
// New line!
offScreenDC.DrawImage(pictureBox1.Image, new Point());
offScreenDC.DrawLines(PenSpikes, CurrentpointArray);
pictureBox1.Image = canvas;
offScreenDC.Dispose();
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
points.Add(e.Location);
pictureBox1.Invalidate();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{enter code here
if (points.Count > 1)
e.Graphics.DrawLines(Pens.Black, points.ToArray());
}
Lately I found out how to rotate images and I already have problem.
Here is piece of code that I have problem with but you probably don't need to look at it anyway...
Graphics g = e.Graphics;
g.TranslateTransform((float)Width / 2, (float)Height / 2);
g.RotateTransform(myAngle);
Brush brush = new SolidBrush(Color.FromArgb(32, 1, 1, 1));
Pen pen = new Pen(Color.FromArgb(255, 128 , 128, 128), 3);
g.FillRectangle(brush, nX, nY, snX - nX, snY - nY);
g.DrawRectangle(pen, nX, nY, snX - nX, snY - nY);
variables X , sX , snX, Y , sY, snY are coordinates of mouse in specific moments and are calculated mostly in Form1_MouseMove and I can't show what's in there.
How can I make these variables also change no matter what myAngle is?
I've made an example, how to draw on a rotated bitmap: (using a picturebox/bitmap/trackbar)
public partial class Form1 : Form
{
private Bitmap _bitmap;
public Form1()
{
InitializeComponent();
_bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
}
private void TransformGraphics(Graphics g)
{
g.ResetTransform();
g.TranslateTransform(_bitmap.Width / 2, _bitmap.Height / 2);
g.RotateTransform(trackBar1.Value);
g.TranslateTransform(-_bitmap.Width / 2, -_bitmap.Height / 2);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
TransformGraphics(e.Graphics);
e.Graphics.DrawImage(_bitmap, new Point());
}
private Point? _previousPoint;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
_previousPoint = e.Location;
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
_previousPoint = null;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (_previousPoint.HasValue)
{
using (Graphics g = Graphics.FromImage(_bitmap))
{
TransformGraphics(g);
var matrix = g.Transform;
matrix.Invert();
var points = new[] { _previousPoint.Value, e.Location };
matrix.TransformPoints(points);
g.ResetTransform();
g.DrawLine(Pens.Black, points[0], points[1]);
pictureBox1.Invalidate();
_previousPoint = e.Location;
}
}
}
private void trackBar1_ValueChanged(object sender, EventArgs e)
{
pictureBox1.Invalidate();
}
}
You can add another trackbar for scaling.
I' ve drawn roundRectangle using Graphics Path OnPaintEvent
and I already added mouseevent to know if cursor was over the g.p .
void Round_MouseMove(object sender, MouseEventArgs e)
{
Point mousePt = new Point(e.X, e.Y);
if (_path != null)
if (_path.IsVisible(e.Location))
MessageBox.Show("GraphicsPath has been hovered!");
}
Question: is there a way to resize or redraw(hide previous then draw new) a graphicsPath runtime?
Invoke Invalidate for redrawn the Form, so the OnPaint(PaintEventArgs e) will be executed.
Check the following example:
public sealed partial class GraphicsPathForm : Form
{
private bool _graphicsPathIsVisible;
private readonly Pen _pen = new Pen(Color.Red, 2);
private readonly Brush _brush = new SolidBrush(Color.FromArgb(249, 214, 214));
private readonly GraphicsPath _graphicsPath = new GraphicsPath();
private Rectangle _rectangle = new Rectangle(10, 30, 100, 100);
public GraphicsPathForm()
{
InitializeComponent();
_graphicsPath.AddRectangle(_rectangle);
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.Bilinear;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.DrawPath(_pen, _graphicsPath);
if (_graphicsPathIsVisible)
g.FillPath(_brush, _graphicsPath);
base.OnPaint(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
var isVisible = _graphicsPath.IsVisible(e.Location);
if (isVisible == _graphicsPathIsVisible)
return;
const int zoom = 5;
if (isVisible)
{
if (!_graphicsPathIsVisible)
{
_rectangle.Inflate(zoom, zoom);
_graphicsPath.Reset();
_graphicsPath.AddRectangle(_rectangle);
}
}
else
{
if (_graphicsPathIsVisible)
{
_rectangle.Inflate(-zoom, -zoom);
_graphicsPath.Reset();
_graphicsPath.AddRectangle(_rectangle);
}
}
_graphicsPathIsVisible = isVisible;
Invalidate();
base.OnMouseMove(e);
}
}
I hope it helps.