Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Drop list GUI problem


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 newbie123   Members   -  Reputation: 100

Like
0Likes
Like

Posted 02 September 2011 - 04:54 PM

Hello everybody
i have been working for the past two days on a GUI for SFML that i want to put in my Tile based map editor, and maybe make a tutorial on how to make your own GUI in SFML, (You know share the love xD).

anyways i'm having a problem with the implementation of the drop list. now what i have is the following:-
2 images one show Up arrow and one show Down arrow, both are in the same x,y position.

now there is a boolean called Clicked which is set to false, and when its set to false the Up arrow image is drawn.

when you click the mouse on the drop list the variable Clicked = true and the down arrow image get drawn.

finally when you click again and variable Clicked==true, another boolean called Clicked_Again = true, and when its true the up image get drawn again.

but the problem is when you click the first time the down arrow image get drawn but when you try to click again the up arrow image doesn't get drawn.

#include <SFML/Graphics.hpp>

class Drop_List
{
public:
    Drop_List(void);
    ~Drop_List(void);
    void Init(sf::RenderWindow &window);
    void LoadFile();
    void Handle_Events(sf::Event &Event);
    void Draw(sf::RenderWindow &window);

private:
    int MouseX, MouseY,
        ImageX, ImageY,
        ImageSizeX, ImageSizeY;

    bool Clicked, Clicked_Again, Hover, NotClicked;
    sf::Image Image_Up, Image_Down;
    sf::Sprite Sprite_Up, Sprite_Down;
};


#include "Drop_List.h"

Drop_List::Drop_List(void)
{
    Clicked=false;
    Clicked_Again=false;
}


Drop_List::~Drop_List(void)
{
}

void Drop_List::Init(sf::RenderWindow &window)
{
    MouseX = window.GetInput().GetMouseX();
    MouseY = window.GetInput().GetMouseY();

    ImageX = Sprite_Up.GetPosition().x;
    ImageY = Sprite_Up.GetPosition().y;

    ImageSizeX = Sprite_Up.GetSize().x;
    ImageSizeY = Sprite_Up.GetSize().y;
}

void Drop_List::LoadFile()
{
    Image_Up.LoadFromFile("DropList_UP.png");
    Image_Down.LoadFromFile("DropList_Down.png");

    Sprite_Up.SetPosition(200,200);
    Sprite_Down.SetPosition(200,200);

    Sprite_Up.SetImage(Image_Up);
    Sprite_Down.SetImage(Image_Down);
}

void Drop_List::Handle_Events(sf::Event &Event)
{
    for(int ButtonX=ImageX; ButtonX<=ImageX + ImageSizeX; ButtonX++)
    {
        for(int ButtonY=ImageY; ButtonY<=ImageY + ImageSizeY; ButtonY++)
        {
            
            if(MouseX==ButtonX && MouseY==ButtonY && Event.Type == sf::Event::MouseButtonPressed && Event.MouseButton.Button == sf::Mouse::Left)
            {
   	         Clicked=true;
            }
   	         
            if(MouseX==ButtonX && MouseY==ButtonY && Event.Type == sf::Event::MouseButtonPressed && Event.MouseButton.Button == sf::Mouse::Left && Clicked==true)
            {
   	         Clicked_Again=true;
            }
        }
    }
}

void Drop_List::Draw(sf::RenderWindow &window)
{
    if(Clicked==false)
        window.Draw(Sprite_Up);
    
    if(Clicked==true)
    {
        window.Draw(Sprite_Down);
    }
    
    else if(Clicked_Again==true)
    {
        window.Draw(Sprite_Up);
        Clicked_Again=false;
    }
}

#include <SFML/Graphics.hpp>
#include "Drop_List.h"

int main()
{
    Drop_List Drop_List;
    
    sf::RenderWindow window(sf::VideoMode(800,600,32),"test");

    Drop_List.LoadFile();
    
    
    while(window.IsOpened())
    {
        sf::Event Event;
        while(window.GetEvent(Event))
        {
            Drop_List.Handle_Events(Event);
        }

        Drop_List.Init(window);

        window.Clear();
        Drop_List.Draw(window);
        window.Display();

    }
    return 0;
}



Sponsor:

#2 newbie123   Members   -  Reputation: 100

Like
0Likes
Like

Posted 02 September 2011 - 06:52 PM

guys any help please ? :unsure:

#3 ApochPiQ   Moderators   -  Reputation: 18040

Like
0Likes
Like

Posted 02 September 2011 - 06:54 PM

It's been two hours... be patient :-)

#4 Dragonsoulj   Crossbones+   -  Reputation: 2642

Like
0Likes
Like

Posted 02 September 2011 - 07:23 PM

