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()
Related
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!
I can't get the GUI for my application to run in the manner that I need it to. My question is, given the below criteria, how do I go about setting up and running the GUI properly. The lack of good documentation that I have found is insanely frustrating (maybe I'm looking in the wrong places?).
I have a main window in a file called MainCustomerWindow.py containing a class by the same name. This is where all the code from the qt designer is. I have another class file called GUIController. The GUIController class does just that, controls the multiple GUI windows. It is in this GUIController class that I am trying to instantiate and run the MainCustomerWindow. Here is the code I have been trying.
def setup_window(self):
APP = QtWidgets.QApplication(sys.argv)
Window = MainCustomerWindow()
Window.setupUi(QtWidgets.QMainWindow)
Window.show()
sys.exit(APP.exec_())
Just as a side note, I come from JavaFX and Swing, and don't fully understand the workflow for pyqt5. So if someone could add an explanation for that as well it would be greatly appreciated.
The class generated by Qt Designer is not a widget, it is a class used to fill an existing widget, so you must create an object in the window, assuming you have used the "Main Window" template, then the widget must be QMainWindow (if it is another maybe you should use QDialog or QWidget), then you have to create another class that belongs to the design, and using the method setupUi() you must pass the widget to fill it:
def setup_window(self):
app = QtWidgets.QApplication(sys.argv)
# create window
window = QtWidgets.QMainWindow()
ui = MainCustomerWindow()
# fill window
ui.setupUi(window)
window.show()
sys.exit(app.exec_())
Although a better option is to create a new class and have it inherit from both:
class MainWindow(QtWidgets.QMainWindow, MainCustomerWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
If you want to get detailed information I recommend you read the following:
http://pyqt.sourceforge.net/Docs/PyQt5/designer.html
You can try taking the code you have there and adding it to the main statement at the end of your app's script. You can also have this statement instantiate your class where the init method contains the setupui() call. For example:
if __name__ == '__main__':
app = QWidgets.QApplication(sys.argv)
window = QMainWindow()
main_window = MainCustomerWindow()
window.show()
sys.exit(app.exec())
This code first sets up the PyQt app as an instance of QApplication. Next it instantiates an instance of QMainWindow so that PyQt knows what to display as the main app starts. In my experience, I've put setupui() in the init method of the app class. In your case, in the init method of MainCustomerWindow Finally, window.show() tells PyQt to begin rendering the main window.
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)
In my Qt-based application (built using PyQt 4.8.6), I have a class that is a subclass of QtGui.QDialog:
class ModelDialog(QtGui.QDialog):
...
When I run the application's user interface, I can display the QDialog like so:
def main():
app = QtGui.QApplication(sys.argv)
dialog = ModelDialog()
dialog.exec_()
According to the Qt docs and the PyQt docs, exec_() is a blocking function for this QDialog, which defaults to a modal window (which by definition prevents the user from interacting with any other windows within the application). This is exactly what happens under normal circumstances.
Recently, however, I've been working on a way to call through the entire QApplication using defaults for all input values, and not asking the user for any input. The application behaves as expected except for one single aspect: calling dialog.exec_() causes the modal dialog to be shown.
The only workaround I've been able to find has been to catch the showEvent function and to promptly hide the window, but this still allows the QDialog object to be shown for a split second:
class ModelDialog(QtGui.QDialog):
...
def showEvent(self, data=None):
self.hide()
Is there a way to prevent the modal window from being shown altogether, while continuing to block the main event loop? I'd love for there to be something like:
def main():
app = QtGui.QApplication(sys.argv)
dialog = ModelDialog()
dialog.setHideNoMatterWhat(True)
dialog.exec_()
(to that end, I tried using QWidget.setVisible(False), but dialog.exec_() sets the dialog to be visible anyways, which is expected according to the Qt docs)
Use app.exec_() instead of dialog.exec_().
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.