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

Author Topic: Drawing a click and drag rectangle?  (Read 13606 times)

0 Members and 1 Guest are viewing this topic.

Hawkpath

  • Newbie
  • *
  • Posts: 4
    • View Profile
Drawing a click and drag rectangle?
« on: January 14, 2011, 02:22:08 am »
Hey, I would like to draw a rectangle that resizes when the user move the mouse. Like when you click and drag on a desktop. I tried doing it with this code:

Code: [Select]
 while(drag){
                    while(StartWindow.GetEvent(Event)){

                        sf::Vector2f coords = StartWindow.ConvertCoords(StartWindow.GetInput().GetMouseX(),StartWindow.GetInput().GetMouseY());
                        x2 = coords.x;
                        y2 = coords.y;
                        rectangle = sf::Shape::Rectangle(x,y,x2,y2,sf::Color::Blue,1,sf::Color::Red);
                        StartWindow.SetView(StartWindow.GetDefaultView());
                        rectangle.SetPosition(x,y);
                         StartWindow.Draw(rectangle);
}


This code is pretty incomplete, but its supposed to make a drag-able rectangle selection tool. This does draw the rectangle, but not where the the user clicks. Can anyone help me with this code, or suggest some new code? Thanks.

[/code]

model76

  • Full Member
  • ***
  • Posts: 231
    • View Profile
Drawing a click and drag rectangle?
« Reply #1 on: January 14, 2011, 03:28:15 am »
I didn't really look too deeply at your code, because I didn't really get your logic at first glance. Why "while(drag)"?

Also, you already stated that it wasn't complete.

Anyway, I felt in the mood, and went and created a small program that does what you asked for:
Code: [Select]
#include <SFML/Graphics.hpp>

int main()
{
    // Initialization
    sf::RenderWindow window( sf::VideoMode( 800, 600 ), "DragBox" );
    const sf::Input &input = window.GetInput();

    sf::Vector2i mouseDownPosition;

    // Program loop
    while( window.IsOpened() )
    {
        // Event handling
        sf::Event event;
        while( window.GetEvent( event ) )
        {
            if( event.Type == sf::Event::Closed )
                window.Close();
            else if( event.Type == sf::Event::MouseButtonPressed &&
                     event.MouseButton.Button == sf::Mouse::Left )
            {
                mouseDownPosition.x = event.MouseButton.X;
                mouseDownPosition.y = event.MouseButton.Y;
            }
        }

        // Drawing
        window.Clear();

        if( input.IsMouseButtonDown( sf::Mouse::Left ) )
        {
            sf::Shape box = sf::Shape::Rectangle( mouseDownPosition.x, mouseDownPosition.y,
                                                  input.GetMouseX(), input.GetMouseY(),
                                                  sf::Color( 0, 0, 0, 0 ), -1.f, sf::Color::Yellow );
            window.Draw( box );
        }

        window.Display();
    }
}


Another time, it is a good idea to post a minimal and complete example that demonstrates your problem. ;)

Hawkpath

  • Newbie
  • *
  • Posts: 4
    • View Profile
Solved
« Reply #2 on: January 14, 2011, 03:35:23 am »
Thank you so much!! It turned out that I was defining the rectangle, then setting the position when I didn't need to set the position. Thanks!

Grimshaw

  • Hero Member
  • *****
  • Posts: 631
  • Nephilim SDK
    • View Profile
Drawing a click and drag rectangle?
« Reply #3 on: January 14, 2011, 03:50:03 am »
Question, when you do that, creating a new sf::Shape, does it delete the previous from memory ? or does it leave a memory leak?

model76

  • Full Member
  • ***
  • Posts: 231
    • View Profile
Drawing a click and drag rectangle?
« Reply #4 on: January 14, 2011, 05:23:22 am »
No, the variable dies when it goes out of scope, so there is no memory leak.

Had it been created with
Code: [Select]
sf::Shape *box = new sf::Shape::Rectangle( ... );it would stay in memory until deleted as:
Code: [Select]
delete box;

Kain5056

  • Newbie
  • *
  • Posts: 26
    • View Profile
Re: Drawing a click and drag rectangle?
« Reply #5 on: August 25, 2014, 12:54:26 pm »
Hi, I'm trying to do the same thing in SFML 2.1, but I'm having some trouble. I only get a square that disappears when I move the mouse.

