Pyqt: Making a widget update without mouse focus - python

I'm making something akin to a screen recorder using the PyQT library. My problem is that the only way I can think to get the recording part of the application to run is in the "paint event" part of the widget class. Here's some code for example:
class MainWindow(QWidget):
def __init__(self):
#setup window
def initUI(self):
#init UI stuff
def paintEvent(self, event):
#capture the screen and then display it on this widget
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainWindow()
sys.exit(app.exec_())
My main problem is on the paintevent area. I could start a thread and let the at capture and save frames, but I want to actively display each frame on the window. This can work while the widget has focus, but once the mouse moves away, and the window loses focus, then it stops because the paintevent is not being activated.
Is there anyway to solve this? Thank you!

Related

How to transfer mouse focus back while showing a QMenu?

I have two buttons and both of the has some hovering effect. The first button has a menu as well, and the problem is, when the first button is clicked and menu appears, the mouse hover doesn't work for the second button at the same time until the menu is closed.
I'm not sure, but I believe it is due to some sort of focusPolicy, and I tried to find the solution but I couldn't. I just want to make hovering effect on the buttons of the widget available even while showing the menu.
from PySide2 import QtWidgets, QtGui, QtCore
import sys
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super(MyWidget, self).__init__()
self.resize(300, 300)
layout = QtWidgets.QHBoxLayout(self)
btn = QtWidgets.QPushButton('Button 1')
btn.setStyleSheet('QPushButton::hover{background-color: gray;}')
layout.addWidget(btn)
menu = QtWidgets.QMenu(self)
action = QtWidgets.QAction('buttonAction', menu)
menu.addAction(action)
btn.setMenu(menu)
btn = QtWidgets.QPushButton('Button 2')
btn.setStyleSheet('QPushButton::hover{background-color: gray;}')
layout.addWidget(btn)
self.setLayout(layout)
app = QtWidgets.QApplication([])
wig = MyWidget()
wig.show()
sys.exit(app.exec_())
Please be noted, instead of stylesheet, I even tried using evenFilter changing the colors on Enter/Leave events and returning True/`False values.
TL; DR; The behavior you want is not possible.
Explanation:
Only one window can have the focus and only the widgets that belong to that window can get the focus. In this case, the QMenu lives in a different window that is on top of the original window and that window is the one with the focus and no longer the original window.

Displaying a QtGui.QMainWindow object without quiting the script afterwards

I've wrote an object that inherits from QtGui.QMainWindow (python/pyqt). It displays an image and gives me more controls. I want to use this object as additional way to plot figures in the flow of the script (like plt.show())
The problem is that displaying this object involves a code like this:
app = QtGui.QApplication(sys.argv)
mainWin = ImageViewerWindow(result) #ImageViewerWindow inherits from QtGui.QMainWindow
mainWin.show()
app.exec_()
After the "app" was closed, I can't display additional window. Is there a way to display this window, wait for it to close, and then display another window without explicitly using signals?
(signals can be used behind the scenes but I don't want to complicate the user that want to display the image with minimal number of commands)
Probably the easiet way, another way will be catching the closing event in your window.
app = QtGui.QApplication(sys.argv)
mainWin = ImageViewerWindow(result) #ImageViewerWindow inherits from QtGui.QMainWindow
mainWin.show()
differentWindow = dW() # your other window
app.aboutToQuit.connect(lambda: differentWindow.show())
app.exec_()
Another way would be adding the closeEvent method to your window class
class ImageViewerWindow(...): # or QMainWindow
...
def closeEvent(self, event):
differentWindow = dW() # your other window
differentWindow.show()

What does the Qt.Popup window flag entail?

I'm using PyQT5 to create a GUI. Basically, what I want is a transparent window that extends the entire width and height of the screen (including the toolbar and dock on MacOS)
The code I am using to achieve this is like so:
class Gui(QWidget):
def __init__(self):
#Initialize the QApp/QWidget things
super().__init__()
#Add a default rectangle
self.rectangle = QRect(0, 0, 0, 0)
#Build the window in a method to keep the init clean
self.buildWindow()
#Build the window
def buildWindow(self):
#Make the window transparent
self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint | Qt.Popup)
self.setAttribute(Qt.WA_TranslucentBackground)
#Maximize the window
self.resize(1920, 1080)
#Enable mouse tracking
self.setMouseTracking(True)
#Render the window
self.show()
I open the GUI like so:
#Instantiate our app and Gui stuff.
app = QApplication(sys.argv)
gui = Gui()
#Make the cursor the "cross cursor" for effect
app.setOverrideCursor(QCursor(Qt.CrossCursor))
#Exit when our app exits
sys.exit(app.exec_())
The issue is that the GUI opens, renders for a second, and disappears immediately. If I remove Qt.Popup from the window flags, it will do exactly what I want it to do (but it will not extend past the dock or the toolbar on MacOS)
I've heard that this problem is causes (generally) by a widget being rendered and leaving the scope due to Python's garbage collection system, but I'm unsure if that is the problem here because it will actually render if I remove the Qt.Popup
Anyone who has experience with QT and could help would be awesome.. I've been trying to figure out this bug for a couple days.
EDIT: If you can't tell already, I am developing this on MacOS

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

PyQt: getting widgets to resize automatically in a QDialog

I'm having difficulty getting widgets in a QDialog resized automatically when the dialog itself is resized.
In the following program, the textarea resizes automatically if you resize the main window. However, the textarea within the dialog stays the same size when the dialog is resized.
Is there any way of making the textarea in the dialog resize automatically? I've tried using setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) on the dialog itself and the two widgets within, but that seems to have no effect.
I'm using Qt version 3.3.7 and PyQt version 3.5.5-29 on openSuSE 10.2, if that's relevant.
import sys
from qt import *
# The numbers 1 to 1000 as a string.
NUMBERS = ("%d " * 1000) % (tuple(range(1,1001)))
# Add a textarea containing the numbers 1 to 1000 to the given
# QWidget.
def addTextArea(parent, size):
textbox = QTextEdit(parent)
textbox.setReadOnly(True)
textbox.setMinimumSize(QSize(size, size*0.75))
textbox.setText(NUMBERS)
class TestDialog(QDialog):
def __init__(self,parent=None):
QDialog.__init__(self,parent)
self.setCaption("Dialog")
everything = QVBox(self)
addTextArea(everything, 400)
everything.resize(everything.sizeHint())
class TestMainWindow(QMainWindow):
def __init__(self,parent=None):
QMainWindow.__init__(self,parent)
self.setCaption("Main Window")
everything = QVBox(self)
addTextArea(everything, 800)
button = QPushButton("Open dialog", everything)
self.connect(button, SIGNAL('clicked()'), self.openDialog)
self.setCentralWidget(everything)
self.resize(self.sizeHint())
self.dialog = TestDialog(self)
def openDialog(self):
self.dialog.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
mainwin = TestMainWindow(None)
app.setMainWidget(mainwin)
mainwin.show()
app.exec_loop()
QMainWindow has special behavior for the central widget that a QDialog does not. To achieve the desired behavior you need to create a layout, add the text area to the layout and assign the layout to the dialog.
Just to add a little note about this - I was trying to have a child window spawned from an application, which is a QDialog, containing a single QTextEdit as a child/content - and I wanted the QTextEdit to resize automatically whenever the QDialog window size changes. This seems to have done the trick for me with PyQt4:
def showTextWindow(self):
#QVBox, QHBox # don't exist in Qt4
dialog = QDialog(self)
#dialog.setGeometry(QRect(100, 100, 400, 200))
dialog.setWindowTitle("Title")
dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
textbox = QTextEdit(dialog)
textbox.setReadOnly(True)
textbox.setMinimumSize(QSize(400, 400*0.75))
textbox.setText("AHAAA!")
# this seems enough to have the QTextEdit
# autoresize to window size changes of dialog!
layout = QHBoxLayout(dialog)
layout.addWidget(textbox)
dialog.setLayout(layout)
dialog.exec_()
I had looked at using a QLayout before but had no luck. I was trying to do something like
dialog.setLayout(some_layout)
but I couldn't get that approach to work so I gave up.
My mistake was that I was trying to pass the layout to the dialog when I should have been passing the dialog to the layout.
Adding the lines
layout = QVBoxLayout(self)
layout.add(everything)
to the end of TestDialog.__init__ fixes the problem.
Thanks to Monjardin for prompting me to reconsider layouts.
Check out Python QT Automatic Widget Resizer It's suppose to work well.

Categories