How to prevent a trackbar from moving, in only one direction? - c#

I'm currently working on a quite simple Windows Form program and I currently have a small issue regarding trackbars.
It's kind of a stats distributor for characters so I have 6 trackbars which should allow the user to distribute a set amount of point to each stats of the said character. They have a common maximum of points they can distribute so I check and confirm when they reach the max ammmount of points they could distribute but here's the problem, I don't know how to prevent the cursor to ONLY go up. I know I can disable the trackbars completely but then the user can't adjust the amounts of points even if he only wanted to lower a value to adjust it. How can I stop them from adding point without disabling the trackbars completely?

You can handle the ValueChanged event handler and do something like this:
int lastValue;
//ValueChanged event handler for your trackBar1
private void trackBar1_ValueChanged(object sender, EventArgs e){
if (trackBar1.Value < lastValue) trackBar1.Value = lastValue;
lastValue = trackBar1.Value;
}

Related

Smooth zoom in WPF

So here is my questions that I hope I will be able to ask it in a proper way.
In brief: how to zoom smoothly in WPF?
In detail: I'm writing a CAD application in WPF that I'm redrawing parts of the screen when MouseWheel event is fired.
private void ModelWindowBorder_MouseWheel(object sender, MouseWheelEventArgs e)
{
var zoom = e.Delta > 0 ? 0.2 : -0.2;
// increase or decrease the scale by *zoom*
// Redraw Screen
// Apply TransformScale and etc.
}
Well actually the above code works but I'm not content with it for two reasons:
When I have to redraw lots of visuals on the screen it kinda misses the multiple MouseWheel events that are fired. So if 8 MouseWheel events are to be fired in one big scroll only 4-5 of them are fired. And this makes the zooming a little slow.
The second reason might not be WPF related at all. Is var zoom = e.Delta > 0 ? 0.2 : -0.2; the correct way we should increase/decrease the scale? To me it seems not appropriate. Since when we are zoomed out the difference seems considerable when we zoom in by one step, but once we are close to the drawing, increasing the zoom by one step doesn't seem much.
I'd like to know your answers and comments on both of these issues.
Problem 1.
You should take in account the value of e.Delta.
Not
var zoom = e.Delta > 0 ? 0.2 : -0.2;
but
var zoom = e.Delta * k;
k is a double factor, it's device specific
The effective upper and lower ranges of this value potentially come from device implementations or other callers that raised the event, and are therefore not defined
But its value get higher for as you say one big scroll.
One possible solution to find k would be to get first MouseWheel event and use received value as a starting point. If you receive double of that value, then two or more of mousewheel scrolls were combined into single event. Or do calibration all time, remembering smallest value and changing factor for it. Up to you.
Problem 2.
Use multiplication instead of adding flat value.
And combined solution will looks like this
st.ScaleX *= e.Delta * k;
One simple thing to try and coelesce MouseWheel events is to use Rx. You can use the .FromEventPattern() method to consume Wheel events and only care about those that satisfy your delta tolerances. Rx is a little tricky but can help you have simpler code paths.
See this answer - Detect scroll is completed with PointerWheelChanged

Prevent mouse from leaving my form

I've attached some MouseMove and MouseClick events to my program and next up is one of these:
Get "global" mouse movement, so that I can read the mouse location even outside the form.
Prevent my mouse from leaving the form in the first place.
My project is a game so it'd be awesome to prevent the mouse leaving my form like most other games do (ofc. you can move it out if you switch focus with alt+tab fe.) and taking a look at answers to other questions asking for global mosue movement, they seem pretty messy for my needs.
Is there an easy way to prevent my mouse from going outside my form's borders? Or actually to prevent it from going OVER the borders in the first place, I want the mouse to stay inside the client area.
Additional info about the game:
The game is a short, 5-30 seconds long survival game (it gets too hard after 30 seconds for you to stay alive) where you have to dodge bullets with your mouse. It's really annoying when you move your mouse out of the form and then the player (System.Windows.Forms.Panel attached to mouse) stops moving and instantly gets hit by a bullet. This is why preventing mouse from leaving the area would be good.
Late answer but might come in handy. You could subscribe the form to MouseLeave and MouseMove events and handle them like this :
private int X = 0;
private int Y = 0;
private void Form1_MouseLeave(object sender, EventArgs e)
{
Cursor.Position = new Point(X, Y);
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (Cursor.Position.X < this.Bounds.X + 50 )
X = Cursor.Position.X + 20;
else
X = Cursor.Position.X - 20;
if (Cursor.Position.Y < this.Bounds.Y + 50)
Y = Cursor.Position.Y + 20;
else
Y = Cursor.Position.Y - 20;
}
The above will make sure the mouse cursor never leaves the bounds of the form. Make sure you unsubscribe the events when the game is finished.
Edit :
Hans Passants's answer makes more sense than my answer. Use Cursor.Clip on MouseEnter :
private void Form1_MouseEnter(object sender, EventArgs e)
{
Cursor.Clip = this.Bounds;
}
You could free the cursor in case of any error/crash (I'm sure you could catch'em) :
Cursor.Clip = Rectangle.Empty;
You cannot trap the mouse, that would prevent the user from, say, operating the Start menu. Closest you can get is assigning the Cursor.Clip property. But it is easily defeated by the user pressing Ctrl+Esc for example, there is no notification for this.
Best thing to do is to subscribe the form's Deactivated event, it reliably tells you that the user switched to another program. The Activated event tells you when the user moved back. Of course the user will have few reasons to actually do this when the game score depends on keeping a game object moving. So don't forget to give the user an easy way to pause the game with, say, the Escape key.
I don't know a solution for your exact problem, but I have a completely different idea for you. I don't know how your game works, but based on what you told me, why not make it a step harder: Add borders to the game-area, for example 4 pixels wide rectangles, which you are not allowed to touch. If you touch them, you die and the mouse gets released.
You can use the Cursor class. For example:
int X = Cursor.Position.X;
int Y = Cursor.Position.Y;
As for preventing the user to move the mouse outside the form, the best approach would probably be if you had someway to know what is the coordinates of your form on the screen and attach a MouseMove event, and check if the mouse is inside the form rectangle.
To know the form position on the screen take a look at this question.
I wouldn't recommend the global mouse movement control for two reasons.
It's bad design, you should respect the bounds of the operating system. Make the application full screen if you want this kind of behaviour. The only applications that should perform these kind of operations are "kiosk" mode applications which lock down the entire OS (to prevent operator abuse).
Global key hooks are messy, aren't guaranteed to work and are dangerous because they affect a key part of the operating system (all controls). A bug in your code could result in requiring a reboot on the machine.
That said, last time I checked (a while ago, on Vista) SetWindowsHookEx still works (but its not officially supported IIRC), it's an unmanaged call so you'll have to pinvoke but with it you can refuse to pass on messages that would move the mouse outside of the bounds of your application. I'm not 100% sure if the OS will let you beat it to the cursor control (I've only blocked keyboards before on desktop boxes) but its probably your best shot.

