Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++ SFML 2.6.2] Obsługa wielu zdarzeń kursora

Ostatnio zmodyfikowano wczoraj o godz. 19:20
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
[C++ SFML 2.6.2] Obsługa wielu zdarzeń kursora
» 2024-12-20 17:01:28
Witam.
Potrzebuję obsłużyć wiele zdarzeń kursora jednocześnie i nie wiem jak się za to zabrać a męczę się już trochę z tym.
Zdarzenia do obsługi: brak, kliknięcie, podwójne kliknięcie i zaznaczenie. Byłbym wdzięczny za każdą pomoc.

C/C++
sf::Time currentTime;
sf::Time prevTime;

sf::Vector2i mousePosition; // pozycja kursora wzgledem okna
sf::Vector2f worldMousePosition; // globalna pozycja kursora

sf::Time mouse_start_time; // kursor czas start

sf::Vector2i startMousePosition; // pozycja startowa
sf::Vector2f startWorldMousePosition; // globalna pozycja startowa
sf::RectangleShape selectArea; // rect do zobrazowania zaznaczenia

enum class MouseState { None, Press, Selecting, Click, DoubleClick };
MouseState mouse_state = MouseState::None;

int main()
{
   
while( window->isOpen() ) {
       
prevTime = currentTime;
       
currentTime = timeClock.getElapsedTime();
       
       
mousePosition = sf::Mouse::getPosition( * window );
       
worldMousePosition = window->mapPixelToCoords( mousePosition );
       
       
sf::Event event;
       
while( window->pollEvent( event ) )
       
{
           
           
if( event.type == sf::Event::Closed ) {
               
window->close();
           
}
           
else if( event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left ) {
               
               
if(( currentTime - mouse_start_time ).asSeconds() < 0.2f )
               
{
                   
if( mouse_state == MouseState::Click )
                   
{
                       
                       
mouse_state = MouseState::DoubleClick;
                       
std::cout << "double click\n";
                   
}
                   
else if( mouse_state == MouseState::Selecting )
                   
{
                       
mouse_start_time = currentTime;
                       
mouse_state = MouseState::Click;
                       
std::cout << "click\n";
                   
}
                   
else
                       
 mouse_state = MouseState::None;
                   
               
}
               
else
               
{
                   
mouse_state = MouseState::None;
                   
cout << " end selecting\n";
               
}
               
               
            }
else if( event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left ) {
               
               
if( mouse_state == MouseState::None )
               
{
                   
mouse_state = MouseState::Press;
                   
mouse_start_time = currentTime;
                   
startMousePosition = mousePosition;
                   
startWorldMousePosition = worldMousePosition;
                   
               
}
            }
        }
       
       
       
if( mouse_state == MouseState::Press )
       
{
           
if(( currentTime - mouse_start_time ).asSeconds() > 0.1f )
           
{
               
mouse_state = MouseState::Selecting;
               
std::cout << "start selecting\n";
           
}
           
        }
       
       
if( mouse_state == MouseState::Selecting )
       
{
           
cout << "selecting\n";
       
}
       
       
    }
   
   
return 0;
   
}
P-181974
pekfos
» 2024-12-20 17:13:06
Napisz co to za kod i co chciałbyś żeby robił, albo co robi źle. Bo tak to nie wiadomo co odpisać.
P-181976
tBane
Temat założony przez niniejszego użytkownika
» 2024-12-20 17:33:54
Jest to kod obsługujący zdarzenia kursora.
No więc kod działa tak:

-jeżeli przycisk jest puszczony to jest to jakieś kliknięcie, należy więc sprawdzić czy podwójne czy pojedyncze i je obsłużyć (wyświetl "click" lub "double click"
-jeżeli przycisk jest trzymany to jest to zaznaczenie a jeżeli jeszcze MouseState jest None to jest to początek zaznaczenia

i po zdarzeniach
-jeżeli stan myszy jest press to zmieniamy stan kursora na zaznaczenie
-jeżeli stan myszy to zaznaczenie to wykonujemy operację zaznaczania

Nie wiem gdzie popełniłem błąd logiczny, nie wyjaśnię.
Chciałbym by kod obsługiwał takie zdarzenia dla lewego przycisku myszy jak kliknięcie, podwójne kliknięcie oraz zaznaczenie.
Byłbym wdzieczny za pomoc :-)
P-181977
pekfos
» 2024-12-20 18:34:36
Dziwnie to jakoś wymyśliłeś, zwłaszcza z tymi wymaganiami czasowymi. Nie wymyślasz tu koła na nowo, tylko chcesz zreprodukować zachowanie Windowsa, które możesz zresztą łatwo wybadać na ikonkach na pulpicie. W szczególności
  • nie ma limitu czasowego na kliknięcie, to jest down-up, o ile kursor nie odjechał za daleko od punktu wciśnięcia,
  • jeżeli odjechał to wchodzisz do stanu zaznaczania i rysujesz prostokąt.
  • Podwójne kliknięcie to sekwencja down-up-down, również nie odchodząc kursorem za daleko od punktu startu. Żeby nie wykrywać podwójnego kliknięcia razem z pojedynczym, wykrycie pojedynczego kliknięcia musisz opóźnić do momentu zamknięcia się okna czasowego, którym określasz jak szybko trzeba te podwójne kliknięcie wykonać. To jest jedyny element czasowy tutaj. Poza tym podwójne kliknięcie nie wymaga puszczenia przycisku, więc zadbaj żeby potem zignorować te puszczenie, a nie odczytać to jako kolejne kliknięcie.
