I am creating a C# WinForm application and I want to detect mouse movement when the mouse is outside the form.
I already tried to create new thread that continually calculates the mouse coordinates, it work well as a job, but it uses while(true). It's really inefficient for CPU.
Edit (missunderstanding from first time) :
Working example -->
private void MainForm_MouseLeave(object sender, EventArgs e)
{
this.Cursor = new System.Windows.Forms.Cursor(System.Windows.Forms.Cursor.Current.Handle);
System.Windows.Forms.Cursor.Position = new Point(0, 0);
MoveCursor(300, 300);
MoveCursor(400, 400);
}
private void MoveCursor(int X, int Y)
{
this.Cursor = new System.Windows.Forms.Cursor(System.Windows.Forms.Cursor.Current.Handle);
System.Windows.Forms.Cursor.Position = new Point(X,Y);
}
Related
I have a question about a program I am writing for practice, which in its current state allows the user to move a label around the Form using the arrow keys.
I want to start adding some graphical rectangles to my program, and am currently practicing by trying to draw a simple rectangle once a timer hits 100.
Here's the weird part, the rectangle only draws once the label has passed over part of it, and will only draw the part the label passes over. Picture of this happening: label passing over rectangle. Ideally I would like to understand why this is happening, but will also be very happy if anyone can offer a solution!
I will post my whole code as I'm not even sure which part the problem could be coming from. Very sorry if its untidy, hopefully someone will have an idea just from the image:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
int direction;
int X = 200;
int Y = 200;
Rectangle myRock;
public System.Windows.Forms.Timer aTimer = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
this.Load += new System.EventHandler(this.Form1_Load);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
this.Click += new System.EventHandler(this.Form1_Click);
}
void worker()
{
for (int i = 0; i < 100000; i++) {
if (label2.InvokeRequired)
{
label2.Invoke((MethodInvoker)delegate
{
label2.Text = i.ToString(); // this is a timer acting as a score keeper
});
Thread.Sleep(100);
}
}
}
public void DrawRectangleRectangle(PaintEventArgs e, Rectangle rect)
{
// Create pen.
Pen blackPen = new Pen(Color.White, 3);
SolidBrush whiteBrush = new SolidBrush(Color.White);
// Create rectangle.
// Draw rectangle to screen.
e.Graphics.DrawRectangle(blackPen, rect);
e.Graphics.FillRectangle(whiteBrush, rect);
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_Click(object sender, EventArgs e)
{
Thread newThread = new Thread(worker);
direction = 2;
newThread.Start();
}
private void SetDirection(KeyEventArgs e)
{
if (e.KeyCode == Keys.Down) direction = 4;
else if (e.KeyCode == Keys.Up) direction = 2;
else if (e.KeyCode == Keys.Right) direction = 3;
else if (e.KeyCode == Keys.Left) direction = 1;
}
private void ApplyMovement()
{
Size size = new Size(100,100);
Point position = new Point(100, 100);
while (direction != 0)
{
Application.DoEvents();
if (direction == 1) X--;
else if (direction == 2) Y--;
else if (direction == 3) X++;
else if (direction == 4) Y++;
if (label2.Text == "100") myRock = new Rectangle(position, size);
Thread.Sleep(10);
label1.Location = new Point(X, Y);
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
SetDirection(e);
ApplyMovement();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
int label2Variable = Convert.ToInt32(label2.Text);
if (label2Variable > 100)
{
DrawRectangleRectangle(e, myRock);
}
}
private void label1_Click(object sender, EventArgs e)
{
}
}
}
Thanks in advance!
What is happening is that the OnPaint() function is not being called, so you aren't repainting all of the form. When Windows believes that something on your form has changed, it will issue a Repaint command to your application, asking it to redraw all or a section of the form's area, which appears in your code as the Form.OnPaint() method being fired.
What you need to do here is tell Windows that your form has changed. The easiest way to do this is to call:
this.Invalidate();
once something has changed, so possibly at the end of the loop in ApplyMovement().
(You can also call this.Refresh(), which will Invalidate the whole form, and then cause a synchronous repaint of it. Thanks #Bradley)
That way, you're telling Windows that the form is "invalid" and needs to be completely repainted, whereupon Windows will (indirectly) call the OnPaint() method.
Edit
Having rehydrated your app, I have applied the following change to the ApplyMovement() method:
if (label2.Text == "100") myRock = new Rectangle(position, size);
... changed to ...
if (label2.Text == "100")
{
myRock = new Rectangle(position, size);
this.Invalidate();
}
Now, when the value of the incrementing label field hits "100", the myRock rectangle appears immediately in my tests.
It's important to understand that your code never calls OnPaint() directly. You use the Invalidate() method to tell Windows itself that a part (or all) of your form has changed and needs to be updated on-screen. Windows will then "call" the OnPaint() method.
If you're using the OnPaint() method like this to draw information from your program to the screen, such as the myRock rectangle, or some custom painted text, then any time that information changes, you need to call Invalidate() to trigger an OnPaint().
It's the way all the common controls, such as textboxes and buttons, update themselves to the screen. They call Invalidate() internally any time you change one of their properties.
A quick way to think about it is that anytime you want OnPaint() to be called, you call Invalidate().
Hope this helps
i try making a point'n'click adventure for a school project, i can do it the way i want with the language i want, but there needs to be one new aspect we didn't discuss in lessons. i chose c# and make a windows forms program.
i wanted to make a soundtrack and play it in the background ingame as the new aspect, but my teacher said that would be too easy and told me to do the animations with transform commands. i barely managed to actually make translatetransform work, now i'm trying to animate it using a timer which updates the panel displaying the images. i tried different ways to do so, this is my last solution:
public partial class Form1 : Form
{
private float move = 0f;
private int sizex = 40, sizey = 40;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void gavi_ani_timer_Tick(object sender, EventArgs e)
{
gavi.Update();
move = move + 10;
}
private void gavi_Paint(object sender, PaintEventArgs e)
{
Graphics g = gavi.CreateGraphics();
Pen pen1 = new Pen(Color.Red, 5);
g.TranslateTransform(move, move);
g.DrawEllipse(pen1, 0, 0, sizex, sizey);
}
}
what do i have to do to make the circle move?
the circle is not part of the actual game, i'm just trying to make it work.
help is much appreciated, thank you
Hello I'm trying to do the effect that the button is pressed, so when mousenter moving 2px the picturebox, I'm using picturebox as button because It allows me to set transparent backgrounds.
I tried forcing the background to transparent in various events(paint,pevious change location,after change location),but without success.
I think that is caused for the re-drawing when changing an element, because the white part of the background that whas "hidden" by the picturebox appears.
Any idea how to solve that?
Thanks in advance
private void buttonX2_MouseLeave(object sender, EventArgs e)
{
((PictureBox) sender).Location = new Point(
((PictureBox) sender).Location.X, ((PictureBox) sender).Location.Y - 2);
}
private void buttonX2_MouseEnter(object sender, EventArgs e)
{
((PictureBox)sender).Location = new Point(
((PictureBox)sender).Location.X, ((PictureBox)sender).Location.Y + 2);
}
The problem seems to come from moving in or out too slowly. If you do that you will say enter from below, but the PB is moving up so you're out of it again, so it moves down and therefore you're in it again etc..The correct repainting of the Background can't keep up with these 'Jittering ButtBoxes'..
First, as Hans noted, make things less obtrusive: make the Form's BackColor dark, maybe even black!
Second to avoid the problem of jittering, move the Mouse Cursor itself a few pixels with the Pictureboxes, like this:
private void pictureBox1_MouseEnter(object sender, EventArgs e)
{
PictureBox PB = (PictureBox)sender;
Point MP = Cursor.Position;
this.SuspendLayout();
PB.Location = new Point( PB.Location.X, PB.Location.Y - 2);
Cursor.Position = new Point(MP.X, MP.Y - 2);
this.ResumeLayout();
}
private void pictureBox1_MouseLeave(object sender, EventArgs e)
{
PictureBox PB = (PictureBox)sender;
Point MP = Cursor.Position;
this.SuspendLayout();
PB.Location = new Point( PB.Location.X, PB.Location.Y + 2);
Cursor.Position = new Point(MP.X, MP.Y + 2);
this.ResumeLayout();
}
So I am trying to make a drag and drop application that drags something on a panel. I did it before and I have forgot the code that I used for it. I would also like it to have an event too. Here is an example that failed to work:
private void pictureBox1_Click(object sender, EventArgs e)
{
PictureBox flower1 = new PictureBox();
flower1.Image = pictureBox1.Image;
flower1.Location = new Point(panel1.Location.X, panel1.Location.Y);
flower1.Width = 100;
this.Controls.Add(flower1);
flower1.MouseDown += new MouseEventHandler(flower1_MouseDown);
}
void flower1_MouseDown(object sender, MouseEventArgs e)
{
//flower1.Location = new Point(MousePosition.X, MousePosition.Y);
}
I wanted me to click on a flower, then it would be placed onto the panel then, if the mouse is clicked over that control duplicated onto the panel, then make the location the mouse cursors location. How would I go about doing any of this? It does not even appear to duplicate.
EDIT: Just realised that the image is underneath the panel making it not able to be seen. That's one issue, now how do I get it to drag and drop?
private void pictureBox1_Click(object sender, EventArgs e)
{
PictureBox flower1 = new PictureBox();
flower1.Image = pictureBox1.Image;
flower1.Location = Point.Empty;
flower1.Width = 100;
flower1.Parent = panel1;
flower1.MouseDown += new MouseEventHandler(flower1_MouseDown);
}
Im trying to integrate a toolwindow in a Winforms application, it will be a tiny floating window to display element details in a listbox. What I need is pop the window in a relative position to the control that triggers the action, so here is the thing: the Location property gives me the relative position of the control from its container (the main form in this case) so this is the workaround im using:
public void Show(kTextBox source)
{
Point absCoord = source.PointToScreen(source.Location);
this.Location = this.PointToClient(absCoord);
base.Show();
}
Basically this is: get the absolute control position and set this position (previously converted into owner relative) to the toolwindow. I think it should work just fine but is missing for a certain degree, and it varies depending what control i use. Its kinda confusing. Been there anyone?? Thanks in advance.
What happens if you try the following:
public void Show(kTextBox source)
{
Point control_origin = source.PointToScreen(new Point(0, 0));
this.Location = new Point(control_origin.X, control_origin.Y);
base.Show();
}
private void button1_Click(object sender, EventArgs e)
{
ToolStripDropDown popup = new ToolStripDropDown();
popup.Margin = Padding.Empty;
popup.Padding = Padding.Empty;
ToolStripControlHost host = new ToolStripControlHost(frm);
host.Margin = Padding.Empty;
host.Padding = Padding.Empty;
popup.Items.Add(host);
popup.Show(button1, button1.Left - 10, button1.Top + (int)(button1.Height / 2));
}
Form2 frm = new Form2();
private void Form1_Load(object sender, EventArgs e)
{
frm.TopLevel = false;
}
}