Witam, staram się stworzyć kilka projektów przy pomocy SFML i postanowiłem skupić się na czymś, co ułatwi mi pracę w przyszłości - edytor GUI. Na początek stworzyłem klasy przycisków. Zawiera ona metody takie jak: sprawdzenie czy kursor znajduje się w obrębie przycisku, sprawdzenie czy przycisk został przyciśnięty, oraz czy został kliknięty. Całość działa, mam jednak problem z umiejscowieniem metody aktualizacji logiki przycisku. Na początek potrzebne pliki (nie są długie, wyciąłem z nich zbędne dla tematu klasy) :
gui.h :
https://pastebin.com/XuvJ9Ctzgui.cpp :
https://pastebin.com/wsSZamYFmain.cpp :
https://pastebin.com/FXz3p30XA to najważniejsze metody przycisku (pominąłem ten sprawdzający, czy kursor jest w jego obrębie):
void RectangularButton::update( sf::Event action ) {
checkIfPressed( action );
checkIfClicked( action );
}
void RectangularButton::checkIfPressed( sf::Event action ) {
if( isMouseOver() && action.type == sf::Event::MouseButtonPressed && action.mouseButton.button == sf::Mouse::Left )
pressed = true;
}
void RectangularButton::checkIfClicked( sf::Event action ) {
if( pressed ) {
if( isMouseOver() && action.type == sf::Event::MouseButtonReleased && action.mouseButton.button == sf::Mouse::Left ) {
clicked = true;
pressed = false;
}
else if( action.type == sf::Event::MouseButtonReleased && action.mouseButton.button == sf::Mouse::Left )
pressed = false;
}
else clicked = false;
}
Oto pętla główna programu:
int main() {
sf::RenderWindow mainWindow( sf::VideoMode( 800, 600, 32 ), "Test GUI" );
sf::Event action;
RectangularButton button( & mainWindow, sf::Vector2f( 250.f, 125.f ), sf::Vector2f( 275.f, 290.f ), 3 );
while( mainWindow.isOpen() ) {
while( mainWindow.pollEvent( action ) ) {
if( action.type == sf::Event::Closed ) mainWindow.close();
button.update( action );
}
std::cout << "Przycisniety: " << button.isPressed() << std::endl;
std::cout << "Klikniety: " << button.isClicked() << std::endl;
mainWindow.clear();
system( "cls" );
button.draw();
mainWindow.display();
}
return 0;
}
Chodzi o moment obsługi klawiatury i myszki. Z tego co zrozumiałem wszystkie eventy myszki i klawiatury wrzucane są na pewien stos, gdzie ostatni event jest na jego szczycie.
mainWindow.pollEvent(action) ma służyć do wyciągania tego eventu i przypisanie go do action.
Dobra i teraz pojawia się problem. Są dwa scenariusze.
1. Daję
przycisk.update(sf::Event) poza pętlą wyciągającą wszystkie eventy z danego obrotu programu. Dzięki temu logika aktualizowana jest zawsze. Problem jednak występuje gdy użytkownik zacznie wciskać wiele przycisków w tym samym czasie. Np. "A", "LPM" i "Spacja" (i mimo, że wydarzyły się w tym samym obrocie programu, zostaną wrzucone do stosu w określonej kolejności). Pętla przejdzie przez wszystkie eventy ale po wyjściu z pętli tylko ostatni zostanie w action. Przycisk uzna, że nie został przyciśnięty (bo użyto spacji) mimo, że użytkownik użył na nim LPM.
2. Daję
przycisk.update(sf::Event) do pętli wyciągającą wszystkie eventy z danego obrotu programu. Nie ma tu możliwości błędu. Nawet jak użytkownik wciśnie na raz 3 przyciski,
przycisk.update(sf::Event) wykona się dla każdego z nich. Brzmi pięknie, jaki jest problem? Przy odpowiednich okolicznościach aktualizacja może nie nastąpić w danym obrocie. Kiedy? Otóż kiedy nie nastąpi żaden event
mainWindow.pollEvent(action) zwraca false, czyli pętla while się nie wykona - nie wykona się
przycisk.update(sf::Event). Wyobraźcie sobie taką sytuację. Użytkownik wciska przycisk i zwalnia LPM. Clicked przyjmuje wartość true. Użytkownik po zwolnieniu przycisku
niczego nie dotyka. Nie następuje event. Nie wykonuje się
przycisk.update(sf::Event), wartość nie może zmienić się na false tak jak powinna, zamist tego trwa ciągle przy true.
Czy ktoś ma pomysł na rozwiązanie tego problemu? Jak powinienem umiejscowić
przycisk.update(sf::Event), żeby wszytko działało? Za wszystkie odpowiedzi z góry dziękuję.