This is my current code (based on model76's code):

#include <SFML/Graphics.hpp>

int main(int argc , char * argv[] )
{
    const int SCREEN_WIDTH = 640;
    const int SCREEN_HEIGHT = 480;
    const int BITS_PER_PIXEL = 32;

    sf::VideoMode VMode( SCREEN_WIDTH , SCREEN_HEIGHT , BITS_PER_PIXEL );
    sf::RenderWindow window( VMode , "SFML!" , sf::Style::Titlebar | sf::Style::Close );

    sf::Vector2i mouse_position;
    mouse_position = sf::Mouse::getPosition( window );

    while( window.isOpen() )
    {
        sf::Event event;
        while( window.pollEvent( event ) )
        {
            if( event.type == sf::Event::Closed || event.key.code == sf::Keyboard::Escape ) window.close();

            if( event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left )
            {
                mouse_position.x = event.mouseButton.x;
                mouse_position.y = event.mouseButton.y;
            }
        }

        window.clear();

        if( event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left )
        {
            sf::RectangleShape box;
            box.setPosition( mouse_position.x , mouse_position.y );
            box.setSize( sf::Vector2f( sf::Mouse::getPosition().x - mouse_position.x , sf::Mouse::getPosition().y - mouse_position.y ) );
            box.setFillColor( sf::Color::White );
            window.draw( box );
        }

        window.display();
    }
    return 0;
}

Thank you in advance. :-)

BaneTrapper

  • Full Member
  • ***
  • Posts: 213
  • Do you even see this, i dont need it.
    • View Profile
    • Email
Re: Drawing a click and drag rectangle?
« Reply #6 on: August 25, 2014, 01:06:55 pm »
General idea:
When Mouse button left pressed, save position as start position, until Mouse button left released, calculate:
If start position X < mouse X, Draw rectangle from mouse X to start position x else draw from start position X to mouse X
Do same logic for Y axis and you got yourself the math complete now implement it using sfml. Good luck!
BaneTrapperDev@hotmail.com Programing, Coding
Projects: Not in development(unfinished/playable):
http://en.sfml-dev.org/forums/index.php?topic=11073.msg76266#msg76266
UP and in Development: The Wanderer - Lost in time
http://en.sfml-dev.org/forums/index.php?topic=14563.0

Kain5056

  • Newbie
  • *
  • Posts: 26
    • View Profile
Re: Drawing a click and drag rectangle?
« Reply #7 on: August 25, 2014, 01:13:08 pm »
That's exactly what I'm trying to do though.  :-\
Problem is, I can only set x, y and size, instead of x1, x2, y1 and y2.
The only thing I could think of is

box.setSize( sf::Vector2f( sf::Mouse::getPosition().x - mouse_position.x , sf::Mouse::getPosition().y - mouse_position.y ) );

...Where mouse_position is the x and y, but apparently I'm doing something wrong because it does not work at all as intended.

G.

  • Hero Member
  • *****
  • Posts: 1593
    • View Profile
Re: Drawing a click and drag rectangle?
« Reply #8 on: August 25, 2014, 01:58:28 pm »
Never use events outside of the event loop!
Don't forget to give your window to sf::Mouse::getPosition()...
You could change the size of your box inside a MouseMoved event so that it's only modified when the mouse moves.

BaneTrapper

  • Full Member
  • ***
  • Posts: 213
  • Do you even see this, i dont need it.
    • View Profile
    • Email
Re: Drawing a click and drag rectangle?
« Reply #9 on: August 25, 2014, 03:18:21 pm »
Here is a example of how i did it, but if you don't make your own damn copy and rewrite it all... I will me bad  >:(
Code: [Select]
void SetRectangle(sf::Vector2f & startPos, sf::Vector2f & mousePos, sf::RectangleShape & rec)
{
if (mousePos.x < startPos.x && mousePos.y < startPos.y)//Mouse is left up of start, use mouse for x and y
{
rec.setPosition(mousePos.x, mousePos.y);
rec.setSize(sf::Vector2f(startPos.x - mousePos.x, startPos.y - mousePos.y));
}
else if (mousePos.x < startPos.x)//Rectagle is left down of start pos
{
rec.setPosition(mousePos.x, startPos.y);
rec.setSize(sf::Vector2f(startPos.x - mousePos.x, mousePos.y - startPos.y));
}
else if (mousePos.y < startPos.y)//Rectagle is right up of start pos
{
rec.setPosition(startPos.x, mousePos.y);
rec.setSize(sf::Vector2f(mousePos.x - startPos.x, startPos.y - mousePos.y));
}
else//Rectangle is right down, default state
{
rec.setPosition(startPos.x, startPos.y);
rec.setSize(sf::Vector2f(mousePos.x - startPos.x, mousePos.y - startPos.y));
}
}

