I'm using the answer from another StackOverflow thread here.
My situation is very similar, expect I'm drawing my Lines inside a PictureBox. I modified the above answer by adding a PictureBox to the constructor. I can see that the lines are drawn in my PictureBox, but it won't move.
Am I missing something really obvious here? I've tried a lot of different things, but nothing is working.
LineMover.cs
public class LineMover : Form
{
public LineMover(PictureBox pb)
{
this.DoubleBuffered = true;
pb.Paint += new PaintEventHandler(LineMover_Paint);
pb.MouseMove += new MouseEventHandler(LineMover_MouseMove);
pb.MouseDown += new MouseEventHandler(LineMover_MouseDown);
pb.MouseUp += new MouseEventHandler(LineMover_MouseUp);
this.Lines = new List<GraphLine>()
{
new GraphLine (10, 10, 100, 200),
new GraphLine (10, 150, 120, 40),
};
}
void LineMover_MouseUp(object sender, MouseEventArgs e)
{
if (Moving != null)
{
this.Capture = false;
Moving = null;
}
RefreshLineSelection(e.Location);
}
void LineMover_MouseDown(object sender, MouseEventArgs e)
{
RefreshLineSelection(e.Location);
if (this.SelectedLine != null && Moving == null)
{
this.Capture = true;
Moving = new MoveInfo
{
Line = this.SelectedLine,
StartLinePoint = SelectedLine.StartPoint,
EndLinePoint = SelectedLine.EndPoint,
StartMoveMousePoint = e.Location
};
}
RefreshLineSelection(e.Location);
}
void LineMover_Paint(object sender, PaintEventArgs e)
{
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
foreach (var line in Lines)
{
var color = line == SelectedLine ? Color.Red : Color.Black;
var pen = new Pen(color, 2);
e.Graphics.DrawLine(pen, line.StartPoint, line.EndPoint);
}
}
void LineMover_MouseMove(object sender, MouseEventArgs e)
{
if (Moving != null)
{
Moving.Line.StartPoint = new PointF(Moving.StartLinePoint.X + e.X - Moving.StartMoveMousePoint.X, Moving.StartLinePoint.Y + e.Y - Moving.StartMoveMousePoint.Y);
Moving.Line.EndPoint = new PointF(Moving.EndLinePoint.X + e.X - Moving.StartMoveMousePoint.X, Moving.EndLinePoint.Y + e.Y - Moving.StartMoveMousePoint.Y);
}
RefreshLineSelection(e.Location);
}
private void RefreshLineSelection(Point point)
{
var selectedLine = FindLineByPoint(Lines, point);
if (selectedLine != this.SelectedLine)
{
this.SelectedLine = selectedLine;
this.Invalidate();
}
if (Moving != null)
this.Invalidate();
this.Cursor =
Moving != null ? Cursors.Hand :
SelectedLine != null ? Cursors.SizeAll :
Cursors.Default;
}
public List<GraphLine> Lines = new List<GraphLine>();
GraphLine SelectedLine = null;
MoveInfo Moving = null;
static GraphLine FindLineByPoint(List<GraphLine> lines, Point p)
{
var size = 10;
var buffer = new Bitmap(size * 2, size * 2);
foreach (var line in lines)
{
//draw each line on small region around current point p and check pixel in point p
using (var g = Graphics.FromImage(buffer))
{
g.Clear(Color.Black);
g.DrawLine(new Pen(Color.Green, 3), line.StartPoint.X - p.X + size, line.StartPoint.Y - p.Y + size, line.EndPoint.X - p.X + size, line.EndPoint.Y - p.Y + size);
}
if (buffer.GetPixel(size, size).ToArgb() != Color.Black.ToArgb())
return line;
}
return null;
}
//public static void Main()
//{
// Application.Run(new LineMover());
//}
}
public class MoveInfo
{
public GraphLine Line;
public PointF StartLinePoint;
public PointF EndLinePoint;
public Point StartMoveMousePoint;
}
public class GraphLine
{
public GraphLine(float x1, float y1, float x2, float y2)
{
this.StartPoint = new PointF(x1, y1);
this.EndPoint = new PointF(x2, y2);
}
public PointF StartPoint;
public PointF EndPoint;
}
And my Form1.cs
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
LineMover myLineMover = new LineMover(pictureBox1);
}
}
Related
I am currently working on a topdown game made in windows forms. In the game, your character rotates after your mouse and you can shoot a shot from your character in the direction of your mouse. To create multiple areas in the game, I chose to use groupboxes as separate areas in the game that you can switch between using buttons but I've run in to a problem. I can no longer rotate or move my character or even shoot within the groupboxes.
I've tried setting breakpoints and discovered that the keyup, keydown and mousemove methods are not being called but I don't know why. For some reason I get an error when i release space in the btnSave_Click method which i marked in the code.
static Image originalImage;
bool pRight, pLeft, pUp, pDown;
string[] Saves;
Save[] RSaves = new Save[4];
Save yoursave;
Save temp;
int slot;
NewGame newgame;
SavedGames savedgames;
string savedata, name = "";
int lvl = 1;
double exp = 0, money = 0;
int pSpeed = 5;
double deltaY, deltaX;
float interval = 7;
Point start;
Point nextStart;
Point cursor;
float radian;
const double Rad2Grad = (180 / Math.PI);
public MainGame()
{
InitializeComponent();
pbPlayer.BringToFront();
gbxTown.AllowDrop = true;
gbxQ1.AllowDrop = true;
pbShot.Location = pbPlayer.Location;
// newgame = new NewGame();
// savedgames = new SavedGames();
originalImage = pbPlayer.Image;
}
public void setSaves(string savedata, int slot)
{
Saves = savedata.Split('#');
string a1 = Saves[0];
string a2 = Saves[1];
string a3 = Saves[2];
string a4 = Saves[3];
RSaves[0] = temp.StringToSaves(temp, a1);
RSaves[1] = temp.StringToSaves(temp, a2);
RSaves[2] = temp.StringToSaves(temp, a3);
RSaves[3] = temp.StringToSaves(temp, a4);
yoursave = RSaves[slot - 1];
name = yoursave.getName();
this.slot = slot;
Controls.Add(pbPlayer);
Controls.Add(pbShot);
}
private void MainGame_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.A)
{
pRight = false;
pLeft = true;
}
else if (e.KeyData == Keys.D)
{
pRight = true;
pLeft = false;
}
else if (e.KeyData == Keys.S)
{
pUp = true;
pDown = false;
}
else if (e.KeyData == Keys.W)
{
pUp = false;
pDown = true;
}
if (e.KeyData == Keys.Space)
{
start = pbPlayer.Location;
cursor = Cursor.Position;
nextStart = start;
deltaY = cursor.Y - start.Y;
deltaX = cursor.X - start.X;
double test = Angle(start, cursor);
radian = (float)(Angle(start, cursor) - 175);
timer2.Enabled = true;
}
}
private void MainGame_KeyUp_1(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.A)
{
pLeft = false;
}
else if (e.KeyData == Keys.D)
{
pRight = false;
}
else if (e.KeyData == Keys.S)
{
pUp = false;
}
else if (e.KeyData == Keys.W)
{
pDown = false;
}
if (e.KeyData == Keys.Space)
{
timer2.Stop();
pbShot.Location = start;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
MovePlayer();
//checkCollision();
}
private void btnNextArea_Click(object sender, EventArgs e)
{
pbPlayer.Parent = gbxQ1;
pbShot.Parent = gbxQ1;
gbxQ1.Location = new Point(0, 0);
gbxTown.Location = new Point(605, 0);
pbPlayer.Location = new Point(100, 200);
pbShot.Location = pbPlayer.Location;
}
private void btnSave_Click(object sender, EventArgs e)
{
newgame = new NewGame();
savedgames = new SavedGames();
RSaves[slot - 1] = new Save(name, money, lvl, exp);
for (int i = 0; i < 4; i++) //When the Spacebar is released, a System.IndexOutOfRangeException error happens for i.
{
Saves[i] = RSaves[i].SavesToString();
}
savedata = Saves[0] + Saves[1] + Saves[2] + Saves[3];
System.IO.File.WriteAllLines(#"saves.txt", Saves);
newgame.setSaves(savedata);
savedgames.setSaves(savedata);
}
private void btnBack_Click(object sender, EventArgs e)
{
pbPlayer.Parent = gbxTown;
pbShot.Parent = gbxTown;
gbxTown.Location = new Point(0, 0);
gbxQ1.Location = new Point(605, 0);
pbPlayer.Location = new Point(100, 200);
pbShot.Location = pbPlayer.Location;
}
private void MainGame_MouseMove_1(object sender, MouseEventArgs e)
{
var y2 = e.Y;
var y1 = (this.pbPlayer.Location.Y + (this.pbPlayer.Height / 2));
var x2 = e.X;
var x1 = (this.pbPlayer.Location.X + (this.pbPlayer.Width / 2));
var angle = (float)Math.Atan2((y1 - y2), (x1 - x2));
pbPlayer.Image = RotateImage(originalImage, (angle * 57));
}
private double Angle(Point start, Point end)
{
return (float)Math.Atan2(end.Y - start.Y, end.X - start.X) * 57;
}
private void timer2_Tick_1(object sender, EventArgs e)
{
nextStart.X -= Convert.ToInt16(interval * ((float)Math.Cos(radian / Rad2Grad)));
nextStart.Y -= Convert.ToInt16(interval * ((float)Math.Sin(radian / Rad2Grad)));
pbShot.Location = nextStart;
}
public static Image RotateImage(Image img, float rotationAngle)
{
Bitmap bmp = new Bitmap(img.Width, img.Height);
Graphics gfx = Graphics.FromImage(bmp);
gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);
gfx.RotateTransform(rotationAngle);
gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.DrawImage(img, new Point(0, 0));
gfx.Dispose();
return bmp;
}
private void MovePlayer()
{
if (pRight == true && pbPlayer.Left < 900)
{
pbPlayer.Left += pSpeed;
}
else if (pLeft == true && pbPlayer.Left > 0)
{
pbPlayer.Left -= pSpeed;
}
else if (pUp == true && pbPlayer.Top < 600)
{
pbPlayer.Top += pSpeed;
}
else if (pDown == true && pbPlayer.Top > 0)
{
pbPlayer.Top -= pSpeed;
}
}
The expected outcome is for the movement, aiming and firing to work as intended within the groupboxes but currently they do not execute in the code while in the groupboxes. It works fine in the form but not in the groupboxes. I would appriciate any help.
I've 4 panels, having same Y and different X, that are created at the program start on a picturebox. When I click on a panel, it sets the focus and is ready to get a keysDown event so i.e. if I click on up arrow key the panel moves up.
This is the code:
public partial class FormView : Form
{
List<CircleButton> myPanels = new List<CircleButton>(); // array of panels CircleButton
Point[] arrayPoints_milestones; // array of X,Y
int index;
public FormView()
{
InitializeComponent();
arrayPoints_milestones = new Point[4];
for (int i = 0; i < 4; i++ )
{
arrayPoints_milestones[i] = new Point { X = 20, Y = 20 };
}
test();
}
protected void panel_Click(object sender, EventArgs e)
{
myPanels[index].PreviewKeyDown -= new PreviewKeyDownEventHandler(panel_KeyDown);
CircleButton panel = sender as CircleButton;
index = (int)panel.Tag;
myPanels[index].Focus(); //panel.Focus();
myPanels[index].PreviewKeyDown += new PreviewKeyDownEventHandler(panel_KeyDown);
}
private void panel_KeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Up)
{
myPanels[index].Centre = new Point(myPanels[index].Centre.X, myPanels[index].Centre.Y - 10);
MessageBox.Show("" + myPanels[index].Centre.Y);
Invalidate();
}
if (e.KeyCode == Keys.Down)
{
myPanels[index].Centre = new Point(myPanels[index].Centre.X, myPanels[index].Centre.Y + 10);
MessageBox.Show("" + myPanels[index].Centre.Y);
Invalidate();
}
}
private void test()
{
//for (int i = 0; i < 4; i++)
int i=0;
foreach(var value in arrayPoints_milestones)
{
CircleButton panel = new CircleButton();
panel.Tag = i;
panel.Centre = new Point(arrayPoints_milestones[i].X + i * 10, arrayPoints_milestones[i].Y);
panel.Radius = 10;
panel.BackColor = Color.Red;
panel.Message = "Index: " + panel.Tag.ToString();
myPanels.Add(panel); // qui aggiungo il pannello alla lista di pannelli myPanels
pictureBox1.Controls.Add(myPanels[i]);
myPanels[i].Click += new EventHandler(panel_Click);
i++;
}
}
}
and this is the custom panel class:
public class CircleButton : Panel
{
//Properties to draw circle
float radius;
public float Radius
{
get { return radius; }
set
{
radius = value;
this.Size = new Size((int)Radius, (int)Radius);
}
}
public string Name
{
get;
set;
}
Point centre;
public Point Centre
{
get { return centre; }
set
{
centre = value;
this.Location = Centre;
}
}
public string Message { get; set; }
public CircleButton()
{
//Default Values
Name = "panel_base";
this.BackColor = Color.Black;
Radius = 1;
Centre = new Point(0, 0);
this.DoubleBuffered = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
//Defines a graphic path and set it as the panel's region
//For custom region use different path's
if (centre != null)
{
GraphicsPath path = new GraphicsPath();
path.AddEllipse(0, 0, radius, radius);
this.Region = new Region(path);
path.Dispose();
}
}
}
Each time you click a panel, a PreviewKeyDownEventHandler is added - so 3 clicks will trigger 3 (different) eventhandlers with the same invocation target, and each will move your panel for 10 pixels up/down:
protected void panel_Click(object sender, EventArgs e) {
CircleButton panel = sender as CircleButton;
index = (int)panel.Tag;
myPanels[index].Focus(); //panel.Focus();
myPanels[index].PreviewKeyDown += new PreviewKeyDownEventHandler(panel_KeyDown);
}
Updated code for FormView:
public partial class FormView : Form {
List<CircleButton> myPanels = new List<CircleButton>(); // local use only in my example
Point[] arrayPoints_milestones; //not needed anymore
int index; //not needed anymore
public FormView() {
InitializeComponent();
this.Load += FormView_Load;
}
void FormView_Load(object sender, EventArgs args) {
Point panelOffset = new Point(20, 20);
for (int i = 0; i < 4; i++) {
var panel = new CircleButton() {
Name = "panel" + i, //Attention! You have hidden the property "Name" in "Control" with a re-declaration in "CircleButton"
Tag = i, //not needed anymore, right?
Centre = new Point(panelOffset.X + i * 10, panelOffset.Y),
Radius = 10,
BackColor = Color.Red,
Message = "Index: " + i.ToString(),
};
panel.Click += (s, e) => {
panel.Focus();
};
panel.PreviewKeyDown += (s, e) => {
if(e.KeyCode == Keys.Up) {
Point centre = panel.Centre; //copy value
centre.Y -= 10;
panel.Centre = centre; //assign modified copy
Invalidate();
}
if(e.KeyCode == Keys.Down) {
Point centre = panel.Centre; //copy value
centre.Y += 10;
panel.Centre = centre; //assign modified copy
Invalidate();
}
};
myPanels.Add(panel);
pictureBox1.Controls.Add(panel);
}
}
}
What i want is that if i drawed a rectangle on one of the items in the pictureBox next time i click the button it will display those items when i click on them in the listBox only the rectangles i drawed.
This is what i tried so far:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using DannyGeneral;
using System.Diagnostics;
namespace MinimizeCapture
{
public partial class Form1 : Form
{
Point p1 = new Point(0, 0);
Rectangle recttest;
private Rectangle Rect;
private Rectangle[] rectangles;
private Rectangle RectClone;
private bool btn = false;
private Point RectStartPoint = Point.Empty;
private Point RectEndPoint = Point.Empty;
private Brush selectionBrush = new SolidBrush(Color.Red);
private Pen pen;
private string selectedIndex;
private List<string> drawnItems = new List<string>();
private bool ClearGraphics;
public Form1()
{
InitializeComponent();
var windows = OpenWindowGetter.FindWindowsWithText();
ClearGraphics = false;
this.DoubleBuffered = true;
btn = false;
pen = new Pen(selectionBrush);
buttonSnap.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
private void buttonSnap_Click(object sender, EventArgs e)
{
ClearGraphics = true;
this.listBoxSnap.Items.Clear();
this.pictureBoxSnap.Image = null;
backgroundWorker1.RunWorkerAsync();
}
private void CutRectangle()
{
for (int i = 0; i < rectangles.Length; i++)
{
if (!rectangles[i].IsEmpty)
{
}
}
}
private void listBoxSnap_SelectedIndexChanged(object sender, EventArgs e)
{
WindowSnap snap = this.listBoxSnap.SelectedItem as WindowSnap;
selectedIndex = this.listBoxSnap.SelectedIndex.ToString();
this.pictureBoxSnap.Image = snap.Image;
for (int i = 0; i < rectangles.Length; i++)
{
if (rectangles[i] != RectClone)
{
ClearGraphics = false;
}
else
{
ClearGraphics = true;
}
}
}
private void checkBoxForceMDI_CheckedChanged(object sender, EventArgs e)
{
WindowSnap.ForceMDICapturing = (sender as CheckBox).Checked;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
listBoxSnap.Invoke(new MethodInvoker(delegate { this.listBoxSnap.Items.Add("Minimized Windows"); }));
listBoxSnap.Invoke(new MethodInvoker(delegate { this.listBoxSnap.Items.AddRange(WindowSnap.GetAllWindows(true,true).ToArray()); }));
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
rectangles = new Rectangle[listBoxSnap.Items.Count];
buttonSnap.Enabled = true;
}
private void pictureBoxSnap_Paint(object sender, PaintEventArgs e)
{
if (pictureBoxSnap.Image != null)
{
{
if (ClearGraphics == false)
{
if (rectangles[listBoxSnap.SelectedIndex] != Rectangle.Empty)
{
e.Graphics.DrawRectangle(Pens.Firebrick, rectangles[listBoxSnap.SelectedIndex]);
}
if (recttest.Width > 10 && recttest.Height > 10)
e.Graphics.DrawRectangle(Pens.Firebrick, recttest);
}
}
}
}
private void pictureBoxSnap_MouseMove(object sender, MouseEventArgs e)
{
if (btn == true)
{
ClearGraphics = false;
RectEndPoint = e.Location;
int currentindex = listBoxSnap.SelectedIndex;
rectangles[currentindex] = RectClone;
Rect = getRect(RectStartPoint, RectEndPoint);
RectClone = Rect;
pictureBoxSnap.Invalidate();
}
}
private void pictureBoxSnap_MouseDown(object sender, MouseEventArgs e)
{
RectStartPoint = e.Location;
btn = true;
Rect = Rectangle.Empty;
RectClone = Rectangle.Empty;
p1 = e.Location;
}
private void pictureBoxSnap_MouseUp(object sender, MouseEventArgs e)
{
recttest = rectangles[listBoxSnap.SelectedIndex];
ClearGraphics = false;
btn = false;
RectEndPoint = e.Location;
pictureBoxSnap.Invalidate();
int currentindex = listBoxSnap.SelectedIndex;
rectangles[currentindex] = RectClone;
if (e.Location.X > p1.X)
{
recttest.X = p1.X;
recttest.Width = e.Location.X - p1.X;
}
else
{
recttest.X = e.Location.X;
recttest.Width = p1.X - e.Location.X;
}
//Top and Height
if (e.Location.Y > p1.Y)
{
recttest.Y = p1.Y;
recttest.Height = e.Location.Y - p1.Y;
}
else
{
recttest.Y = e.Location.Y;
recttest.Height = p1.Y - e.Location.Y;
}
if (recttest.Width > 10 && recttest.Height > 10)
pictureBoxSnap.Invalidate();
}
Rectangle getRect(Point p1, Point p2)
{
Point p = new Point(Math.Min(p1.X, p2.X), Math.Min(p1.Y, p2.Y));
Size s = new Size(Math.Abs(p1.X - p2.X), Math.Abs(p1.Y - p2.Y));
return new Rectangle(p, s);
}
private void ConfirmRectangle_Click(object sender, EventArgs e)
{
ConfirmRectangle.ForeColor = Color.Red;
ConfirmRectangle.Enabled = false;
StreamWriter w = new StreamWriter(#"c:\temp\Settings.txt", true);
w.WriteLine("Rectangle Location: " + RectClone.Location + " Rectangle Size: " + RectClone.Size + " Selected Index: " + selectedIndex);
textBoxIndex.Text = selectedIndex.ToString();
w.Close();
pictureBoxSnap.Image = CropImage();
}
private Bitmap CropImage()
{
Bitmap pic = pictureBoxSnap.Image as Bitmap;
Bitmap cropped = new Bitmap(recttest.Width, recttest.Height);
using (Graphics g = Graphics.FromImage(cropped))
{
g.DrawImage(pic, new Rectangle(0, 0, recttest.Width, recttest.Height),
recttest, GraphicsUnit.Pixel);
}
return cropped;
}
}
}
For the test i called the rectangle variable recttest.
In the mouse up event i'm getting the rectangle i drawed in the current selected item in the listBox.
I can't upload here images but what i get is when i click the ConfirmRectangle button i see the the rectangle i drawed in the pictureBox the same as it was and the image in the pictureBox get resize get very very big from the inside like it was zoom in.
Instead what i wanted to get is the part of the image in the pictureBox that was marked/drawed by the rectangle. Like the rectangle is the border so when i click on the ConfirmRectangle i will see the part of the image was in the pictureBox in the rectangle and only this all the rest should not be shown.
I should see rectangle with inside the part of the image. Not to resize or zoom in the image only to cut the part was marked/drawn on by the rectangle.
try following method.
Boolean bHaveMouse;
Point ptOriginal = new Point();
Point ptLast = new Point();
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
bHaveMouse = true;
// Store the "starting point" for this rubber-band rectangle.
ptOriginal.X = e.X;
ptOriginal.Y = e.Y;
// Special value lets us know that no previous
// rectangle needs to be erased.
ptLast.X = -1;
ptLast.Y = -1;
}
// Convert and normalize the points and draw the reversible frame.
private void MyDrawReversibleRectangle(Point p1, Point p2)
{
Rectangle rc = new Rectangle();
// Convert the points to screen coordinates.
p1 = pictureBox.PointToScreen(p1);
p2 = pictureBox.PointToScreen(p2);
// Normalize the rectangle.
if (p1.X < p2.X)
{
rc.X = p1.X;
rc.Width = p2.X - p1.X;
}
else
{
rc.X = p2.X;
rc.Width = p1.X - p2.X;
}
if (p1.Y < p2.Y)
{
rc.Y = p1.Y;
rc.Height = p2.Y - p1.Y;
}
else
{
rc.Y = p2.Y;
rc.Height = p1.Y - p2.Y;
}
// Draw the reversible frame.
rect = new Rectangle(pictureBox.PointToClient(rc.Location), rc.Size);
ControlPaint.DrawReversibleFrame(rc, Color.Gray, FrameStyle.Dashed);
}
Rectangle rect = Rectangle.Empty;
private void pictureBox_MouseUp(object sender, MouseEventArgs e)
{
// Set internal flag to know we no longer "have the mouse".
bHaveMouse = false;
// If we have drawn previously, draw again in that spot
// to remove the lines.
if (ptLast.X != -1)
{
Point ptCurrent = new Point(e.X, e.Y);
MyDrawReversibleRectangle(ptOriginal, ptLast);
}
// Set flags to know that there is no "previous" line to reverse.
ptLast.X = -1;
ptLast.Y = -1;
ptOriginal.X = -1;
ptOriginal.Y = -1;
pictureBox.Invalidate();
}
private void pictureBox_Paint(object sender, PaintEventArgs e)
{
if (rect.Width > 10 && rect.Height > 10)
{
e.Graphics.DrawRectangle(Pens.Gray, rect);
pictureBox1.Image = CropImage();
}
}
private Bitmap CropImage()
{
Bitmap pic = pictureBox.Image as Bitmap;
Bitmap cropped = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(cropped))
{
g.DrawImage(pic, new Rectangle(0, 0, rect.Width, rect.Height),
rect, GraphicsUnit.Pixel);
}
return cropped;
}
private void pictureBox_MouseMove(object sender, MouseEventArgs e)
{
Point ptCurrent = new Point(e.X, e.Y);
// If we "have the mouse", then we draw our lines.
if (bHaveMouse)
{
// If we have drawn previously, draw again in
// that spot to remove the lines.
if (ptLast.X != -1)
{
MyDrawReversibleRectangle(ptOriginal, ptLast);
}
// Update last point.
ptLast = ptCurrent;
// Draw new lines.
MyDrawReversibleRectangle(ptOriginal, ptCurrent);
}
}
Output
I am using ControPaint.DrawReversibleFrame method to draw rubber band. To read more about this method u can refere this tutorial
I am displaying two lines dynamically in form and want to move line vertically.
I tried to move using mousemove event but it's moving both lines together.
So is it possible to move dynamically added line individually on the form?
Here is my code
Graphics g;
int Y = 250;
public Form2()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
}
private void Form2_Paint(object sender, PaintEventArgs e)
{
g = e.Graphics;
g.DrawLine(Pens.Red, new Point(0, Y), new Point(1500, Y));
g.DrawLine(Pens.LimeGreen, new Point(0, Y+50), new Point(1500, Y+50));
}
public void Form2_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Y = e.Location.Y;
Refresh();
}
}
Any input will be greatly appreciated.
You may use following code to solve your purpose.
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 TestWin
{
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
this.DoubleBuffered = true;
this.Paint += new PaintEventHandler(LineMover_Paint);
this.MouseMove += new MouseEventHandler(LineMover_MouseMove);
this.MouseDown += new MouseEventHandler(LineMover_MouseDown);
this.MouseUp += new MouseEventHandler(LineMover_MouseUp);
this.Lines = new List<GraphLine>()
{
new GraphLine (10, 10, 100, 200),
new GraphLine (10, 150, 120, 40),
};
}
void LineMover_MouseUp(object sender, MouseEventArgs e)
{
if (Moving != null)
{
this.Capture = false;
Moving = null;
}
RefreshLineSelection(e.Location);
}
void LineMover_MouseDown(object sender, MouseEventArgs e)
{
RefreshLineSelection(e.Location);
if (this.SelectedLine != null && Moving == null)
{
this.Capture = true;
Moving = new MoveInfo
{
Line = this.SelectedLine,
StartLinePoint = SelectedLine.StartPoint,
EndLinePoint = SelectedLine.EndPoint,
StartMoveMousePoint = e.Location
};
}
RefreshLineSelection(e.Location);
}
void LineMover_Paint(object sender, PaintEventArgs e)
{
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
foreach (var line in Lines)
{
var color = line == SelectedLine ? Color.Red : Color.Black;
var pen = new Pen(color, 2);
e.Graphics.DrawLine(pen, line.StartPoint, line.EndPoint);
}
}
void LineMover_MouseMove(object sender, MouseEventArgs e)
{
if (Moving != null)
{
Moving.Line.StartPoint = new PointF(Moving.StartLinePoint.X + e.X - Moving.StartMoveMousePoint.X, Moving.StartLinePoint.Y + e.Y - Moving.StartMoveMousePoint.Y);
Moving.Line.EndPoint = new PointF(Moving.EndLinePoint.X + e.X - Moving.StartMoveMousePoint.X, Moving.EndLinePoint.Y + e.Y - Moving.StartMoveMousePoint.Y);
}
RefreshLineSelection(e.Location);
}
private void RefreshLineSelection(Point point)
{
var selectedLine = FindLineByPoint(Lines, point);
if (selectedLine != this.SelectedLine)
{
this.SelectedLine = selectedLine;
this.Invalidate();
}
if (Moving != null)
this.Invalidate();
this.Cursor =
Moving != null ? Cursors.Hand :
SelectedLine != null ? Cursors.SizeAll :
Cursors.Default;
}
public List<GraphLine> Lines = new List<GraphLine>();
GraphLine SelectedLine = null;
MoveInfo Moving = null;
static GraphLine FindLineByPoint(List<GraphLine> lines, Point p)
{
var size = 10;
var buffer = new Bitmap(size * 2, size * 2);
foreach (var line in lines)
{
//draw each line on small region around current point p and check pixel in point p
using (var g = Graphics.FromImage(buffer))
{
g.Clear(Color.Black);
g.DrawLine(new Pen(Color.Green, 3), line.StartPoint.X - p.X + size, line.StartPoint.Y - p.Y + size, line.EndPoint.X - p.X + size, line.EndPoint.Y - p.Y + size);
}
if (buffer.GetPixel(size, size).ToArgb() != Color.Black.ToArgb())
return line;
}
return null;
}
public class MoveInfo
{
public GraphLine Line;
public PointF StartLinePoint;
public PointF EndLinePoint;
public Point StartMoveMousePoint;
}
public class GraphLine
{
public GraphLine(float x1, float y1, float x2, float y2)
{
this.StartPoint = new PointF(x1, y1);
this.EndPoint = new PointF(x2, y2);
}
public PointF StartPoint;
public PointF EndPoint;
}
}
}
Both of your lines take there position from the same variable Y (declared at the top of the source code) to do what you want you will need to firstly create a second variable to keep track of where the lines are individually.
Your second problem is going to be deciding which line you want to move perhaps alternating which line is moved based on which mouse button is down during Form2_MouseMove() .
I have drawn Some Ellipses on Windows Form.
Is it Possible for 'c# Window Form' to 'mouse click' on an ellipse and to delete it?..
Code from Comments
public void DrawCircle_Paint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.Black, 3);
Graphics gr = this.CreateGraphics();
gr.DrawEllipse(pen, 40, 45, 20, 20);
Pen pen2 = new Pen(Color.Black, 3);
Graphics gr1 = this.CreateGraphics();
gr.DrawEllipse(pen2, 30, 25, 38, 20);
Pen pen3 = new Pen(Color.Black, 3);
Graphics gr2 = this.CreateGraphics();
gr.DrawEllipse(pen3, 35, 36, 68, 15);
Pen pen4 = new Pen(Color.Black, 3);
Graphics gr3 = this.CreateGraphics();
gr.DrawEllipse(pen4, 50, 60, 67, 35);
}
Yes its possible.
I assume that you know the positions and dimensions of the ellipses and have them stored in a list. Then you can use the MouseDown and iterate through the ellipses. How to check, if a point is in an ellipse, can be found here for example.
If you found a clicked ellipse remove it from your list and repaint everything.
Update:
To your code. You dont need to call CreateGraphics all the time. The graphics object is given in the PaintEventArgs (e.Graphics). Also you dont need to create a pen every time.
public void DrawCircle_Paint(object sender, PaintEventArgs e)
{
Graphics gr = e.Graphics;
using(Pen p = new Pen(Color.Black, 3))
{
gr.DrawEllipse(pen, 40, 45, 20, 20);
gr.DrawEllipse(pen2, 30, 25, 38, 20);
gr.DrawEllipse(pen3, 35, 36, 68, 15);
gr.DrawEllipse(pen4, 50, 60, 67, 35);
}
}
I've just tried this demo, well there are fairly much work. It's just a demo because there are still many features lacked and also the memory leakage problem is not ensured to not occur. Drawing some thing directly using some methods of Graphics object won't help you support some interaction (like hittesting). You have to draw a GraphicsPath or a Region using the methods FillPath or FillRegion. In this demo, I used GraphicsPath, is has 2 interesting methods to help us implement hittesting which are IsVisible and IsOutlineVisible, in this case we just use IsVisible. Now is the code for you:
public class Ellipse : IDisposable
{
GraphicsPath gp = new GraphicsPath();
RectangleF rect;
public Ellipse(Point center, float rx, float ry)
{
Center = center;
RadiusX = rx;
RadiusY = ry;
Visible = true;
rect = new RectangleF(Center.X - RadiusX, Center.Y - RadiusY, RadiusX * 2, RadiusY * 2);
gp.AddEllipse(rect);
BackColor = Color.Green;
SelectedBackColor = Color.LimeGreen;
BorderColor = Color.Transparent;
}
public event EventHandler Click;
public event EventHandler MouseEnter;
public event EventHandler MouseLeave;
Point center;
float rx, ry;
Control canvas;
bool entered;
bool visible;
Color backColor;
Color borderColor;
Color selectedColor;
bool selected;
public bool Selected
{
get { return selected; }
set
{
if (selected != value)
{
selected = value;
if (canvas != null) canvas.Invalidate(Rectangle.Ceiling(rect));
}
}
}
public bool Visible
{
get { return visible; }
set
{
if (visible != value)
{
visible = value;
if(canvas != null) canvas.Invalidate(Rectangle.Ceiling(rect));
}
}
}
public Control Canvas
{
get { return canvas; }
set
{
if (canvas != value)
{
if(canvas != null) DetachCanvas(canvas);
if (value != null)
{
AttachCanvas(value);
value.Invalidate(Rectangle.Ceiling(rect));
}
canvas = value;
}
}
}
public Point Center
{
get { return center; }
set
{
if (center != value)
{
int dx = value.X - center.X;
int dy = value.Y - center.Y;
rect.Offset(dx, dy);
center = value;
gp.Reset();
gp.AddEllipse(rect);
if (canvas != null) canvas.Invalidate(Rectangle.Ceiling(rect));
}
}
}
public float RadiusX
{
get { return rx; }
set
{
if (rx != value)
{
rect.Width = rx * 2;
rx = value;
gp.Reset();
gp.AddEllipse(rect);
if (canvas != null) canvas.Invalidate(Rectangle.Ceiling(rect));
}
}
}
public float RadiusY
{
get { return ry; }
set
{
if (ry != value)
{
rect.Height = ry * 2;
ry = value;
gp.Reset();
gp.AddEllipse(rect);
if (canvas != null) canvas.Invalidate(Rectangle.Ceiling(rect));
}
}
}
public Color BorderColor
{
get { return borderColor; }
set
{
if (borderColor != value)
{
borderColor = value;
if (canvas != null) canvas.Invalidate(Rectangle.Ceiling(rect));
}
}
}
public Color SelectedBackColor
{
get { return selectedColor; }
set
{
if (selectedColor != value)
{
selectedColor = value;
if (canvas != null) canvas.Invalidate(Rectangle.Ceiling(rect));
}
}
}
public Color BackColor
{
get { return backColor; }
set
{
if (backColor != value)
{
backColor = value;
if (canvas != null) canvas.Invalidate(Rectangle.Ceiling(rect));
}
}
}
private void Render(Graphics g)
{
using(Pen p = new Pen(BorderColor))
using (Brush b = new SolidBrush(selected ? SelectedBackColor : BackColor))
{
SmoothingMode sm = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.FillPath(b, gp);
g.DrawPath(p, gp);
g.SmoothingMode = sm;
}
}
private void CanvasPaint(object sender, PaintEventArgs e)
{
if (Visible) Render(e.Graphics);
}
private void CanvasMouseMove(object sender, MouseEventArgs e)
{
var cv = sender as Control;
if (gp.IsVisible(e.Location))
{
var handler = MouseEnter;
if (handler != null && Visible)
{
handler(this, EventArgs.Empty);
}
entered = true;
}
else if (entered)
{
var handler = MouseLeave;
if (handler != null && Visible)
{
handler(this, EventArgs.Empty);
}
entered = false;
}
}
private void CanvasMouseClick(object sender, MouseEventArgs e){
var cv = sender as Control;
if (gp.IsVisible(e.Location))
{
var handler = Click;
if (handler != null && Visible) handler(this, EventArgs.Empty);
}
}
private void AttachCanvas(Control canvas)
{
canvas.Paint += CanvasPaint;
canvas.MouseMove += CanvasMouseMove;
canvas.MouseClick += CanvasMouseClick;
}
private void DetachCanvas(Control canvas)
{
canvas.Paint -= CanvasPaint;
canvas.MouseMove -= CanvasMouseMove;
canvas.MouseClick -= CanvasMouseClick;
}
public void Dispose()
{
Visible = false;
if (Canvas != null) Canvas.Invalidate(Rectangle.Ceiling(rect));
Canvas = null;
gp.Dispose();
}
}
Usage: I implemented only 3 events: MouseEnter, MouseLeave and Click. These events are very similar to the events we use with normal control. Here is the demo code for you to test, it will render the ellipse on a form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var e = new Ellipse(new Point(400, 400), 100, 100) { Canvas = this };
e.MouseEnter += (s, ev) => {
e.BackColor = Color.Red;
};
e.MouseLeave += (s, ev) => {
e.BackColor = Color.Green;
};
e.Click += (s, ev) => {
e.Visible = false; //Hide the ellipse
};
}
}
Note that you can create your own class for other shapes.
UPDATE: I updated the Ellipse class with some modification to avoid memory leakage, to delete the ellipse you just need to call Dispose, it will delete the ellipse and you can't use it anymore, for your requirement with a List<Ellipse>, try this:
//You have to handle `Ellipse.Click` to set the `Selected` manually, this is by design
//do this for every ellipses
Ellipse selectedEllipse;
//Use this handler for all the Click event of your ellipses
private void Ellipse_Click(object sender, EventArgs e){
var ellipse = sender as Ellipse;
if(ellipse == selectedEllipse) return;
if(selectedEllipse != null) selectedEllipse.Selected = false;
ellipse.Selected = true;
selectedEllipse = ellipse;
}
List<Ellipse> ellipses = ...; //this is your List<Ellipse>
for(int i = ellipses.Count - 1; i >= 0; i--){
if(ellipses[i].Selected){
ellipses[i].Dispose();
ellipses.RemoveAt(i);
}
}
The code to handle the Ellipse.Click event for every Ellipse can be modified to allow multiple selected. That's why it's not hard-coded to be selected when begin clicked.
try it !
Bitmap Painting;
Pen Pen_Drawing;
Graphics Graph_Drawing;
Pen_Drawing.Dispose();
Graph_Drawing.Dispose();
Painting.Dispose();
Painting = new Bitmap(500, 500);
Pen_Drawing = new Pen(Color.FromArgb(95, 158, 160), 1f);
Graph_Drawing = Graphics.FromImage(Painting);