So if I understood you correctly, you want to be able to click an arrow and have it change to another arrow, then you click it again and it changes back. If that is correct, you shouldn't need the clicked_again option. For the if statement in handle events, instead of setting clicked_again to true, just set clicked to false. Then the draw command will flip back the arrow. Make sense?

#5 newbie123   Members   -  Reputation: 100

Like
0Likes
Like

Posted 02 September 2011 - 07:40 PM

So if I understood you correctly, you want to be able to click an arrow and have it change to another arrow, then you click it again and it changes back. If that is correct, you shouldn't need the clicked_again option. For the if statement in handle events, instead of setting clicked_again to true, just set clicked to false. Then the draw command will flip back the arrow. Make sense?


i tried that but it didnt work. i have spent the past 2 hours trying to fix it but it didnt work.


void Drop_List::Handle_Events(sf::Event &Event)
{
	for(int ButtonX=ImageX; ButtonX<=ImageX + ImageSizeX; ButtonX++)
	{
		for(int ButtonY=ImageY; ButtonY<=ImageY + ImageSizeY; ButtonY++)
		{
			
			if(MouseX==ButtonX && MouseY==ButtonY && Event.Type == sf::Event::MouseButtonPressed && Event.MouseButton.Button == sf::Mouse::Left)
			{
				Clicked=true;
			}
			
			else if(MouseX==ButtonX && MouseY==ButtonY && Event.Type == sf::Event::MouseButtonPressed && Event.MouseButton.Button == sf::Mouse::Left && Clicked==true)
			{
				Clicked=false;
			}
		}
	}
}

void Drop_List::Draw(sf::RenderWindow &window)
{
	if(Clicked==false)
		window.Draw(Sprite_Up);
	
	if(Clicked==true)
	{
		window.Draw(Sprite_Down);
	}

}

when i do that, i click on the drop list and the arrow will change from Up to Down but then when i click it again it doesnt change from down to up, it stays down

#6 Megahertz   Members   -  Reputation: 285

Like
1Likes
Like

Posted 02 September 2011 - 08:16 PM

Have you tried setting a break point and stepping through the code?

If you can understand where the logic is going bad, you can then figure out how to fix it. =)
-=[Megahertz]=-

#7 aregee   Members   -  Reputation: 1066

Like
1Likes
Like

Posted 02 September 2011 - 09:02 PM

It seems you are scanning each row and column of your image to test if the mouse button was clicked there. A better way of finding out whether your mouse pointer was clicked inside the image or not is to test against the borders of your image. It is easily done doing a test like this:

(Given screen coordinates starting with (0, 0) at the top left corner.)

Be warned that I am basing this on some assumptions on your code. I don't know anything about the parameters in the first 'if' test for instance. I am just assuming it is correct. I hope at least it will give you some ideas.


//To test if the left button was clicked at all

if (!(Event.Type == sf::Event::MouseButtonPressed && Event.MouseButton.Button == sf::Mouse::Left))
{
	// Left button was not clicked, so we do not need any more testing
	return;
}

// The left mouse button was clicked,
// Now test if the click was inside the image

int LeftEdge = ImageX;
int RightEdge = ImageX + ImageSizeX;
int TopEdge = ImageY;
int BottomEdge = ImageY + ImageSizeY;

if ((MouseX >= LeftEdge) && (MouseX <= RightEdge))
{
	if ((MouseY >= TopEdge) && (MouseY <= BottomEdge))
	{
		// Here you know that the mouse click was positioned within the image

		// To toggle the state of the image:
		if (Clicked) 
		{
			Clicked = false;
		}
		else
		{
			Clicked = true;
		}
	}
}


I believe that the code above should work, if I understood your code correctly. Hope it is of some help as I am making quite a bit of guessing myself. :)

Edit: I changed ButtonX and Y to MouseX and Y as the latter is what I assume is giving you the mouse coordinates.

#8 Serapth   Crossbones+   -  Reputation: 6186

Like
0Likes
Like

Posted 02 September 2011 - 09:05 PM

This should do what you want. It's verbose on purpose.

Drop_List.cpp:

#include "stdafx.h"
#include "Drop_List.h"

Drop_List::Drop_List(void)
{
	_open = false;
	_clickCount = 0;
}


Drop_List::~Drop_List(void)
{
}

void Drop_List::Init(sf::RenderWindow &window)
{
    ImageX = Sprite_Up.GetPosition().x;
    ImageY = Sprite_Up.GetPosition().y;

    ImageSizeX = Sprite_Up.GetSize().x;
    ImageSizeY = Sprite_Up.GetSize().y;
}

