I have a panel with multiple pictureboxes over it. I want to create a rectangle over panel and Picturebox when MouseLeft Button is down and Mouse is dragged. I understand Rectangle Mouse select area can be created with the combination of Mousedown on Panel and MouseMove events on Picturebox and Panel.
Now My Implementation is , When i receive Mousedown event on Panel I save Mousedown Location and look for MouseMove events. if mousemove events is on panel i draw a rectangle over panel and if Mouse Move event is on Picturebox i start drwaing Rectangle for that Picturebox.
Now the Problem is , when mouseleft button is down and mouse move is done over panel i am able to receive mousemove events over it and draw rectangle over panel. However i am not receiving any MouseMove Events for Picturebox to create rectangle select area for it.
Is my Implementation Correct and can someone kindly propose the solution for this ?
I am Posting My Code Snippet for reference.
Code:
//Panel Class
public partial class Childwindow : Form
{
//Mouse down event
private void ClickEventOnchildForm(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
RectStartPoint = e.Location;
IsSelecting = true;
Invalidate();
}
}
//Mouse Move event
private void flowLayoutPanel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
Point tempEndPoint = e.Location;
Rect.Location = new Point(
Math.Min(RectStartPoint.X, tempEndPoint.X),
Math.Min(RectStartPoint.Y, tempEndPoint.Y));
Rect.Size = new Size(
Math.Abs(RectStartPoint.X - tempEndPoint.X),
Math.Abs(RectStartPoint.Y - tempEndPoint.Y));
this.flowLayoutPanel1.Invalidate();
}
//Paint event
private void flowLayoutPanel1_Paint_1(object sender, PaintEventArgs e)
{
if (Rect != null && Rect.Width > 0 && Rect.Height > 0)
{
e.Graphics.FillRectangle(selectionBrush, Rect);
}
}
}
Public class Picturebox: UserControl{
private void picbox_MouseMove(object sender, MouseEventArgs e)
{//Higlight particular Picturebox
}
}
Related
I'm hooking my form with middle click. And for now i middle click to hook my form then middle click again to trigger my method to draw on my picturebox (which is on my form).
I'd like to middle click once and instantly draw on my picturebox instead of two middle click. I tried MouseHover and MouseEnter with this code :
private void PbxDrawing_MouseEnter(object sender, EventArgs e)
{
bMoving = true;
Point pos = PbxDrawing.PointToClient(Cursor.Position);
x = pos.X;
y = pos.Y;
}
Mouse move :
private void PbxDrawing_MouseMove(object sender, MouseEventArgs e)
{
if(bMoving && x!=-2 && y != -2)
{
g.DrawLine(pen,new Point(x,y), e.Location);
x = e.X;
y = e.Y;
}
}
It allows me to know the position of the cursor and draw but to draw i've to release middle click .
How can i draw from 1 middle click if my middle click was made outside of my form ?
Edit : Clarify question
Just check if the Middle Button is down in the MouseMove event:
private void PbxDrawing_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle)
{
x = e.X;
y = e.Y;
}
}
private void PbxDrawing_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle)
{
g.DrawLine(pen, new Point(x, y), e.Location);
x = e.X;
y = e.Y;
}
}
Your use of g is a red flag, though. Is g created with PbxDrawing.CreateGraphics()? If yes, this is wrong and should be refactored to use the e.Graphics from the Paint() event of the PictureBox.
I'm trying to code a draggable rectangle zoombox that's transparent, once the mouse is up again, it zooms into that area and deletes the drawn rectangle.
I've got the zoom working and drawing the rectangle, however I can't 1) Figure out how to make it transparent, and 2) Figure out how to delete the rectangle after it's zoomed in. It gets deleted again once the mouse is clicked down to draw another zoombox on the zoomed in image (I'm drawing a fractal) but I can't figure out what to write to get it to delete after zooming in.
Paint
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics windowG = e.Graphics;
windowG.DrawImageUnscaled(picture, 0, 0);
if (rectangle == true)
{
e.Graphics.FillRectangle(Brushes.Aquamarine, rec);
}
if (rectangle == false)
{
Invalidate();
}
}
Mouse Down
rectangle = true;
if (e.Button == MouseButtons.Left)
{
rec = new Rectangle(e.X, e.Y, 0, 0);
Invalidate();
}
Mouse up
{
rectangle = false;
}
Mouse Move
if (e.Button == MouseButtons.Left)
{
rec.Width = e.X - rec.X;
rec.Height = e.Y - rec.Y;
Invalidate();
}
At first I thought you need this:
This is one of the very rare cases where your drawing should not be done in the Paint event but in the MouseMove using a Graphics object created with CreateGraphics.
The reason why this is the right way here is that for this kind of interactive rubberband drawing you do not want the drawing to persist. Other examples would be a line preview or a cursor cross.
To make the Rectangle transparent you can either
Use DrawRectangle
or use a semi-transparent color and FillRectangle
or use both as in the example below:
Here is the code you need:
Point mDown = Point.Empty;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
mDown = e.Location; // note the first corner
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
Invalidate(); // clear the rectangle
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
using (Graphics G = this.CreateGraphics() ) // !!! usually wrong !!!
{
G.Clear(BackColor); // Invalidate();
Rectangle rect = rectangle(mDown, e.Location);
// either
using (SolidBrush brush = new SolidBrush(Color.FromArgb(32, 255, 0, 0)))
G.FillRectangle(brush, rect);
// or
G.DrawRectangle(Pens.Red, rect);
}
}
This is a function that lets you start drawing any any corner, not just top left:
Rectangle rectangle (Point p1, Point p2)
{
int x = Math.Min(p1.X, p2.X);
int y = Math.Min(p1.Y, p2.Y);
int w = Math.Abs(p1.X - p2.X);
int h = Math.Abs(p1.Y - p2.Y);
return new Rectangle(x, y, w, h);
}
Note that if you have a BackgroundImage this above code won't work so well.
But now I think this is closer to your situation:
In this case we go back to the normal way and draw things in the Paint but only as long as the mouse button is pressed. As we don't have the mouse parameters here we need another class level Point and also use the Control.MouseButtons property:
Point mCurrent = Point.Empty;
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
mCurrent = e.Location;
Invalidate();
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
mDown = Point.Empty;
mCurrent = Point.Empty;
Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (Control.MouseButtons == System.Windows.Forms.MouseButtons.Left)
{
Rectangle rect = rectangle(mDown, mCurrent);
// either one..
using (SolidBrush brush = new SolidBrush(Color.FromArgb(32, 255, 0, 0)))
e.Graphics.FillRectangle(brush, rect);
// ..or both of these
e.Graphics.DrawRectangle(Pens.Red, rect);
}
}
So to sum it up: Besides quite a few details your main problem is missing the check for the mouse button in the paint event..
I'm creating a simple application that draws a horizontal and a vertical line following the mouse.
The form is transparent using TransparencyKey, and the lines are drawn using the Paint event:
private void Form1_Paint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.Lime);
e.Graphics.DrawLine(pen, 0, py, this.Size.Width, py);
e.Graphics.DrawLine(pen, px, 0, px, this.Size.Height);
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
px = e.X; // get cursor X pos
py = e.Y; // get cursor Y pos
Invalidate(); // fire Paint event
}
But the MouseMove event only is fired when the mouse is over the lines drawn. How to make the form catch mouse events when transparent? (Only the mouse move, I want the form still click-through)
As you can read here: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.transparencykey%28v=vs.110%29.aspx - "Any mouse actions, such as the click of the mouse, that are performed on the transparent areas of the form will be transferred to the windows below the transparent area". One way to accomplish your goal is to write your own method, that will check the cursor relative position to the form in a loop, here's what I mean (it worked for me with TransparencyKey, resizing and moving the form):
private void MouseMovedWithTransparency()
{
Point lastCursorPos = new Point(-1, -1); // Starting point.
while (this.Visible)
{
Point currentCursorPos = Cursor.Position;
if (this.ContainsFocus && currentCursorPos.X > this.Left && currentCursorPos.X < this.Left + this.Width &&
currentCursorPos.Y > this.Top && currentCursorPos.Y < this.Top + this.Height)
{
if ((currentCursorPos.X != lastCursorPos.X) || (currentCursorPos.Y != lastCursorPos.Y))
{
// Do actions as in MouseMoved event.
// Save the new position, so it won't be triggered, when user doesn't move the cursor.
lastCursorPos = currentCursorPos;
}
}
Application.DoEvents(); // UI must be kept responsive.
Thread.Sleep(1);
}
}
All you have to do now is to invoke this method from the Shown event - this.Visible has to be true, so it's the easiest way to make it work.
I have a picture box and I draw a string on it by DrawString(). I change position of the string by scrolling a TrackBar. But I want to move the string by directly clicking on the string and then dragging. It'll be easier for any user. Can anybody help me achieve this?
Edit: I already move my pictureBox1 my mouse click:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(img, 0, 0);
e.Graphics.DrawString(str, font, new SolidBrush(color), new PointF(NinjaClass.NINJA.pointX, NinjaClass.NINJA.pointY));
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
x = e.X;
y = e.Y;
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
pictureBox1.Left += (e.X - x);
pictureBox1.Top += (e.Y - y);
}
}
Using DrawString is not very convenient for such a task, you have to save a Rectangle around the string, update that rectangle according to the mouse movement ... If we need to click exactly on the string curve to move the string, using DrawString can't help. In such a case we have to use a GraphicsPath which supports a little hittesting. However in this case we just allow user to click on the string bounds, because clicking on the string curve with small font or even normal font is not easy and very annoying indeed. Try the following code:
//your form constructor
public Form1(){
InitializeComponent();
//add string to the GraphicsPath, the string location is initialized with (10,10)
gp.AddString("Your string goes here", Font.FontFamily,
(int)Font.Style, 20, new Point(10, 10), StringFormat.GenericDefault);
}
GraphicsPath gp = new GraphicsPath();
float dx, dy;
//the Paint event handler for your pictureBox1
private void pictureBox1_Paint(object sender, PaintEventArgs e) {
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
gp.Transform(new Matrix(1, 0, 0, 1, dx, dy));//Translate and paint
e.Graphics.FillPath(Brushes.Red, gp);
gp.Transform(new Matrix(1,0,0,1,-dx,-dy));//translate back (reset to old location)
}
Point downPoint;
bool hitOn;
//MouseDown event handler for your pictureBox1
private void pictureBox1_MouseDown(object sender, MouseEventArgs e){
if(e.Button == MouseButtons.Left){
downPoint = e.Location;
if (gp.GetBounds(new Matrix(1,0,0,1,dx,dy)).Contains(e.Location)) {
gp.Transform(new Matrix(1, 0, 0, 1, dx, dy));
hitOn = true;
}
}
}
//MouseMove event handler for your pictureBox1
private void pictureBox1_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
if(hitOn){
dx = e.X - downPoint.X;
dy = e.Y - downPoint.Y;
pictureBox1.Invalidate();
} else {
pictureBox1.Left += e.X - downPoint.X;
pictureBox1.Top += e.Y - downPoint.Y;
}
}
}
//MouseUp event handler for your pictureBox1
private void pictureBox1_MouseUp(object sender, MouseEventArgs e) {
hitOn = false;
}
Update: For using a transparent backColor Label: There is a note that when you drag and drop a label on a pictureBox at design time, the Parent of the label will be the pictureBox container not the PictureBox, that's by design, because PictureBox is not intended to contain any control. So you have to set the Parent using code, for the code moving the label, you do similarly to what you do with your PictureBox, the difference is the parent of PictureBox is your form while the parent of the label is your pictureBox:
public Form1(){
InitializeComponent();
label1.BackColor = Color.Transparent;
label1.Parent = pictureBox1;
//try this to prevent a little flicker, but looks like it does not help much
typeof(Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance)
.SetValue(pictureBox1, true, null);
}
Point lblDownPoint;
//MouseDown event handler for your label1
private void label1_MouseDown(object sender, MouseEventArgs e){
if(e.Button == MouseButtons.Left) lblDownPoint = e.Location;
}
//MouseMove event handler for your label1
private void label1_MouseMove(object sender, MouseEventArgs e){
if(e.Button == MouseButtons.Left) {
label1.Left += e.X - lblDownPoint.X;
label2.Top += e.Y - lblDownPoint.Y;
}
}
However after trying using a transparent BackColor label instead, I can see that it's fairly worse (caused by flicker) than draw directly on the pictureBox as the previous code does. You should consider to choose between them yourself, the previous code seems a little complicated (but not really if you understand it).
i have used this code to move picture box on the pictureBox_MouseMove event
pictureBox.Location = new System.Drawing.Point(e.Location);
but when i try to execute the picture box flickers and the exact position cannot be identified. can you guys help me with it. I want the picture box to be steady...
You want to move the control by the amount that the mouse moved:
Point mousePos;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e) {
mousePos = e.Location;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
int dx = e.X - mousePos.X;
int dy = e.Y - mousePos.Y;
pictureBox1.Location = new Point(pictureBox1.Left + dx, pictureBox1.Top + dy);
}
}
Note that this code does not update the mousePos variable in MouseMove. Necessary since moving the control changes the relative position of the mouse cursor.
You have to do several things
Register the start of the moving operation in MouseDown and remember the start location of the mouse.
In MouseMove see if you are actually moving the picture. Move by keeping the same offset to the upper left corner of the picture box, i.e. while moving, the mouse pointer should always point to the same point inside the picture box. This makes the picture box move together with the mouse pointer.
Register the end of the moving operation in MouseUp.
private bool _moving;
private Point _startLocation;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
_moving = true;
_startLocation = e.Location;
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
_moving = false;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (_moving) {
pictureBox1.Left += e.Location.X - _startLocation.X;
pictureBox1.Top += e.Location.Y - _startLocation.Y;
}
}
Try to change SizeMode property from AutoSize to Normal