Double click timer event

I am developing an application that maps users eye movements with the cursor movements, hence developing ahands free cursor control system.
I am using Open CV library's .NET Wrapper for C# i.e. Emgu CV for development.
I am stuck at a point where I want to open a file/folder such that when a cursor is placed over a file/folder for say 3 to 5 seconds, the file/folder should open up or just perform a double-click event of a conventional mouse.
What could I use so as to solve this problem?
Timer timer = new System.Timers.Timer(5000);//5 seconds
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
private void form_MouseHover(object sender, System.EventArgs e)
{
timer.Start();
}
private void form_MouseLeave(object sender, System.EventArgs e)
{
timer.Stop();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
timer.Stop();
OpenFileOrFolder();//Edit : implement your file / folder opening logic here
}
I guess you need to break it down:
Detect when the mouse moves or hovers
Send a double click
For 1, I'd be looking at: capturing WM_MOUSEMOVE if you want your own definition of 'hovering'. For example, having a greater threshold for how much movement you'll tolerate and still consider it a 'hover'. Or, you could use the OS defined threshold and look for WM_MOUSEHOVER
For 2, SendInput should get you there
I'm assuming here, you don't actually care what's under the mouse per-se. As in, you're not going to do different behavior depending on what's under the mouse. For example, you'd send the double click when hovering over the titlebar, as well as if you were hovering over the file.
This article on project builds up a Spy++ style app, which should help.
Are you mapping eye control to the mouse pointer? The MouseHover event may be useful:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.mousehover.aspx
As well as MouseEnter, MouseLeave, etc.
If you're controlling a separate element (i.e., not the mouse) with the eyes, then I had to do something similar in WPF. It ultimately came down to mapping control coordinates to mouse location, counting the time within the bounds of that control, then calling the mouse click event handler.

Is there a clean way that I can capture when a user left clicks and then drags the mouse?

I am trying to make it so that the user can scroll a richtextbox by clicking the window the richtexbox is on and dragging the mouse. Unfortunately I haven't gotten very far:
private void Main_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
}
}
I've seen some suggestions on the web to track the last several x,y coordinates of the mouse and compare them to the x,y coordinates each time the mouse move event is triggered. Is there any less messy way to do this?
None that I know of. Unless you're using an API that handles it for you, you have to keep track of the information manually. And even if you did use an API just for mouse drags, it'd do the storing itself and likely just pass back the current X and Y, and the difference in X and Y, since the API wouldn't know what you want done with the information.
You'd be handling a little bit less information, but saving only about 5 lines or so of code to get the same result.

mouse followed drawing in C#

I want to to make a shared drawing board in C#. This means that two people connected via a TCP connection can draw on this board. The idea (for now) is that people can click on the screen and draw. What do you think is the best method for this?
It's easy enough to draw a dot when the user clicks on a certain spot, but it gets a little more complicated when the user drags the mouse, where you need to draw a line between the last point and the current. Also that doesn't work so well, so I draw a dot where the line starts to improve things a bit, but it's not that good.
Lastly, I need to also send this over TCP, so I need to distinguish between the two. I hoped that I could just send points and have it draw it on the other side, but it seems it wouldn't work. Any ideas except also sending the type?
drawing http://img193.imageshack.us/img193/9697/drawingw.png
EDIT:
ok, I'm going with a IDrawingArgument interface that has Dispatch(myForm), and basically does double dispatch, so it solves the TCP problem (going to serialize/deserialize it).
Lines are still a bit bulky.
One little tip... on your mousemove event. keep a flag that wont fire the event again until the last event that set the flag turns it off. i.e.:
bool isDrawing = false;
public void myCanvas_MouseMove(object sender, EventArgs e)
{
if(!isDrawing)
{
isDrawing = true;
// Do drawing here
isDrawing = false;
}
}
This helped me a lot when doing drawing in a mousemove event.
Dots:
(x,y),(x2,y2),(x3,y3)
Lines:
(x,y,x2,y2),(x3,y3,x4,y4)
Thus, the format is a list of tuples. Tuples of size 4 are lines, of size 2 are points. Note that if your system gets more complicated, you'll really regret not just doing something like:
Dots:
D(x,y),D(x2,y2),D(x3,y3)
Lines:
L(x,y,x2,y2),L(x3,y3,x4,y4)

Categories

Resources