PyQt: Qt.Popup widget sometimes loses focus without closing, becomes unclosable - python

I'm writing a very small application with PyQt. All of my testing has been on Ubuntu/gnome so far.
I want a single "Popup" style window, with no taskbar/panel entry, that will close itself (and the application) the moment it loses focus.
The Qt.Popup flag seems to fit the bill, but I'm having a weird problem. I've noticed that it's possible (pretty easy, in fact) to take focus away from the application as it's starting, leaving a Popup window with no focus -- and it is now impossible to close it, because it cannot lose focus.
Here's a simplified example:
#!/usr/bin/python
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QDialog()
w.setWindowFlags(Qt.Popup)
w.exec_()
If you click around a bit within the same moment the program is starting, the QDialog will appear without focus, and will not close itself under any circumstance. Clicking on the popup does not restore focus or allow it to be closed.
I could add a close button to the popup (and I intend to!) but that doesn't fix the broken close-on-lost-focus behavior. Is there something else I should be doing with Qt.Popup windows to prevent this, or is there some way I can work around it?

Using QWidget::raise() seems to help here.
(Also took the liberty and fixed your app event loop)
#!/usr/bin/python
import sys
#import time
from PyQt4.QtCore import *
from PyQt4.QtGui import *
if __name__ == '__main__':
#time.sleep(2)
app = QApplication(sys.argv)
w = QDialog()
w.setWindowFlags(Qt.Popup)
w.setAttribute(Qt.WA_QuitOnClose)
w.show()
w.raise_()
sys.exit(app.exec_())

Related

SetWindowFlags immediately closes the program

I am trying to run the following script inside a software called Anki. This is basically an addon (a plugin) that makes the program to be always on top. This is the MRE:
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget
import time
app = QApplication([])
window = QWidget()
window.show()
def start():
while True:
window.setWindowFlags(Qt.WindowStaysOnTopHint)
#window.show()
#app.exec()
time.sleep(1)
start()
This is the closer I could get to the actual error I'm getting. Whenever the program runs the line window.setWindowFlags(Qt.WindowStaysOnTopHint), it immediatly closes the window and becomes unable to reach window.show(). Since this is just a plugin to the base app, I assume all plugins are loaded AFTER the main window has opened and within the main window. So if you close the main window, all plugins also stop running. How can I prevent the main window from closing?
There should only be one QApplication, and you don't have to create a new QApplication since anki creates it. Nor is a while True necessary since it will block the eventloop and even less use time.sleep since it also blocks the eventloop.
import time
from aqt import gui_hooks
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget
window = QWidget()
window.setWindowFlags(window.windowFlags() | Qt.WindowStaysOnTopHint)
gui_hooks.main_window_did_init.append(window.show)

pyqt5 textedit delete lines as they move past specified line

I'd like to setup the PYQT Qtextedit widget and use it to monitor another applications activity log(like tail -f on Linux). Long term I worry about it running for too long and using a lot of ram with the text that builds up. Is it possible to set a limit so that text moving past line x gets deleted? From what I've found it seems to require custom work and I'd like to find a limiter setting if one exists.
QPlainTextEdit is an advanced viewer/editor supporting plain text. It is optimized to handle large documents and to respond quickly to user input.
To limit the number of visible lines you must use setMaximumBlockCount, in the following example I show the use:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
counter = 0
def addText():
global counter
w.appendHtml("<font size=\"3\" color=\"red\">{}</font>".format(counter))
counter += 1
if __name__ == "__main__":
app = QApplication(sys.argv)
w = QPlainTextEdit()
timer = QTimer()
timer.timeout.connect(addText)
timer.start(1000)
w.setMaximumBlockCount(4)
w.show()
sys.exit(app.exec_())
If you want to use fonts you can do it easily using HTML.

How to automatically focus QDialog with a Qt.Popup flag set?

Consider the following code snippet using Python 3 and PyQt 5.5:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QWidget()
d = QDialog()
l = QLineEdit(d)
w.show()
# Comment the following line to gain focus.
d.setWindowFlags(Qt.Popup)
d.show()
app.exec_()
After d.show() is invoked, the dialog is shown but the QLineEdit inside it doesn't have focus. No amount of raise_(), activateWindow() or setFocus() seems to be working. How can I make the dialog automatically gain focus when it's shown? I would like to keep the dialog as Qt.Popup, because I need it to close when I click outside of it.
There is
QWidget::raise();
QWidget::activateWindow();
From the docs:
Sets the top-level widget containing this widget to be the active window.
An active window is a visible top-level window that has the keyboard input focus.
This function performs the same operation as clicking the mouse on the title bar of a top-level window. On X11, the result depends on the Window Manager. If you want to ensure that the window is stacked on top as well you should also call raise(). Note that the window must be visible, otherwise activateWindow() has no effect.
On Windows, if you are calling this when the application is not currently the active one then it will not make it the active window. It will change the color of the taskbar entry to indicate that the window has changed in some way. This is because Microsoft does not allow an application to interrupt what the user is currently doing in another application.
It seems that you need to set focus on the line-edit after the dialog is shown:
l = QLineEdit(d)
w.show()
d.setWindowFlags(Qt.Popup)
d.show()
l.setFocus()
app.exec_()
If that doesn't work, try it with a timer:
QTimer.singleShot(1, l.setFocus)

Using QT (PySide) to get user input with QInputDialog

I did a small script on python to do some stuff, and I want to ask user input first. This is my current code:
import sys
from PySide import QtGui
app = QtGui.QApplication(sys.argv)
gui = QtGui.QWidget()
text, ok = QtGui.QInputDialog.getText(gui, "question",
"""please put the thing I need from you""")
print(text, ok)
if ok:
app.exit()
else:
app.exit()
app.exec_()
print ("I'm aliveeeee'")
The dialog pop-ups exactly as I want, but app.exec_() never ends so the rest of the code is never executed (and the process never finish) I tried to kill it with app.exit(), app.quit(), I also try to show() and close() the QWidget, but nothing is working.
If I do gui.show() before calling the QInputDialog and then close the widget manually, the app closes successfully. However, this is not the behavior I want.
Can you guide me on which is the best way to close the exec loop after I got my data?
PD: This is going to be a windows app (with py2exe) and using the shell is not an option.
Just don't call app.exec_()
The problem here is that this is a toy example. In real life, usually you will show some UI and then call app.exec() to let the user interact with it.

PyQt4: Stop Window from taking Focus

What I am trying to do is make an on screen keyboard.
To do this I need to stop the Program from taking focus away from other windows.
Here is the code I have that keeps the window on top.
import sys
from PyQt4 import QtGui, QtCore, Qt
class mymainwindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self, None, QtCore.Qt.WindowStaysOnTopHint)
app = QtGui.QApplication(sys.argv)
mywindow.show()
app.exec_()
(Note: Example from Keep Window on Top)
So what I want to do is add code to stop the window taking focus.
Thanks
Change focus policy of window and all of its contents QWidget::setFocusPolicy

Categories