SFML community forums

Help => Window => Topic started by: shawrie777 on May 01, 2020, 11:20:33 am

Title: Controlling focus with multiple windows
Post by: shawrie777 on May 01, 2020, 11:20:33 am
Hi

I've created a fairly simple program to play a game, and when the player clicks to start a new game a second window pops up to let them choose options. The problem is that they can still click on and switch focus to the first window. How can I force focus to the second window until they've chosen? Note I'm not intending them to be unable to switch program, just between the windows of the program.

Thanks
Title: Re: Controlling focus with multiple windows
Post by: Hapax on May 01, 2020, 06:18:05 pm
A modal window? 8)

You could check events in the new window to see if it loses focus and if it does, request the focus again.
If you use this approach, I would suggest that you make sure it's only taking focus from your first window otherwise other programs/your operating system may have trouble.
Title: Re: Controlling focus with multiple windows
Post by: shawrie777 on May 02, 2020, 01:23:04 pm
Thanks! I hadn't heard the term modal window before, so didn't know what to search for! You say to check it's taking focus from the other window: does that mean I still need to run its event loop to see if it gained focus?
Title: Re: Controlling focus with multiple windows
Post by: Hapax on May 02, 2020, 05:09:05 pm
Haven't actually tried this and I'm not certain it's the right approach due to possibly affecting other programs too.

That said, the idea was that the modal window itself checks (it should have its own event loop, right?) to see if it loses focus and then requests focus again.
So, yes, the modal window would always still have its event loop running. The original window should process events too since it will still continue to receive them and may be considered crashed if they aren't processed.
Title: Re: Controlling focus with multiple windows
Post by: LucasM on June 22, 2020, 12:13:24 am
I figured out some basic code for a modal window loop.  Seemed to work ok, as was trying to figure it out and found this thread.  If it helps?

#include <SFML/Graphics.hpp>

/*
https://stackoverflow.com/questions/26741841/how-does-a-modal-dialogs-message-pump-interact-with-the-main-application-messag
They run on the same thread. The modal dialog spawns a nested message loop.
Both the nested message loop and the main application's message loop (or rather message handlers) are siamese twins in crime:
If one doesn't play by the rules, the respective other will suffer as well. – IInspectable
*/


//call from child
void mainWinMSGHandle(sf::Window &window, sf::Window &child);

void createPopUpWindow(sf::Window *parent, int num)
{
    sf::RenderWindow popUpWindow(sf::VideoMode(320,240), "HI " + std::to_string(num), sf::Style::Close);
    popUpWindow.setPosition(parent->getPosition() + sf::Vector2i(100,100));
    sf::Event event;
    while (popUpWindow.isOpen())
    {
        popUpWindow.clear(sf::Color::Cyan);
        popUpWindow.display();

        while(popUpWindow.pollEvent(event))
     {
        if(event.type == sf::Event::Closed)
            popUpWindow.close();
        if(event.type == sf::Event::LostFocus)
        {
            if(parent->hasFocus())
                popUpWindow.requestFocus();
        }
      }
        mainWinMSGHandle(*parent, popUpWindow);
       
        sf::sleep(sf::milliseconds(1));
    }

}

//child message loop blocking main window message loop so need to handle main from child
void mainWinMSGHandle(sf::Window &window, sf::Window &child)
{
    sf::Event event;
    while(window.pollEvent(event))
    {
    if(event.type == sf::Event::Closed)
    {
        child.close();
        window.close();
    }
    if(event.type == sf::Event::GainedFocus)
    {
        child.requestFocus();
    }
    }
}

int main()
{
    sf::RenderWindow window(sf::VideoMode(800,600),"Main Window");

    sf::Event event;
    int n = 0;

    while (window.isOpen())
    {
        window.clear(sf::Color::Magenta);
        window.display();

        window.waitEvent(event);
       
        if(event.type == sf::Event::Closed)
        {
            window.close();
        }
        if(event.type == sf::Event::MouseButtonPressed)
        {
            createPopUpWindow(&window, n++);
        }
    }

    return 0;
}