Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Doing a drag and drop method  (Read 10237 times)

0 Members and 2 Guests are viewing this topic.

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Doing a drag and drop method
« on: June 14, 2016, 11:28:02 pm »
Hi Folks,

I am trying to implement method that can detect whether a user is holding down the left mouse button, thus indicating that the user is dragging a sprite.

In my event loop, I have this - note some is pseudo code. Basically I am sleeping the program for 100 milliseconds after the a sf::Mouse::Left event is detected. If the mouse is still pressed then I say the user is attempt to drag an icon.

I cannot assume that just having a sf::Mouse::Left indicates that the user is dragging an icon as he could just be left clicking the sprite to select it. If I did then it starts dragging/dropping icons when the user is just trying to select them.

It just seems a bit of an inefficient way to detect whether a user is dragging by adding a sleep. Is there a more efficient method to implement drag/drop, whilst at the same time support left clicking


                        if (event.type == sf::Event::MouseButtonPressed)
                        {
                                //if left button pressed
                                if (event.mouseButton.button == sf::Mouse::Left)
                                {
                                        cout << "left pressed \n";
                                        sf::sleep(sf::milliseconds(100));
                                        if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
                                        {
                                                isDragging = true;
                                                cout << "left pressed and isDragging \n";
                                               
                                                //Here I check if mouse was within the bounds of the sprite and do what I need to do
                                        }
                                }
                        }

 

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Doing a drag and drop method
« Reply #1 on: June 15, 2016, 03:08:51 am »
Is the sleep there to ensure that the button is held rather than just clicked?
You can do this with a clock by testing how long has passed since the left button was first clicked. It would probably be useful to keep track of this state (pre-drag hold) so that you know when the time has passed and the left button is still down (or just simply hasn't yet been released) you can set the "is dragging" flag only if the pre-drag hold state is present.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
AW: Doing a drag and drop method
« Reply #2 on: June 15, 2016, 01:34:44 pm »
IMHO it's easier to track the MouseButtonPressed and MouseButtonReleased event.
Save the initial position when the mouse gets pressed and set a boolean to true. Then in the mouse move event you can check if the boolean is true and if the thing underneath the initial position is dragabble and move the object accordingly.
That way you don't need a timer and don't introduce potential interface lag.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Doing a drag and drop method
« Reply #3 on: June 15, 2016, 08:32:51 pm »
I agree that that way is simpler, eXpl0it3r, but sometimes you want to enforce a delay. One reason is for "drag-clicking" (moving the mouse during a click) which might want to be counted as clicking instead of dragging. The problem with that is more evident with touches than clicks.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Mario

  • SFML Team
  • Hero Member
  • *****
  • Posts: 879
    • View Profile
Re: Doing a drag and drop method
« Reply #4 on: June 15, 2016, 08:36:57 pm »
Hapax: Just enforce a minimum drag distance. This should avoid all "accidential drags".

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Doing a drag and drop method
« Reply #5 on: June 15, 2016, 08:44:09 pm »
That too would work for most cases. However, consider accessibility and possible spasms during a click; the move could be quite drastic in a short time.
The timer would alleviate that problem but is probably very likely to be not required for most applications.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: Doing a drag and drop method
« Reply #6 on: June 15, 2016, 11:02:29 pm »
Is the sleep there to ensure that the button is held rather than just clicked?

Yes that is exactly why the sleep is there. Basically if the left pressed event is triggered then I want to know if the user is still holding the left button. If I don't have that sleep in there then it takes left clicks as dragging attempts and moves the sprite when I just trying to left-click on the sprite.

I don't think I fully understand the timing method that you are describing. Are you able to clarify how the timer would work?

I did make an attempt as below, but it always seemed to be saying the user was dragging, even during a left-click.

So in my class I defined a gameClock

sf::Clock gameClock;
 

Then at the beginning of the event loop, I have this to check if the left button is pressed and if the gameclock elapsed time is > 100 milliseconds. If not then restart the game clock

                        if (sf::Mouse::isButtonPressed(sf::Mouse::Left) && gameClock.getElapsedTime().asMilliseconds() >= 100)
                        {
                                cout << "gameClock.getElapsedTime().asMilliseconds() = " << gameClock.getElapsedTime().asMilliseconds() << "\n";
                                cout << "setting isdragging to true\n";
                                isDragging = true;
                        }
                        else
                        {
                                gameClock.restart();
                        }
 

Now I am not entirely sure if this what you meant as to having a timer?

Then in my events I have more or less the same thing, except no sleep or isButton pressed check anymore.

                        if (event.type == sf::Event::MouseButtonPressed)
                        {
                                //if left button pressed
                                if (event.mouseButton.button == sf::Mouse::Left)
                                {
                                        cout << "left pressed \n";
                                        if (isDragging)
                                        {
                                                //Here I check if mouse was within the bounds of the sprite and if so then do the dragging updates.
                                        }
                                        else if (!isDragging)
                                        {
                                                //Do the stuff I want to do when user is not trying to do a drag and drop
                                        }
                                }
                        }
 

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Doing a drag and drop method
« Reply #7 on: June 17, 2016, 06:05:08 pm »
First thing I'd like to mention is that you shouldn't really be mixing real-time mouse states with mouse events for a number of reason not least the fact that they may not match chronologically.

Second is that it's likely that it's a better option to go with the simpler version mentioned above by Exploiter; it's probably a more common method.

Going with the idea of using that method, you can use events like this:
  • check button down events and store a flag marking it as pressed,
  • check mouse move events and, if the button is marked as pressed, either set a flag to mark that it is now dragging or perform the dragging here directly.
  • check button up events and clear the flag that marks as pressed and the flag that marks as being dragged (if you use one).

I'm suggesting to manually use a flag/boolean to keep track of the pressed/down state of the button since the events could technically be delayed so the real-time state is inaccurate for the actual time of the events.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*