int main()
{
sf::View view;
view.reset(sf::FloatRect(0, 0, float(800), float(600)));
view.setViewport(sf::FloatRect(0, 0, 1.f, 1.f));


sf::RenderWindow win;
sf::VideoMode vidMod(800, 600, 32);
win.create(vidMod, "test", sf::Style::Default);
win.setFramerateLimit(100);
win.setView(view);

sf::RectangleShape rec;
rec.setFillColor(sf::Color::White);
sf::Vector2f startPos;
sf::Vector2f mousePos;
bool isDrawRectangle = false;

bool done = false;
while (done == false)
{
win.clear();

sf::Event event;
while (win.pollEvent(event))
{
switch (event.type)
{
case sf::Event::Closed:
done = true;
break;
case sf::Event::MouseButtonPressed:
switch (event.mouseButton.button)
{
case sf::Mouse::Button::Left:
isDrawRectangle = true;
startPos = mousePos;
break;
default:
break;
}
break;
case sf::Event::MouseButtonReleased:
switch (event.mouseButton.button)
{
case sf::Mouse::Button::Left:
isDrawRectangle = false;
break;
default:
break;
}
break;
case sf::Event::MouseMoved:
mousePos.x = event.mouseMove.x;
mousePos.y = event.mouseMove.y;
break;
default:
break;
}
}

SetRectangle(startPos, mousePos, rec);
if (isDrawRectangle)
win.draw(rec);

win.display();
}

return 0;
}
BaneTrapperDev@hotmail.com Programing, Coding
Projects: Not in development(unfinished/playable):
http://en.sfml-dev.org/forums/index.php?topic=11073.msg76266#msg76266
UP and in Development: The Wanderer - Lost in time
http://en.sfml-dev.org/forums/index.php?topic=14563.0

Kain5056

  • Newbie
  • *
  • Posts: 26
    • View Profile
Re: Drawing a click and drag rectangle?
« Reply #10 on: August 25, 2014, 04:49:33 pm »
Thanks for the help. sf::Event::MouseMoved is what I needed it seems. My code works perfectly now, and I think I can simplify it later, too.  :)

#include <SFML/Graphics.hpp>

int main(int argc , char * argv[] )
{
    const int SCREEN_WIDTH = 640;
    const int SCREEN_HEIGHT = 480;
    const int BITS_PER_PIXEL = 32;

    sf::VideoMode VMode( SCREEN_WIDTH , SCREEN_HEIGHT , BITS_PER_PIXEL );
    sf::RenderWindow window( VMode , "SFML!" , sf::Style::Titlebar | sf::Style::Close );

    sf::Vector2i starting_position;
    starting_position = sf::Mouse::getPosition( window );
    sf::Vector2f current_position;
    sf::RectangleShape box;


    while( window.isOpen() )
    {
        sf::Event event;
        while( window.pollEvent( event ) )
        {
            if( event.type == sf::Event::Closed || event.key.code == sf::Keyboard::Escape ) window.close();

            if( event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left )
            {
                starting_position.x = event.mouseButton.x;
                starting_position.y = event.mouseButton.y;
            }

            if( event.type == sf::Event::MouseMoved && sf::Mouse::isButtonPressed(sf::Mouse::Left) )
            {
                current_position.x = event.mouseMove.x - starting_position.x;
                current_position.y = event.mouseMove.y - starting_position.y;
                box.setSize( current_position );
                box.setPosition( starting_position.x , starting_position.y );
                box.setFillColor( sf::Color::White );
            }
        }

        window.clear();
        window.draw( box );
        window.display();
    }
    return 0;
}

@BaneTrapper Haha, don't worry mate, I never just copy/paste code anyway. Thanks for the example.  ;D