tags:

views:

413

answers:

4

I am aware of the MoveWindow() and SetWindowPos() functions. I know how to use them correctly. However, what I am trying to accomplish is move a window slowly and smoothly as if a user is dragging it.

I have yet to get this to work correctly. What I tried was getting the current coordinates with GetWindowRect() and then using the setwindow and movewindow functions, incrementing Right by 10 pixels each call.

Any ideas?

Here is what I had beside all my definitions.

while(1)
{
     GetWindowRect(notepad,&window);

     Sleep(1000);
     SetWindowPos(
        notepad,
        HWND_TOPMOST,
        window.top - 10,
        window.right,
        400,
        400,
        TRUE
        );
}
+2  A: 

A naturally-moving window would accelerate as it started moving, and decelerate as it stopped. The speed vs. time graph would look like a bell curve, or maybe the top of a triangle wave. The triangle wave would be easier to implement.

As you move the box, you need to steadily increase the number of pixels you are moving the box each time through the loop, until you reach the halfway point between point a and point b, at which you will steadily decrease the number of pixels you are moving the box by. There is no special math involved; it is just addition and subtraction.

Robert Harvey
Could you implement that into a snippet of code I could use for reference
that math stuff is a tough sine
kenny
nodave, see my new post below for the code.
Robert Harvey
+4  A: 

If you want smooth animation, you'll need to make it time-based, and allow Windows to process messages in between movements. Set a timer, and respond to WM_TIMER notifications by moving the window a distance based on the elapsed time since your animation started. For natural-looking movement, don't use a linear function for determining the distance - instead, try something like Robert Harvey's suggested function.

Pseudocode:

//
// animate as a function of time - could use something else, but time is nice.
lengthInMS = 10*1000; // ten second animation length
StartAnimation(desiredPos)
{
   originalPos = GetWindowPos();
   startTime = GetTickCount();
   // omitted: hwnd, ID - you'll call SetTimer differently 
   // based on whether or not you have a window of your own
   timerID = SetTimer(30, callback); 
}

callback()
{
   elapsed = GetTickCount()-startTime;
   if ( elapsed >= lengthInMS )
   {
      // done - move to destination and stop animation timer.
      MoveWindow(desiredPos);
      KillTimer(timerID);
   }

   // convert elapsed time into a value between 0 and 1
   pos = elapsed / lengthInMS; 

   // use Harvey's function to provide smooth movement between original 
   // and desired position
   newPos.x = originalPos.x*(1-SmoothMoveELX(pos)) 
                  + desiredPos.x*SmoothMoveELX(pos);
   newPos.y = originalPos.y*(1-SmoothMoveELX(pos)) 
                  + desiredPos.y*SmoothMoveELX(pos);       
   MoveWindow(newPos);
}
Shog9
Do you have an implementation? This seems slightly over my head
@nodave, they have given you everything you need. Make your callback timer function move the window based off the elapsed time and some mathematical function (like the triangle wave or bell curve).
Simucal
@nodave: what Simucal said. Harvey's given you a function, that's really the only non-trival aspect of this project. Follow the links I gave you, learn how timers work, write something up, and if you run into any problems then come back and post another question. I've added a pseudocode example for you though, should give you a rough idea; your exact implementation will depend on the structure of your program.
Shog9
+4  A: 

I found this code which should do what you want. It's in c#, but you should be able to adapt it:

increment a variable between 0 and 1 (lets call it "inc" and make it global) using small increments (.03?) and use the function below to give a smooth motion.

Math goes like this:

currentx=x1*(1-smoothmmoveELX(inc)) + x2*smoothmmoveELX(inc)

currenty=y1*(1-smoothmmoveELX(inc)) + y2*smoothmmoveELX(inc)

Code:

public double SmoothMoveELX(double x) 
{ 
    double PI = Atn(1) * 4;
    return (Cos((1 - x) * PI) + 1) / 2; 
}

http://www.vbforums.com/showthread.php?t=568889

Robert Harvey
A: 

If you are bored enough, you can do loopback VNC to drag the mouse yourself.

Now, as for why you would want to I don't know.

Joshua