P-181978
tBane
Temat założony przez niniejszego użytkownika
» 2024-12-20 18:39:18
Podesłałbyś kod obsługujący te zachowania?
P-181979
pekfos
» 2024-12-20 19:08:16
Ale wygodnie z Twojej strony.
C/C++
#include <SFML/Graphics.hpp>
#include <cstdio>
#include <cmath>

int main()
{
   
sf::RenderWindow okno( sf::VideoMode( 320, 240 ), "Kurs SFML 2.0 - http://cpp0x.pl" );
   
sf::Clock stoper;
   
   
enum class State
    {
       
Idle,
       
Click, // down, up, okno czasowe trwa
       
DoubleClickDone, // ignoruj puszczenie przycisku po podwójnym kliknięciu
       
Select
    } state = State::Idle;
   
sf::Time lastPressTime;
   
sf::Vector2f lastPressPos;
   
bool isPressed = false;
   
   
const float DoubleClickMaxTime = 0.5f; // s
   
const float ClickMaxProximity = 10.f; // px
   
   
while( okno.isOpen() )
   
{
       
sf::Event event;
       
sf::Time now = stoper.getElapsedTime();
       
       
while( okno.pollEvent( event ) )
       
{
           
if( event.type == sf::Event::Closed )
               
 okno.close();
           
           
if( event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left )
           
{
               
isPressed = true;
               
               
if( state == State::Click &&( now - lastPressTime ).asSeconds() <= DoubleClickMaxTime )
               
{
                   
puts( "Double click" );
                   
state = State::DoubleClickDone;
               
}
               
               
lastPressTime = now;
               
lastPressPos = sf::Vector2f( event.mouseButton.x, event.mouseButton.y );
           
}
           
           
if( event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left )
           
{
               
isPressed = false;
               
switch( state )
               
{
               
case State::Idle:
                   
state = State::Click;
                   
break;
                   
               
case State::Select:
                   
puts( "Select done" );
                   
state = State::Idle;
                   
break;
                   
                   
default:
                   
state = State::Idle;
               
}
            }
           
           
if( state != State::Select && state != State::DoubleClickDone && event.type == sf::Event::MouseMoved && isPressed )
           
{
               
sf::Vector2f v( event.mouseMove.x, event.mouseMove.y );
               
v -= lastPressPos;
               
if( fabs( v.x ) + fabs( v.y ) > ClickMaxProximity )
               
{
                   
puts( "Select start" );
                   
state = State::Select;
               
}
            }
           
        }
//while
       
       
if( state == State::Click &&( now - lastPressTime ).asSeconds() > DoubleClickMaxTime )
       
{
           
puts( "Click" );
           
state = State::Idle;
       
}
       
       
okno.clear();
       
       
if( state == State::Select )
       
{
           
sf::Vector2i pos = sf::Mouse::getPosition( okno );
           
sf::Vector2f mm( std::min < float >( pos.x, lastPressPos.x ), std::min < float >( pos.y, lastPressPos.y ) );
           
sf::Vector2f mx( std::max < float >( pos.x, lastPressPos.x ), std::max < float >( pos.y, lastPressPos.y ) );
           
           
sf::RectangleShape rs;
           
rs.setSize( mx - mm );
           
rs.setPosition( mm );
           
rs.setOutlineThickness( 1 );
           
sf::Color col = sf::Color::Blue;
           
rs.setOutlineColor( col );
           
col.a = 128;
           
rs.setFillColor( col );
           
okno.draw( rs );
       
}
       
       
okno.display();
   
} //while
   
return 0;
}
P-181980
tBane
Temat założony przez niniejszego użytkownika
» 2024-12-20 19:20:02
Ok. Dziękuję. Teraz to trzeba przeanalizować i zrozumieć.
Dziękuję za pomoc! :-)
P-181981
« 1 »
  Strona 1 z 1