I'm trying to draw a circle and a rectangle when the mouse is clicked so I got the x and y cords of the mouse click.
I've searched on the internet that in C# this can only be done with Margin, there is no origin or something like in java, you could give x and y to the constructor.
Now I'm trying to set this right but I can't figure out how to calculate this properly:
According to this:
http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.margin%28v=vs.95%29.aspx
rec.Margin = new Thickness(0, 0,0, 0);
Can someone help me? Or is it not possible with this?
Is this WPF or Windows Forms? WPF mouse event args have a GetPosition(UIElement) method which will tell you the mouse coordinates relative to the control you pass in. So if you're trying to draw a rectangle on a System.Windows.Controls.Canvas called MyCanvas you can use the Point returned by e.GetPosition(MyCanvas) to place your rectangle.
Here's an example:
void MyCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
Point ClickPoint = e.GetPosition(MyCanvas);
Rectangle Rectangle = new Rectangle();
System.Windows.Controls.Canvas.SetTop(Rectangle, ClickPoint.Y)
System.Windows.Controls.Canvas.SetLeft(Rectangle, ClickPoint.X)
MyCanvas.Children.Add(Rectangle);
}
void MyCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
Point ClickPoint = e.GetPosition(MyCanvas);
Rectangle Rectangle = new Rectangle();
System.Windows.Controls.Canvas.SetTop(Rectangle, ClickPoint.Y)
System.Windows.Controls.Canvas.SetLeft(Rectangle, ClickPoint.X)
MyCanvas.Children.Add(Rectangle);
}
Thanks to spencer.
Related
I'm trying to make a little graphics program that has a circle of diameter 100 on the screen and from the center of it, a line is coming out of it that is always attached to the mouse pointer until such time that the user does a click, and then the line is permanently drawn. It's exactly like MSPaint's line, except that starting point is always the center of the circle.
I tried a few things that DON'T work.
I can get the line to appear only after a mouse-click. That's not what I want. I want the line to always be present and pivoting from the circle-center until the mouse is clicked and then it's then permanently on the screen.
I can get a smeary thing where the line is always being drawn. It makes a sort of star shape, but that's not what I want either.
Basically, I want the same functionality that you have in MSPaint when you draw a line. What am I supposed to do? Draw the line and then erase it a second later, and then draw it again when the mouse is in a new position? I tried something like that, but it does a thing where it erases the background a little bit, and then the line is only drawn when the mouse is in motion, but not when the mouse is stationary.
If anyone can provide a code snippet, that'd be great. Or just some pseudo-code.
Is this the right pseudo code?
Start:
Left click and a line appears from center of circle to mouse tip
Line stays there until a new mouse coordinate is made (how do I keep track)?
Line from center of circle to original location gets erased
New line is made to new location of mouse coordinates.
I think this something of a state-machine to use what I learned in digital class. How are states implemented in C#?
Any help would be appreciated, and thanks to everyone that can understand my question even though I'm probably not using the proper terminology.
So short answer is you will need some custom painting. The longer answer involves custom drawing, and event handling.
The other piece of code you need is a list of some sort to hold all of the lines. The code below creates a user control and does the custom painting without relying on a state machine. To test it, create a new project add a user control called UserControl1, and add it to a form. Make sure you tie into the listed events.
I tried to comment the relevant sections and this shows a quick and dirty way to do what you appear to be trying to do.
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace CustomDrawingAndEvents
{
public partial class UserControl1 : UserControl
{
private struct MyLine
{
public Point mStart;
public Point mEnd;
public MyLine(Point xStart, Point xEnd)
{
mStart = xStart;
mEnd = xEnd;
}
}
private List<MyLine> mLines;
private Point mCircleCenter;
private Point mMousePosition;
public UserControl1()
{
InitializeComponent();
mLines = new List<MyLine>();
//Double Buffer to prevent flicker
DoubleBuffered = true;
//Create the center for our circle. For this just put it in the center of
//the control.
mCircleCenter = new Point(this.Width / 2, this.Height / 2);
}
private void UserControl1_MouseClick(object sender, MouseEventArgs e)
{
//User clicked create a new line to add to the list.
mLines.Add(new MyLine(mCircleCenter, e.Location));
}
private void UserControl1_MouseMove(object sender, MouseEventArgs e)
{
//Update mouse position
mMousePosition = e.Location;
//Make the control redraw itself
Invalidate();
}
private void UserControl1_Paint(object sender, PaintEventArgs e)
{
//Create the rect with 100 width/height (subtract half the diameter to center the rect over the circle)
Rectangle lCenterRect = new Rectangle(mCircleCenter.X - 50, mCircleCenter.Y - 50, 100, 100);
//Draw our circle in the center of the control with a diameter of 100
e.Graphics.DrawEllipse(new Pen(Brushes.Black), lCenterRect);
//Draw all of our saved lines
foreach (MyLine lLine in mLines)
e.Graphics.DrawLine(new Pen(Brushes.Red), lLine.mStart, lLine.mEnd);
//Draw our active line from the center of the circle to
//our mouse location
e.Graphics.DrawLine(new Pen(Brushes.Blue), mCircleCenter, mMousePosition);
}
}
}
void MainWindow_MouseMove(object sender, MouseEventArgs e)
{
Ellipse el = new Ellipse();
el.Fill = ellipse.Fill;
el.Width = ellipse.Width;
el.Height = ellipse.Height;
Point p = e.GetPosition(this.canvasPrint);
Canvas.SetLeft(el, p.X);
Canvas.SetTop(el, p.Y);
canvasPrint.Children.Add(el);
}
This is the sample code of the program that I made. I am adding ellipses on a canvas. The point of each ellipse is the point of the mouse cursor. When the mouse is moving, a new ellipse is generated and added so it works like a brush tool in MS Paint.
However, it consumes too much memory. So after a while, the program becomes slower. Is there any way to solve this problem? Can't I reuse the same ellipse object when I add it on the canvas?
You should use DrawingVisual and DrawingContext to draw your brush path. DrawingContext is similar to Windows Forms Graphics object. So in your situation, just draw your brush path on the same DrawingContext.
I am looking to draw an ellipse on the screen during the MouseMove() event but am wanting it to only draw the most recent ellipse from a start point to the current mouse position. At the moment it is drawing an ellipse for every mouse position that is getting registered. I would be able to draw it easily enough without showing the ellipse if i simply used the MouseDown() and MouseUp() events, but I am wanting the user to be able to see the ellipse as they move the mouse around, so they can know exactly where they are placing it. Does anyone know how I could achieve this?
My current code is as follows:
private void pnlDraw_MouseDown(object sender, MouseEventArgs e)
{
initialX = e.X;
initialY = e.Y;
previousX = e.X;
previousY = e.Y;
isPainting = true;
}
private void pnlDraw_MouseMove(object sender, MouseEventArgs e)
{
if (isPainting)
{
switch (currentDrawType)
{
case DRAWTYPE.ELLIPSE:
{
DrawEllipse(e);
break;
}
default:
{
break;
}
}
}
}
private void DrawEllipse(MouseEventArgs e)
{
pen = new Pen(Color.Black);
Graphics graphics = pnlDraw.CreateGraphics();
graphics.DrawEllipse(pen, initialX, initialY, e.X - initialX, e.Y - initialY);
previousX = e.X;
previousY = e.Y;
graphics.Dispose();
}
Any help would be greatly appreciated!
The first thing you should do when you are drawing something on screen is to clear what was previously displayed. Otherwise, you simply draw on top of existing drawing.
In WinForm, it's normally handled in the OnBackgroundPaint() method, which is a simple way of saying that it's there you should clear the background.
It should looks like this:
e.Graphics.FillRectangle(new SolidBrush(MyBackgroundColor), e.ClipRectangle);
or if it's not a drawing event:
graphics.FillRectangle(new SolidBrush(MyBackgroundColor), 0, 0, MyWidth, MyHeight);
And should be called before drawing anything on top of it.
It is also a guaranty that your drawing zone is ready to be drawn on it.
How can I clear the fill of a rectangle? I only want to keep the border.
g.FillRectangle(Brushes.Transparent, x, y, w, h);
Didn't work, neither did aRGB with alpha, I want to delete the fill so there's only the border left.
So what you want is
g.DrawRectangle(Pens.Black,x,y,w,h);
I think
EDIT: due to a change in the OP requirements this is not exactly the answer he wants, though it is not incorrect, therefore I choose to leave it here, for now.
you must set new clip for your graphics after set clip clear it, then restore clip to normal.
g.SetClip(new Rectangle(x,y,w,h), CombineMode.Replace);
g.Clear(Color.Transparent);
Ok so you are after a selection tool, you might have wanted to tell us that in the first place.
Create a new windows form application.
in the form events use mousedown, mouseup and mousemove
public Point MouseXY = new Point(0, 0);
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
MouseXY = e.Location;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
int width = e.Location.X - MouseXY.X;
int height = e.Location.Y-MouseXY.Y;
this.Refresh();
CreateGraphics().DrawRectangle(Pens.Blue, new Rectangle(MouseXY, new Size(width,height)));
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
this.Refresh();
}
This code is not perfect and I don't pretend it is. What this will do is draw a blue rectangle that starts where you click and follows your mouse. It does not draw a negative rectangle, you would have to determine whether your mouse is currently to the left or up from your starting point then draw the rectangle accordingly, but I think you can figure that out on your own. as well the rectangle is not persistent, though I do not believe you would want it to be.
I am creating a image viewer sort of application. I am on Windows and using .Net
In my app, I am trying to highlight a Particular area while dragging.
I have created a Rectangle.
Rectangle areaRect = new Rectangle(100,100, 300, 300);
Point ptOld = new Point(0, 0);
Pen rectPen = new Pen(Brushes.White, 3);
protected override void OnPaint(PaintEventArgs e)
{
Graphics dcPaint = e.Graphics;
dcPaint.DrawRectangle(rectPen, areaRect);
}
Now I am dragging this rectangular area along with my mouse movements.
protected override void OnMouseMove(MouseEventArgs e)
{
Point ptNew = new Point(e.X, e.Y);
int dx = ptNew.X - ptOld.X;
int dy = ptNew.Y - ptOld.Y;
areaRect.Offset(dx, dy);
MoveRect(ptNew);
ptOld = ptNew;
}
Here I am trying to move this rect along with my mouse
void MoveRect(Point point)
{
Graphics grfxClient = CreateGraphics();
Rectangle tempRectangle = new Rectangle(areaRect.Left, areaRect.Top, areaRect.Width, areaRect.Height);
grfxClient.DrawRectangle(rectPen, tempRectangle);
this.Invalidate();
grfxClient.Dispose();
}
My Code till this point is working fine.
Now I would like to darken the INVERSE drag Area (The area which is outside the drag region), I mean the area which is within this Rectangle should gets highlighted while dragging.
Any idea how to proceed.
Thanks.
-Pankaj
I suppose you can do it by creating a Region object that covers the outside of the rectangle and fill it with a semi-transparent SolidBrush to make it look darkened.
You also don't have to create a graphics and draw in OnMouseMove event, but just shift the rectangle and invalidate the surface of the control you are drawing on.
The code I used looks more or less like this:
Rectangle areaRect = new Rectangle(100,100, 300, 300);
Point ptOld = new Point(0, 0);
Pen rectPen = new Pen(Brushes.White, 3);
//A new field with a semi-transparent brush to paint the outside of the rectangle
Brush dimmingBrush = new SolidBrush(Color.FromArgb(128, 0, 0, 0));
protected override void OnPaint(PaintEventArgs e)
{
Region outsideRegion = new System.Drawing.Region(e.ClipRectangle);
outsideRegion.Exclude(areaRect);
Graphics dcPaint = e.Graphics;
dcPaint.FillRegion(dimmingBrush, outsideRegion);
dcPaint.DrawRectangle(rectPen, areaRect);
}
protected override void OnMouseMove(MouseEventArgs e)
{
Point ptNew = new Point(e.X, e.Y);
int dx = ptNew.X - ptOld.X;
int dy = ptNew.Y - ptOld.Y;
areaRect.Offset(dx, dy);
ptOld = ptNew;
this.Invalidate();
}
The method named MoveRect is not needed.
It now seems to work as you wanted it to.
Suggestions
I also have some suggestions. You don't have to use them, maybe they will be helpful for you.
You haven't written what kind of control you are using to draw on (or overriding Form methods and painting directly on it), but I suggest you to use a PictureBox control, create a custom control derived from it and override its events. This should make the painting process smooth and prevent flickering. To do it this way:
Create a new user control by selecting Add and User Control... and name a new control i.e. MyPictureBox
change the parent class of the control, so it should now contain the line:
public partial class MyPictureBox : PictureBox
open file MyPictureBox.Designer.cs and comment out these lines:
//this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
//this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
copy the code I posted in this answer and add line base.OnPaint(e); and the beginning of OnPaint method
compile the project
now you should be able to open designer of your main form, drag MyPictureBox control from the toolbox and use it without additional code needed
You also might consider changing the behaviour of the highlighted area, so mouse cursor was in the center of it. I suppose it would be more intuitive to the user.
If you have any issues with the code, just write it in the comments and I'll try to help :).