I want to show my form on the screen I'm clicking on.
For this I use a globalhookMouse to get the coordinates of my cursor outside my form. I've two screen (1280x1024 and 1680x1050).
I've tried to put my form if my Cursor.Position.X is lower than one of my resolution but I get higher value.
This is how I hook my form to show
private void GlobalHookMouseDownExt(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle)
{
this.Show();
this.TopLevel = true;
}
}
How can I know from which screen I clicked to show my form on the right screen ?
System.Windows.Forms.Screen.AllScreens gives you a lot of information about your screens.
You will see that the X can go negative.
int x = System.Windows.Forms.Cursor.Position.X;
int y = System.Windows.Forms.Cursor.Position.Y;
these will always be the coords of where your cursor is at that moment.
the end result would be something like:
if (Cursor.Position.X > 0)
{
this.Location = new System.Drawing.Point(0,0);
}
else
{
this.Location = new System.Drawing.Point(-1920,0);
}
I hope it helps.
Related
So I'm trying to make a slider. I'm using my cursor to move a button's x position.
I have 3 functions, the mouseDown, mouseUp and the mouseMove function. In the mouseUp and mouseDown functions I set a variable to true and false to tell the program that the mouse is clicked or not. In the mouseMove function I tell the program to set the button's x position to the x position of the mouse when the mouse is clicked. This works but has 2 problems.
The first problem is that when I press the button and move it, the button moves along with the mouse's x but it has a space between the mouse and the button. It looks a bit like this:
CURSOR.......BUTTON
The space between the cursor and button change when I change the resolution of the form.
The second problem is that when I move the button it flickers a bit. It only does this at higher speeds but it is a problem in my case.
My code looks like this:
bool mouseDown = false;
private void volumeGrabBT_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mouseDown = true;
}
}
private void volumeGrabBT_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mouseDown = false;
}
}
private void volumeGrabBT_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDown == true)
{
Point volumeBTPoint = new Point();
volumeBTPoint.X = Cursor.Position.X;
volumeBTPoint.Y = volumeGrabBT.Location.Y;
volumeGrabBT.Location = volumeBTPoint;
}
}
The volumeGrabBT is the button I'm trying to move along with the mouse.
The volumeBTPoint is the point of the button I'm trying to set the button's position to.
I hope someone can help me fix these problems. Thanks in advance!
I believe that flickering can be fixed by setting some additional form styles: SetStyle(ControlStyles.AllPaintingInWmPaint |ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
in form's constructor. It will use double buffering and generally just draws faster.
For the Cursor class, it's relative to the screen, not your form. You can use this.PointToClient() function to get client's space position of cursor, like this:
Point clientCursor = this.PointToClient(Cursor.Position);
and then use clientCursor to get exact X in your client space.
You have to translate screen coordinates to client coordinates.
Point volumeBTPoint = new Point();
Point point = this.PointToClient(Cursor.Position);
volumeBTPoint.X = point.X;
volumeBTPoint.Y = volumeGrabBT.Location.Y;
volumeGrabBT.Location = volumeBTPoint;
Instead of this you should use button's parent control (Panel, GroupBox, etc).
As the application starts, I'd like my WPF window to automatically snap to the right edge of the screen. Is there a way to do that? I also want to be able to retain its dimensions. So, unlike the snapping behavior that happens when you drag a window to the edge of the screen, causing the window to resize to either a portion of the screen or full screen, I want my window to simply snap to the edge at a certain location by default or if dragged by the user to a specific location afterwards, without resizing. I still want to retain the ability of the user to drag the window away from the edge.
Is there anything like that already implemented or would I have to create my own behavior schema? I tried numerous search keyword combinations, but couldn't find anything similar to what I'm doing. Some of the searches included disabling snapping behavior or providing snapping behavior, but nothing in the way I described above.
EDIT:
I haven't been able to find a ready solution, so I wrote my own. This solution is based on BenVlodgi's suggestions, so I thank him for helping me out. This is a very rough implementation and still requires a lot of polishing and better code techniques, but it works and it's a good base for anyone wanting to try this. It's incredibly simple and works very well with WPF. The only limitation of this implementation is that I haven't tried getting it to work with two screens yet, but it's incredibly simple (I'm just not going to have time for it and I don't need that functionality at this point). So, here's the code and I hope that it helps someone out there:
public partial class MainWindow : Window
{
// Get the working area of the screen. It excludes any dockings or toolbars, which
// is exactly what we want.
private System.Drawing.Rectangle screen =
System.Windows.Forms.Screen.PrimaryScreen.WorkingArea;
// This will be the flag for the automatic positioning.
private bool dragging = false;
// The usual initialization routine
public MainWindow()
{
InitializeComponent();
}
// Wait until window is lodaded, but prior to being rendered to set position. This
// is done because prior to being loaded you'll get NaN for this.Height and 0 for
// this.ActualHeight.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Sets the initial position.
SetInitialWindowPosition();
// Sets the monitoring timer loop.
InitializeWindowPositionMonitoring();
}
// Allows the window to be dragged where the are no other controls present.
// PreviewMouseButton could be used, but then you have to do more work to ensure that if
// you're pressing down on a button, it executes its routine if dragging was not performed.
private void Window_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// Set the dragging flag to true, so that position would not be reset automatically.
if (e.ChangedButton == System.Windows.Input.MouseButton.Left)
{
dragging = true;
this.DragMove();
}
}
// Similar to MouseDown. We're setting dragging flag to false to allow automatic
// positioning.
private void Window_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (e.ChangedButton == System.Windows.Input.MouseButton.Left)
{
dragging = false;
}
}
// Sets the initial position of the window. I made mine static for now, but later it can
// be modified to be whatever the user chooses in the settings.
private void SetInitialWindowPosition()
{
this.Left = screen.Width - this.Width;
this.Top = screen.Height / 2 - this.Height / 2;
}
// Setup the monitoring routine that automatically positions the window based on its location
// relative to the working area.
private void InitializeWindowPositionMonitoring()
{
var timer = new System.Windows.Threading.DispatcherTimer();
timer.Tick += delegate
{
// Check if window is being dragged (assuming that mouse down on any portion of the
// window is connected to dragging). This is a fairly safe assumption and held
// true thus far. Even if you're not performing any dragging, then the position
// doesn't change and nothing gets reset. You can add an extra check to see if
// position has changed, but there is no significant performance gain.
// Correct me if I'm wrong, but this is just O(n) execution, where n is the number of
// ticks the mouse has been held down on that window.
if (!dragging)
{
// Checking the left side of the window.
if (this.Left > screen.Width - this.Width)
{
this.Left = screen.Width - this.Width;
}
else if (this.Left < 0)
{
this.Left = 0;
}
// Checking the top of the window.
if (this.Top > screen.Height - this.Height)
{
this.Top = screen.Height - this.Height;
}
else if (this.Top < 0)
{
this.Top = 0;
}
}
};
// Adjust this based on performance and preference. I set mine to 10 milliseconds.
timer.Interval = new TimeSpan(0, 0, 0, 0, 10);
timer.Start();
}
}
Make sure that your window has the following:
MouseDown="Window_MouseDown"
MouseUp="Window_MouseUp"
WindowStartupLocation="Manual"
Loaded="Window_Loaded"
Also, this doesn't work well with Windows native components of the window, such as the top bar, so I disable the style and create my own (which is actually good for me, since I don't want the windows style for this):
WindowStyle="None"
I don't like the polling approach, but it's been excessively difficult to find a better solution that is still simple in WPF, so I'm gonna post my own.
The solution that I found is actually quite simple, in that it reimplements the behaviour of the DragMove() method of the window, which gives you the option to change the window position while it's being dragged. The following code reimplements DragMove() by storing the distance between the top left corner of the window and the mouse cursor.
public partial class MainWindow : Window
{
// this is the offset of the mouse cursor from the top left corner of the window
private Point offset = new Point();
public MainWindow()
{
InitializeComponent();
}
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Point cursorPos = PointToScreen(Mouse.GetPosition(this));
Point windowPos = new Point(this.Left, this.Top);
offset = (Point)(cursorPos - windowPos);
// capturing the mouse here will redirect all events to this window, even if
// the mouse cursor should leave the window area
Mouse.Capture(this, CaptureMode.Element);
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (Mouse.Captured == this && Mouse.LeftButton == MouseButtonState.Pressed)
{
Point cursorPos = PointToScreen(Mouse.GetPosition(this));
double newLeft = cursorPos.X - offset.X;
double newTop = cursorPos.Y - offset.Y;
// here you can change the window position and implement
// the snapping behaviour that you need
this.Left = newLeft;
this.Top = newTop;
}
}
}
Now you could implement the snapping / sticky window behaviour like this: The window will stick to the edge of the screen if it's within a range of 25 pixels (plus or minus).
int snappingMargin = 25;
if (Math.Abs(SystemParameters.WorkArea.Left - newLeft) < snappingMargin)
newLeft = SystemParameters.WorkArea.Left;
else if (Math.Abs(newLeft + this.ActualWidth - SystemParameters.WorkArea.Left - SystemParameters.WorkArea.Width) < snappingMargin)
newLeft = SystemParameters.WorkArea.Left + SystemParameters.WorkArea.Width - this.ActualWidth;
if (Math.Abs(SystemParameters.WorkArea.Top - newTop) < snappingMargin)
newTop = SystemParameters.WorkArea.Top;
else if (Math.Abs(newTop + this.ActualHeight - SystemParameters.WorkArea.Top - SystemParameters.WorkArea.Height) < snappingMargin)
newTop = SystemParameters.WorkArea.Top + SystemParameters.WorkArea.Height - this.ActualHeight;
The downside of this approach is that the snapping will not work, if the window is being dragged on the title bar, because that doesn't fire the OnMouseLeftButtonDown event (which I don't need, because my window is borderless). Maybe it will still help someone.
There is no API calls you can make (as far as I've seen) to use the Windows snapping features, however you could just get the System.Windows.Forms.Screen.PrimaryScreen.WorkingArea of the screen and set your Top, Left, Height and Width Properties of your Window accordingly.
Edit: The above suggestion does require Forms, which you probably don't want. I believe the WPF equivalent is System.Windows.SystemParameters.WorkArea
I'm having a rather irritating problem with images on buttons in .NET. They don't behave as you would expect an image on a button to behave.
In the properties of a button you can set Image. So I select an image and the image shows up on the button! So far so good.
When a button is clicked, or in a pressed state, the text of the button will move down and right one pixel to create a depth. But not the image! It will stay in the same position, and it will look weird.
There is also the BackgroundImage property, but that's even worse! Because if I set BackgroundImageLayout to None instead of Center, the image will move up and left when pressed, the complete opposite direction of the text! What's up with that?
Anyway, what I want to achieve is a button image that moves just like the text would move when the button is in a pressed state. Is there a way to do this?
Just make a new image and paste the original one at an offset. Then set that as the Button's Image.
Example:
private void button1_MouseDown(object sender, MouseEventArgs e)
{
// replace "button_image.png" with the filename of the image you are using
Image normalImage = Image.FromFile("button_image.png");
Image mouseDownImage = new Bitmap(normalImage.Width + 1, normalImage.Height + 1);
Graphics g = Graphics.FromImage(mouseDownImage);
// this will draw the normal image at an offset on mouseDownImage
g.DrawImage(normalImage, 1, 1); // offset is one pixel each for x and y
// clean up
g.Dispose();
button1.Image = mouseDownImage;
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
// reset image to the normal one
button1.Image = Image.FromFile("button_image.png");
}
EDIT: The following function fixes a problem where the image would not 'pop' back up when the cursor leaves the button area while the mouse button is still pressed (see Labor's comment below):
private void button1_MouseMove(object sender, MouseEventArgs e)
{
Point relMousePos = e.Location;
bool mouseOverButton = true;
mouseOverButton &= relMousePos.X > 0;
mouseOverButton &= relMousePos.X < button1.Width;
mouseOverButton &= relMousePos.Y > 0;
mouseOverButton &= relMousePos.Y < button1.Height;
if (mouseOverButton != MouseButtons.None)
{
button1_MouseDown(sender, e);
}
else
{
button1_MouseUp(sender, e);
}
}
im working on code-editor (windows forms application) and I just want to ask how to get tooltip position instead of mouseposition will make it on cursor something like this 1:
Get current cursor lower left position so that tooltip could be displayed properly
specifically this code:
private void panel1_MouseClick(object sender, MouseEventArgs e) {
int x = e.X;
int y = e.Y + Cursor.Current.Size.Height - Cursor.Current.HotSpot.Y;
toolTip1.Show("test", panel1, x, y);
}
but i dont have panel i only got richtextbox[rtb](serve as code editor) and a labelbox[lb](serve as contexthint) .
anyone pls? really in need thanks!
I'm developing an app for windows mobile (Compact Framework 2.0). It has a WinForms with a PictureBox.
I want to move the image of the PictureBox but I don't know how to do it so I choose to move the hole PictureBox.
To do it I use this event:
private void imagenMapa_MouseMove(object sender, MouseEventArgs e)
{
imagenMapa.Left = e.X;
imagenMapa.Top = e.Y;
this.Refresh();
}
But when I move the PictureBox it blinks and moves every where.
What I'm doing wrong?
Actual Code (Requires .NET Framework 3.5 and beyond, not sure if this is available in the Compact Framework)...
// Global Variables
private int _xPos;
private int _yPos;
private bool _dragging;
// Register mouse events
pictureBox.MouseUp += (sender, args) =>
{
var c = sender as PictureBox;
if (null == c) return;
_dragging = false;
};
pictureBox.MouseDown += (sender, args) =>
{
if (args.Button != MouseButtons.Left) return;
_dragging = true;
_xPos = args.X;
_yPos = args.Y;
};
pictureBox.MouseMove += (sender, args) =>
{
var c = sender as PictureBox;
if (!_dragging || null == c) return;
c.Top = args.Y + c.Top - _yPos;
c.Left = args.X + c.Left - _xPos;
};
The e.X and e.Y are relative to the picture box (e.g. if the mouse is in the upper left of the picture box, that's 0,0) .
The values for imagenMapa.Left and imagenMapa.Top are relative to the form (or whatever control contains imagenMapa)
If you try to mix values from these two systems without conversion, you're going to get jumps (like you're seeing).
You're probably better off converting the mouse position to the same coordinate system used by the thing that contains the picture box.
You could use imagenMapa.PointToScreen to get the mouse coordinates in screen coordinates (or Cursor.Position to get the position directly), and yourForm.PointToClient to get them back in the form coordinates.
Note that depending on your needs, you could accomplish "moving an image within a control" by overriding/handling the Paint event of a control and drawing the image yourself. If you did this, you could keep everything in the picturebox coordinates, since those are likely what you would use when you called graphicsObject.DrawImage.
e.X & e.Y is in the coordinate space of the pictureBox, imagenMapa.Left & imagenMapa.Top is in the coordinate space of the Form. :-)
Also don't forget to set your form to double buffered, that might help with the flickering, but for the actual positioning of it, I like Daniel L's suggestion
Embrace math!
control.Left = control.Left - (_lastMousePos.X - currentMousePos.X);
control.Top = control.Top - (_lastMousePos.Y - currentMousePos.Y);
Quick explanation:
You get the difference from the mouse positions and apply it to the object you want to move.
Example:
If the old mouse X position is 382, and the new one is 385, then the difference is -3. If the controls current X position is 10 then 10 - (-3) = 13
Why:
It works for anything, and is much cheaper than constantly converting coordinates back and forth.
Actually what you have done is correct. But you gave the MouseMove property to the picturebox. You should give that property to the Form(background).
ex:
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
imagenMapa.Left = e.X;
imagenMapa.Top = e.Y;
}