How to create HotSpot in C# with PictureBox? - c#

I am a new C# developer and I want to create a hotspot in an image that I put in my winform application. I followed the solution posted HERE, but I did not know where I should put the coordinates to make this method works:
protected override void OnMouseMove(MouseEventArgs mouseEvent)
{
string X = mouseEvent.X.ToString();
string Y = mouseEvent.Y.ToString();
}
Where should I put the coordinates? I have two coordinates (X,Y): 110, 45

Hotspot I feel should be a small rectangular area rather than just a coordinate. Suppose you want it to be a small square area of width 20 then you would write something like this:
EDIT:
Suppose you have a PictureBox on your form called PictureBox1 and you want that a small rectangle of say 20x20 size starting from Top-Left corner of the picturebox become a hotspot (i.e. when you take mouse over it you would see a HAND cursor) then on the MouSeMove event of the PictureBox write this:
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.X > 0 && e.X < 20 && e.Y > 0 && e.Y < 20)
this.Cursor = Cursors.Hand;
else
this.Cursor = Cursors.Default;
}
Please remember, we are just showing the Hand Cursor to denote a hotspot we have not yet handled a Click for that matter, to make it really a web kind hotspot. If you want to do something on Click, try using the MouseUp event, in the MouseUp event the same IF clause as above would give you the condition that user has clicked on the hotspot region.

Related

Background image of control bugged

I've done a mini test program to prototype a way to drag and drop an image (at the right)(using a button as a support) to a panel (left part)(The current panel background letter are only for test purpose) and to move it inside the panel perimeter.
The image on the moving control is manually drawn during the Paint event :
void bouton_Paint( object sender, PaintEventArgs e )
{
Button but = sender as Button;
Bitmap img = new Bitmap(WindowsFormsApplication1.Properties.Resources.triaxe);
img.MakeTransparent(Color.White);
e.Graphics.DrawImage(img, 0, 0, but.Width, but.Height);
}
As you can see below, during the moving process, the background of the moved control is frezzed. So it is not very pretty
Is it to make the progress smoother ?
Thank you.
This is the code to move my triaxe on the form :
void bouton_MouseUp( object sender, MouseEventArgs e )
{
Button button = sender as Button;
button.Tag = false;
button.BackColor = Color.Transparent;
}
void bouton_MouseMove( object sender, MouseEventArgs e )
{
Button button = sender as Button;
if (button.Tag != null && (bool)button.Tag == true)
{
button.Left += e.X - MouseDownLocation.X;
button.Top += e.Y - MouseDownLocation.Y;
}
}
private Point MouseDownLocation;
void bouton_MouseDown( object sender, MouseEventArgs e )
{
Button button = sender as Button;
MouseDownLocation = e.Location;
button.Tag = true;
button.BackColor = SystemColors.Control;
}
Let's assume you do not want to draw the graphics alone but do want a Control with transparency move on top of another Control.
You have to solve two problems:
Winforms doesn't support transparency well; you have two options:
Either let the system fake it for you
Or do the faking yourself.
For the first it is enough to have a control with a transparent backcolor and an Image or BackgroundImage (depending on the control type) with transparency and then nest the moving control in the background control.
For a simplistic test you can add if (button.Parent != panel1) button.Parent = panel1; to your mousedown code. This will look jumpy but should display transparency correctly. (Don't forget to make the Backcolor transparent; in your code your make it SystemColors.Control.
To fake it yourself you would do exactly what the system does:
You get the target suface in a bitmaps (with DrawToBitmap) and then combine the area the mover currently covers with the image; here getting that area is key.
Then you can set that image as backgroundimage or draw it onto the mover.
The other problem is with the moving code. Here the issue is that when you move the mouse the MouseMove event is triggered and you can move the control. But by moving it the mouse will have moved relativly to the new location and the event will be triggered again leading to flicker an jumpiness!
To avoid this you can test the numbers or use a flag or unregister the move event before setting the location and re-register afterwards.
Also setting the location in one go instead of the two coordinates is a good idea..: button.Location = new Point(button.Left + e.X - MouseDownLocation.X, button.Top + e.Y - MouseDownLocation.Y);
Imo you should still consider drawing just the graphics on On panel.MouseMove and panel.Paint. On panel.MouseUp you can still add a Button to the panel.Controls right there. Both issues are avoided and you are free to add the functionality you want as well..

Convert PictureBox Crop Location to WebCam Crop Location [duplicate]

I have a pictureBox2 and it is set to zoom, I am trying to find out how to to get a real x,y pixel location on the image by Mouse.Click on pictureBox2. but I tried 3 possible ideas I knew of: without/with PointToClient,PointToScreen but I can never get it right.
private void pictureBox2_Click(object sender, EventArgs e)
{
MouseEventArgs me = (MouseEventArgs)e;
txtpictureHeight.Text =(
(OriginalImage.GetImageHeight()*me.Location.Y)/ pictureBox2.Image.Height).ToString();
txtpictureWidth.Text = (
(OriginalImage.GetImageWidth()* me.Location.X)/ pictureBox2.Image.Width).ToString();
}
There must be some factor I need to take care of so I thought to use double result from above and I get closed but there is still 80px off for the height on my test image (1371x2221). As I use Zoom so there are 2 extra spaces on my pictureBox2
Note that with SizeMode set to Zoom, the PictureBox keeps aspect ratio, and centers the image, so on top of calculating the adjusted coordinates, you also have to take padding into account.
My advice, don't use the Click event; it is meant to detect button clicks, not to actually process interaction of the mouse with an object. Use MouseDown instead.
The first thing we need to do is get the width and height of the original image. As I noted in my comment, this is simply the object inside the Image property of the PictureBox.
Next, we need the dimensions and location of the zoomed image. For that, we can start from the dimensions of the ClientRectangle of the PictureBox. Divide those by the image width and height and you'll get the horizontal and vertical zoom values. If the SizeMode would be set to StretchImage, that'd be all we need, but since aspect ratio is conserved, you need the smallest of the two values to have the actual zoom factor.
Once we got that, multiply the original width and height by this zoom factor to get the zoomed width and height, then subtract that from the actual ClientRectangle dimensions and divide it by two to get the padding for both dimensions. This can of course be simplified by checking which of the two possible zoom factors is used, and only calculating the padding for the other one, since the dimension of which the zoom factor was used obviously has 0 padding.
Now you got the padding and zoom factor, the rest is simple: subtract the padding values from the mouse coordinates, and then divide both results by the zoom factor.
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
// Default check: left mouse button only
if (e.Button == MouseButtons.Left)
ShowCoords(e.X, e.Y);
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
// Allows dragging to also update the coords. Checking the button
// on a MouseMove is an easy way to detect click dragging.
if (e.Button == MouseButtons.Left)
ShowCoords(e.X, e.Y);
}
private void ShowCoords(Int32 mouseX, Int32 mouseY)
{
Int32 realW = pictureBox1.Image.Width;
Int32 realH = pictureBox1.Image.Height;
Int32 currentW = pictureBox1.ClientRectangle.Width;
Int32 currentH = pictureBox1.ClientRectangle.Height;
Double zoomW = (currentW / (Double)realW);
Double zoomH = (currentH / (Double)realH);
Double zoomActual = Math.Min(zoomW, zoomH);
Double padX = zoomActual == zoomW ? 0 : (currentW - (zoomActual * realW)) / 2;
Double padY = zoomActual == zoomH ? 0 : (currentH - (zoomActual * realH)) / 2;
Int32 realX = (Int32)((mouseX - padX) / zoomActual);
Int32 realY = (Int32)((mouseY - padY) / zoomActual);
lblPosXval.Text = realX < 0 || realX > realW ? "-" : realX.ToString();
lblPosYVal.Text = realY < 0 || realY > realH ? "-" : realY.ToString();
}
Note, I used sharp pixel zoom here to better show the effect. It's a little trick you can do by subclassing PictureBox and overriding its OnPaint method, to adjust the Graphics object from the PaintEventArgs object and set its InterpolationMode to NearestNeighbor (It's also advised to set PixelOffsetMode to Half; there's a bug where sharp zoom is shifted half a pixel unless you do that). Then you call base.OnPaint() with that adjusted event args object.
I also added some more info on it here, but that's all just stuff you can get from the in-between values of the pixel coordinates calculation process anyway.

How to draw rectangle on picture box at mouse click coordinates [duplicate]

This question already has answers here:
How to draw rectangle on MouseDown/Move c#
(4 answers)
Closed 7 years ago.
I'm trying to create a windows forms application in which, when the user clicks anywhere on a picture box, a rectangle appears at the position where the image was clicked.
However, if I click anywhere on the image, the rectangle will appear at some random position regardless of where I clicked. It can appear either near or far away from the mouse click, and in some cases it never goes beyond the left half of the picture box.
May I have some guidance on how to resolve this issue? Specifically, I want the position where I clicked to be the center of the rectangle.
Thank you!
This is my code for reference:
private void pbImage_Click(object sender, EventArgs e)
{
//Note: pbImage is the name of the picture box used here.
var mouseEventArgs = e as MouseEventArgs;
int x = mouseEventArgs.Location.X;
int y = mouseEventArgs.Location.Y;
// We first cast the "Image" property of the pbImage picture box control
// into a Bitmap object.
Bitmap pbImageBitmap = (Bitmap)(pbImage.Image);
// Obtain a Graphics object from the Bitmap object.
Graphics graphics = Graphics.FromImage((Image)pbImageBitmap);
Pen whitePen = new Pen(Color.White, 1);
// Show the coordinates of the mouse click on the label, label1.
label1.Text = "X: " + x + " Y: " + y;
Rectangle rect = new Rectangle(x, y, 200, 200);
// Draw the rectangle, starting with the given coordinates, on the picture box.
graphics.DrawRectangle(whitePen, rect);
// Refresh the picture box control in order that
// our graphics operation can be rendered.
pbImage.Refresh();
// Calling Dispose() is like calling the destructor of the respective object.
// Dispose() clears all resources associated with the object, but the object still remains in memory
// until the system garbage-collects it.
graphics.Dispose();
}
UPDATE 12.55am, 16/8/2015 - I know why! The SizeMode property of the pictureBox was set to StretchImage. Changed it back to Normal mode and it worked fine. Not exactly sure why this is so, I'll definitely look into it.
To those who have replied, thank you so much for your help! :)
The first two arguments to the Rectangle constructor are the top-left (not center) coordinates.
And handle the mouse and paint events separately:
int mouseX, mouseY;
private void pbImage_MouseDown(object sender, MouseEventArgs e)
{
mouseX = e.X;
mouseY = e.Y;
pbImage.Refresh();
}
private void pbImage_Paint(object sender, PaintEventArgs e)
{
//... your other stuff
Rectangle rect = new Rectangle(mouseX - 100, mouseY - 100, 200, 200);
e.Graphics.DrawRectangle(whitePen, rect);
}
You are casting EventArgs to MouseEventArgs, I think that is incorrect. Are you tried with MouseDown or MouseUp events of the picture control? Those events provides you the information you need.

How can I convert the mouse cursor coordinates when click on pictureBox are to the screen relative mouse cursor coordinates?

In my program I added this code so when I move my mouse all over the screen I will get the mouse cursor coordinates in real time:
Form1 Load:
private void Form1_Load(object sender, EventArgs e)
{
System.Windows.Forms.Timer t1 = new System.Windows.Forms.Timer();
t1.Interval = 50;
t1.Tick += new EventHandler(timer1_Tick);
t1.Enabled = true;;
}
Then the method that get the mouse position:
public static Point GetMousePosition()
{
var position = System.Windows.Forms.Cursor.Position;
return new Point(position.X, position.Y);
}
Then the timer1 tick event:
private void timer1_Tick(object sender, EventArgs e)
{
label1.Text = string.Format("X={0}, Y={1}", GetMousePosition().X, GetMousePosition().Y);
}
Then I ran some application and moved the mouse over a specific location on the screen where the application window is and I found this coordinates:
358, 913
Now I have in my program a listBox with items each item present application screenshot. And if I click on the pictureBox for example in this case on the BATTLEFIELD 3 area I get the mouse cursor coordinates according to the pictureBox area.
So I did:
Point screenCoordinates;
Point pictureBoxSnapCoordinates;
private void pictureBoxSnap_MouseDown(object sender, MouseEventArgs e)
{
screenCoordinates = pictureBoxSnap.PointToScreen(e.Location);
pictureBoxSnapCoordinates = e.Location;
}
Now when I click in the pictureBox at the same location as I found the coordinates 358, 913 but on the pictureBox so the results are:
screenCoordinates 435, 724
pictureBoxSnapCoordinates 23,423
The screenCoordinates isn't the same coordinates as I found with the mouse move 358, 913 it's not even close. There is a big difference between 358,913 and 437,724
e.Location is relative to the Control's top left corner. If you want to use e.Location to get the screen coordinates, then you have to first do pictureBoxSnap.PointToScreen(Point.Empty); and then offset by the e.Location.
Also, Cursor.Position returns a Point object, so making a new Point(...) is pointless.
I must add, if you are dealing with images, and you need to interact with mouse, and do any task related with offset, scroll, etc, I recommend you that library, it is open source and have a lot of examples and methods that will help you
https://github.com/cyotek/Cyotek.Windows.Forms.ImageBox

Graphic user interface with c#

I have to create a graphic interface for a c# winform project. There is a background image and a set of small transparent pictures. The user must be able to put those little images over the backgroud, select them and move them freely (I have also to calculate distance between them but this is another step!).
I know I can do somthing like this:
Flicker free drawing using GDI+ and C#
I also found this:
http://cs-sdl.sourceforge.net/
My question is: is there a better or simplest solution to achieve this?
update
Now images are rectangular. There are no problems if images overlaps!
If small images are a problem I can switch with simple circles (DrawEllipse). The important point is that user can always click on and move them.
I have searched for a solution on how to remove flickering from pictureboxs, without finding something satisfying ... i ended up using some 2DVector from the XNA framework and spirits. it worked fine :)
http://www.xnadevelopment.com/ gives a good explanation for how to use it, it is explained in a game context.
The Windows Presentation Fo
Foundation (WPF) may be a better solution for this. It is more graphically inclined than GDI+, and is also much faster, as its powered by DirectX.
If you don't want flickr your best option is DirectX/XNA/OpenGL. Try to find a 2d framework with sprites for your application.
If you would use WPF then you should use a Canvas as your container control. To the images you have to add these event handlers in you code behind file:
private bool IsDragging = false;
private System.Windows.Point LastPosition;
private void MyImage_MouseDown(object sender, MouseButtonEventArgs e)
{
// Get the right MyImage
Image MyImage = sender as Image;
// Capture the mouse
if (!MyImage.IsMouseCaptured)
{
MyImage.CaptureMouse();
}
// Turn the drag mode on
IsDragging = true;
// Set the current mouse position to the last position before the mouse was moved
LastPosition = e.GetPosition(SelectionCanvas);
// Set this event to handled
e.Handled = true;
}
private void MyImage_MouseUp(object sender, MouseButtonEventArgs e)
{
// Get the right MyImage
Image MyImage = sender as Image;
// Release the mouse
if (MyImage.IsMouseCaptured)
{
MyImage.ReleaseMouseCapture();
}
// Turn the drag mode off
IsDragging = false;
// Set this event to handled
e.Handled = true;
}
private void MyImage_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
// Get the right MyImage
Image MyImage = sender as Image;
// Move the MyImage only when the drag move mode is on
if (IsDragging)
{
// Calculate the offset of the mouse movement
double xOffset = LastPosition.X - e.GetPosition(SelectionCanvas).X;
double yOffset = LastPosition.Y - e.GetPosition(SelectionCanvas).Y;
// Move the MyImage
Canvas.SetLeft(MyImage, (Canvas.GetLeft(MyImage) - xOffset >= 0.0) && (Canvas.GetLeft(MyImage) + MyImage.Width - xOffset <= SelectionCanvas.ActualWidth) ? Canvas.GetLeft(MyImage) - xOffset : Canvas.GetLeft(MyImage));
Canvas.SetTop(MyImage, (Canvas.GetTop(MyImage) - yOffset >= 0.0) && (Canvas.GetTop(MyImage) + MyImage.Height - yOffset <= SelectionCanvas.ActualHeight) ? Canvas.GetTop(MyImage) - yOffset : Canvas.GetTop(MyImage));
// Set the current mouse position as the last position for next mouse movement
LastPosition = e.GetPosition(SelectionCanvas);
}
}
I hope that helps, David.

Categories