Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ Enhancement/Question] How to find out if a GUI is in the foreground or background #2395

Closed
4 tasks
mborus opened this issue Dec 18, 2019 · 10 comments
Closed
4 tasks

Comments

@mborus
Copy link

mborus commented Dec 18, 2019

Type of Issues (Question)

Question:

Is there any way to know if a PySimpleGUIQt/PySimpleGUI gui is currently in the foreground (directly accepting keyboard entries & mouse clicks) or in the background?

Use case: I want to make it extremly noticable if the gui window is in the background and can accept keyboard entries, like for example changing the color of some elements or the GUI background color.

Operating System

windows 10 pro

Python version

3.7.5 64but

PySimpleGUI Port and Version

Using PySimpleGUIQt, newest version

Your Experience Levels In Months or Years

5 years Python programming experience
30+ Programming experience overall
(High level languages)
not seriously___ Have used another Python GUI Framework (tkiner, Qt, etc) previously (yes/no is fine)?

You have completed these steps:

  • Read instructions on how to file an Issue
  • [ x] Searched through main docs http://www.PySimpleGUI.org for your problem
  • Searched through the readme for your specific port if not PySimpleGUI (Qt, WX, Remi)
  • Looked for Demo Programs that are similar to your goal http://www.PySimpleGUI.com
  • [X ] Note that there are also Demo Programs under each port on GitHub
  • Run your program outside of your debugger (from a command line)
  • [ X] Searched through Issues (open and closed) to see if already reported

Code or partial code causing the problem

@PySimpleGUI
Copy link
Owner

You can be notified that your window has lost focus and gained focus if that's of help.

The new bind methods for individual Elements and for the window will generate an event that's returned through your window.read() call.

For the focus in and out, I'm getting 3 events every time for windows. Not exactly sure why, but other than that it's fine. You can simply ignore the extras. This code will generated focus in and focus out keys that come through when you click away from the window and back again.

That handles the focus. Getting the windows "Z-Order" is something entirely different. I have no way of detecting if other windows are on top of this window. This only tells you if the focus is present or not.

import PySimpleGUI as sg

sg.change_look_and_feel('Dark Blue 3')

layout = [  [sg.Text('My Window')],
            [ sg.Button('Exit')]  ]

window = sg.Window('Window Title', layout, finalize=True)

window.bind('<FocusIn>', '+FOCUS IN+')
window.bind('<FocusOut>', '+FOCUS OUT+')

while True:             # Event Loop
    event, values = window.read()
    print(event, values)
    if event in (None, 'Exit'):
        break
window.close()

@PySimpleGUI
Copy link
Owner

There's a new demo program posted that has examples of binding to several different things.

Demo_Event_Binding.py

import PySimpleGUI as sg

"""
    Extending PySimpleGUI using the tkinter event bindings

    The idea here is to enable you to receive tkinter "Events" through the normal place you
    get your events, the window.read() call.

    Both elements and windows have a bind method.
    window.bind(tkinter_event_string, key)   or   element.bind(tkinter_event_string, key_modifier)
    First parameter is the tkinter event string.  These are things like <FocusIn> <Button-1> <Button-3> <Enter>
    Second parameter for windows is an entire key, for elements is something added onto a key.  This key or modified key is what is returned when you read the window.
    If the key modifier is text and the key is text, then the key returned from the read will be the 2 concatenated together.  Otherwise your event will be a tuple containing the key_modifier value you pass in and the key belonging to the element the event happened to.
"""
sg.change_look_and_feel('Dark Blue 3')

layout = [  [sg.Text('Move mouse over me', key='-TEXT-')],
            [sg.In(key='-IN-')],
            [sg.Button('Right Click Me', key='-BUTTON-'), sg.Button('Exit')]  ]

window = sg.Window('Window Title', layout, finalize=True)

window.bind('<FocusOut>', '+FOCUS OUT+')

window['-BUTTON-'].bind('<Button-3>', '+RIGHT CLICK+')
window['-TEXT-'].bind('<Enter>', '+MOUSE OVER+')
window['-TEXT-'].bind('<Leave>', '+MOUSE AWAY+')
window['-IN-'].bind('<FocusIn>', '+INPUT FOCUS+')

while True:             # Event Loop
    event, values = window.read()
    print(event, values)
    if event in (None, 'Exit'):
        break
window.close()

@mborus
Copy link
Author

mborus commented Dec 18, 2019

Thanks for answering to quickly.

I tried this and can confirm, I get the bind events three times (which is no problem)
This works with PySimpleGUI, but not with the PySimpleGUIQt version.
(AttributeError: 'Window' object has no attribute 'bind')

Is there a similar trick for the Qt version?

@PySimpleGUI
Copy link
Owner

Nothing like it yet for PySimpleGUIQt. Sorry.

The focus on Qt at the moment is finishing out the elements. I've been working on the Tree most recently since it doesn't even return a value at the moment. Qt has taken a bit of a back seat as I've been polishing off the color themes for the tkinter version and finishing up some drawing primitives.

@mborus
Copy link
Author

mborus commented Dec 18, 2019

OK, thanks for the info (and for spendig so much time on PySimpleGUI. I'm closing this "issue" then.

@mborus mborus closed this as completed Dec 18, 2019
@PySimpleGUI
Copy link
Owner

No problem. I hope it was of help. If you end up making something cool from it post about it. I've not seen anything made that does what you're talking about.

@mborus
Copy link
Author

mborus commented Dec 18, 2019

Yes, it was very helpful - I now know I need a solution outside of PySimpleGUIQt.

With the code below I can get the active window title, so a hacky approach is to set the PySimpleGUIQt windows title to something unique (like a uuid.uuid4() number) and then check if that text is active.

import win32gui
active_windows_title =win32gui.GetWindowText(win32gui.GetForegroundWindow())

required for this is pywin32 (which is on pip)

@mborus
Copy link
Author

mborus commented Dec 19, 2019

If you end up making something cool from it post about it. I've not seen anything made that does what you're talking about.

It's a cool little thing. We opened a community FM radio station this week and we want beginners to be able to DJ on the air without having to learn about the complicated software needed to manage the playout. So they get a one button PysimpleGUI. Press the button, and a countdown & progress bar tells you how long the current song plays. It will pause after it. So you open the microphone and talk. Press the button again and the next song plays.

This is easy to teach and worked nicely on the opening day. The only problem was, we needed to make sure the window has focus (we can't have it on top all the time, so forcing focus is not an option), so I'll change it to remove all color from the window if it's not active.

@PySimpleGUI
Copy link
Owner

What an AWESOME and unique application.

If you can get a screenshot, that would be great to see.

The loss of focus thing is fixed, I hope, with the binding. Is there a specific reason why you wanted PySimpleGUIQt instead of plain PySimpleGUI? It seems like such a simple application wouldn't dictate the use of Qt.

@PySimpleGUI
Copy link
Owner

I'm wondering if the system tray can also be of help to you?

You can use that area to popup messages as well as take in input.

Just a thought... maybe a bad one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants