SFML community forums
Help => Graphics => Topic started by: LazyLazuli on September 25, 2011, 08:05:33 pm
-
What would be the best way to create a button? Since there doesn't seem to be anything directly included, the only thing I can think of is getting the x and y coordinate of the mouse when it is pressed, and then seeing it is within the range of the coordinates of the image/sprite that I want to use as the button...
-
What would be the best way to create a button? Since there doesn't seem to be anything directly included, the only thing I can think of is getting the x and y coordinate of the mouse when it is pressed, and then seeing it is within the range of the coordinates of the image/sprite that I want to use as the button...
You got it =)
-
darn, I was hoping it would be easier XD
-
darn, I was hoping it would be easier XD
Read the doc of sf::Rect<T> and sf::Sprite. It's not difficult at all.
In fact you just have to check if the mouse (a vector2i) is inside the rect. The function is already written but you have to take a rectangle with the good X (left) and Y (top) coordinates.
-
Im feeling enerous. I just made this yesterday.
class Button {
public:
Button (sf::Image* normal,sf::Image* clicked,std::string,sf::Vector2f location);
void checkClick (sf::Vector2f);
void setState(bool);
void setText(std::string);
bool getVar();
sf::Sprite* getSprite();
sf::String * getText();
private:
sf::Sprite normal;
sf::Sprite clicked;
sf::Sprite* currentSpr;
sf::String String;
bool current;
};
Button::Button(sf::Image* normal,sf::Image* clicked,std::string words,sf::Vector2f location) {
this->normal.SetImage(*normal);
this->clicked.SetImage(*clicked);
this->currentSpr=&this->normal;
current =false;
this->normal.SetPosition(location);
this->clicked.SetPosition(location);
String.SetText(words);
String.SetPosition(location.x+3,location.y+3);
String.SetSize(14);
}
void Button::checkClick (sf::Vector2f mousePos) {
if (mousePos.x>currentSpr->GetPosition().x && mousePos.x<(currentSpr->GetPosition().x + currentSpr->GetSize().x)) {
if(mousePos.y>currentSpr->GetPosition().y && mousePos.y<(currentSpr->GetPosition().y + currentSpr->GetSize().y)) {
setState(!current);
}
}
}
void Button::setState(bool which) {
current = which;
if (current) {
currentSpr=&clicked;
return;
}
currentSpr=&normal;
}
void Button::setText(std::string words) {
String.SetText(words);
}
bool Button::getVar() {
return current;
}
sf::Sprite* Button::getSprite() {
return currentSpr;
}
sf::String * Button::getText() {
return &String;
}
It still needs some work, though.
-
That looks good.
Now, if you want, you can add an action to execute when the button is clicked. This is more complicated.
What I do is to template the whole button class and I add bind and trigger methods.
The template is to for the class that will be called when triggered.
Bind take two parameters, a pointer on T and a functor on one of its method.
I just call it when triggered.
It permit to do bind your button to what you want easily.
-
What I do is to template the whole button class
That's a really bad idea, because then any class or function that works with buttons must be template as well, or know which class it is connected to. It also means that the connection must be known at compile time and cannot be changed during runtime.
You should use (or at least have a look at) std::function/std::bind, or boost::function/boost::bind if your compiler doesn't support the next standard. There's boost::signals also, which is a specialization of boost::function for signals/slots.
-
What I do is to template the whole button class
That's a really bad idea, because then any class or function that works with buttons must be template as well, or know which class it is connected to. It also means that the connection must be known at compile time and cannot be changed during runtime
I don't have that kind of problems. Containers classes of buttons are not templated and I know which class it's connected to.
But I never had to change the connection during runtime, I don't really see what's the point ?
Anyway, I'm interested in bosst solution since I wan't to re-design my UI.
-
I don't have that kind of problems.
Don't you write functions that work with buttons? Instead of
void DoSomething(Button& b);
you have to write
template <typename T>
void DoSomething(Button<T>& b);
and move the whole implementation and all its dependencies into the header.
Containers classes of buttons are not templated
How can you have a container of buttons with different triggers? Or even with one trigger, the container needs to know this type, too. That's often an unnecessary dependency.
But I never had to change the connection during runtime, I don't really see what's the point ?
You get more flexibility. For example, you can associate a new function at runtime. And generally, you can link multiple listeners to the button click, not just one.
-
You get more flexibility. For example, you can associate a new function at runtime. And generally, you can link multiple listeners to the button click, not just one.
That's a very good point.
And yes I have to template each button method in the header file.
I've read a little more about binds and callbacks, that's very interesting =)
-
Now, if you want, you can add an action to execute when the button is clicked. This is more complicated.
Id rather not do that. I just check the variable when ever I want to do something. This button is actually an on/off button, not a click and do something button.(does tht make sense?)
-
This button is actually an on/off button, not a click and do something button.(does tht make sense?)
Then it is rather a checkbox than a button. And it can still make sense to connect the click with actions, even if these actions only consist of setting a variable to true/false.