void Drop_List::LoadFile()
{
    Image_Up.LoadFromFile("DropList_UP.png");
    Image_Down.LoadFromFile("DropList_Down.png");

    Sprite_Up.SetPosition(200,200);
    Sprite_Down.SetPosition(200,200);

    Sprite_Up.SetImage(Image_Up);
    Sprite_Down.SetImage(Image_Down);
}

void Drop_List::Handle_Events(sf::Event &eventToHandle)
{
	if(eventToHandle.Type == sf::Event::MouseButtonPressed)
	{
		if(eventToHandle.MouseButton.Button == sf::Mouse::Button::Left)
		{
			int clickX = eventToHandle.MouseButton.X;
			int clickY = eventToHandle.MouseButton.Y;

			sf::Vector2f rectSize = Sprite_Up.GetSize();
			float width = rectSize.x;
			float height = rectSize.y;

			sf::Vector2f topLeft = Sprite_Up.GetPosition();
			
			sf::Vector2f bottomRight;
			bottomRight.x = Sprite_Up.GetPosition().x + width;
			bottomRight.y = Sprite_Up.GetPosition().y + height;

			

			if( ( ( clickX > topLeft.x) && (clickX < bottomRight.x) )
				&& ( (clickY > topLeft.y ) && (clickY < bottomRight.y ) ))
			
			{
				if(_open)
				{
					//close
					_clickCount = 0;
					_open = false;
				}
				else
				{
					if(_clickCount == 0)
						_clickCount ++;
					else
						_open = true;
				}
			}
		}
	}
}


void Drop_List::Draw(sf::RenderWindow &window)
{
    if(_open)
        window.Draw(Sprite_Up);
	else
    {
        window.Draw(Sprite_Down);
    }
}


Drop_List.h:

#pragma once
#include <SFML/Graphics.hpp>

class Drop_List
{
public:
    Drop_List(void);
    ~Drop_List(void);
    void Init(sf::RenderWindow &window);
    void LoadFile();
    void Handle_Events(sf::Event &Event);
    void Draw(sf::RenderWindow &window);

private:
    int MouseX, MouseY,
        ImageX, ImageY,
        ImageSizeX, ImageSizeY;

    bool _open;
	int _clickCount;

    sf::Image Image_Up, Image_Down;
    sf::Sprite Sprite_Up, Sprite_Down;
};




I've made parts of your code redundant ( for example Init() and all the variables contained within ) that I haven't bothered removing, but the effect should be what you want.

#9 thePyro_13   Members   -  Reputation: 629

Like
0Likes
Like

Posted 02 September 2011 - 10:37 PM

You can use sf::rect<T>.contains(x,y); to simplify the above code and hide all the ugly point comparisons.

In fact using rects and vectors(the points not the containers) will make your code a lot simpler and easier to understand/maintain. SFML implements them both for you, so all you have to do is use them.

#10 Dragonsoulj   Crossbones+   -  Reputation: 2642

Like
0Likes
Like

Posted 02 September 2011 - 10:39 PM

Simple solution. Use only the true false for it and add "Clicked==false" to the first if check in Handle Events. It was changing it and after then it stayed that way.

#11 newbie123   Members   -  Reputation: 100

Like
0Likes
Like

Posted 03 September 2011 - 05:04 AM

It seems you are scanning each row and column of your image to test if the mouse button was clicked there. A better way of finding out whether your mouse pointer was clicked inside the image or not is to test against the borders of your image.


you are correct, i'm scanning for every pixel of the image to see if that pixel was clicked or not. why do you think scanning every pixel is not a good idea ? do you think the software will get slower and the CPU will have more calculations to do ?

and thank you for the code its work perfectly :D

#12 aregee   Members   -  Reputation: 1066

Like
0Likes
Like

Posted 03 September 2011 - 07:11 AM


It seems you are scanning each row and column of your image to test if the mouse button was clicked there. A better way of finding out whether your mouse pointer was clicked inside the image or not is to test against the borders of your image.


you are correct, i'm scanning for every pixel of the image to see if that pixel was clicked or not. why do you think scanning every pixel is not a good idea ? do you think the software will get slower and the CPU will have more calculations to do ?

and thank you for the code its work perfectly :D


Scanning each pixel in the image is bad because it is slow. Maybe not that slow on a small image, but what if your button was like 100x100 in size, or even bigger, or if you have many such small images to check for a button down event. It would take "ages". (Even a couple of hundred millisecond feels like ages in a user interface.) What I did takes the same amount of time regardless of the size of the image.

I am glad my example worked. It was made to give you some ideas of alternative ways to do things. It is not by way the only or best solution at all. I would actually have a look at what Serapth posted just after me. It seems to be a much more elegant solution than mine. :)




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS