Using app.exec() instead of sys.exit(app.exec_()) with PyQT4 in Spyder will not work - pyqt4

I am developing a PyQT program using the Spyder IDE (which uses IPython) on a Windows 7 machine, and I am having trouble with the statement sys.exit(app.exec_()). I have read this post
What the error when I close the dialog
and tried using just app.exec_(). When I use just app.exec_(), however, the GUI very briefly opens and then closes immediately. Here is my minimum (not) working example:
import sys
from PyQt4 import QtGui
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
btn = QtGui.QPushButton('Button', self)
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
app.exec_()
#sys.exit(app.exec_())
if __name__ == '__main__':
main()
This is my first post on stackoverflow, so if I could improve this post in any way, please let me know.

I figured out the solution. Apparently you do not need to include app.exec_() at all, according to
http://cyrille.rossant.net/making-pyqt4-pyside-and-ipython-work-together/
The following code works in Spyder:
import sys
from PyQt4 import QtGui
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
btn = QtGui.QPushButton('Button', self)
self.show()
ex= Example()

Related

Why does the label show only the last set image? (PyQt5) [duplicate]

I have got this problem. I´m trying to set text on a lineEdit object on pyqt4, then wait for a few seconds and changing the text of the same lineEdit. For this I´m using the time.sleep() function given on the python Time module. But my problem is that instead of setting the text, then waiting and finally rewrite the text on the lineEdit, it just waits the time it´s supposed to sleep and only shows the final text. My code is as follows:
from PyQt4 import QtGui
from gui import *
class Ventana(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
self.button.clicked.connect(self.testSleep)
def testSleep(self):
import time
self.lineEdit.setText('Start')
time.sleep(2)
self.lineEdit.setText('Stop')
def mainLoop(self, app ):
sys.exit( app.exec_())
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Ventana()
window.show()
sys.exit(app.exec_())
You can't use time.sleep here because that freezes the GUI thread, so the GUI will be completely frozen during this time.
You should probably use a QTimer and use it's timeout signal to schedule a signal for deferred delivery, or it's singleShot method.
For example (adapted your code to make it run without dependencies):
from PyQt4 import QtGui, QtCore
class Ventana(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setLayout(QtGui.QVBoxLayout())
self.lineEdit = QtGui.QLineEdit(self)
self.button = QtGui.QPushButton('clickme', self)
self.layout().addWidget(self.lineEdit)
self.layout().addWidget(self.button)
self.button.clicked.connect(self.testSleep)
def testSleep(self):
self.lineEdit.setText('Start')
QtCore.QTimer.singleShot(2000, lambda: self.lineEdit.setText('End'))
def mainLoop(self, app ):
sys.exit( app.exec_())
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Ventana()
window.show()
sys.exit(app.exec_())
Also, take a look at the QThread sleep() function, it puts the current thread to sleep and allows other threads to run. https://doc.qt.io/qt-5/qthread.html#sleep
You can't use time.sleep here because that freezes the GUI thread, so the GUI will be completely frozen during this time.You can use QtTest module rather than time.sleep().
from PyQt4 import QtTest
QtTest.QTest.qWait(msecs)
So your code should look like:
from PyQt4 import QtGui,QtTest
from gui import *
class Ventana(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
self.button.clicked.connect(self.testSleep)
def testSleep(self):
import time
self.lineEdit.setText('Start')
QtTest.QTest.qWait(2000)
self.lineEdit.setText('Stop')
def mainLoop(self, app ):
sys.exit( app.exec_())
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Ventana()
window.show()
sys.exit(app.exec_())

Creating new window using keyboard keys [duplicate]

I am programming a simple GUI, that will open a opencv window at a specific point. This window has some very basic keyEvents to control it. I want to advance this with a few functions. Since my QtGui is my Controller, I thought doing it with the KeyPressedEvent is a good way. My Problem is, that I cannot fire the KeyEvent, if I am active on the opencv window.
So How do I fire the KeyEvent, if my Gui is out of Focus?
Do I really need to use GrabKeyboard?
The following code reproduces my Problem:
import sys
from PyQt5.QtWidgets import (QApplication, QWidget)
from PyQt5.Qt import Qt
import cv2
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.first = True
def openselect(self):
im = cv2.imread(str('.\\images\\Steine\\0a5c8e512e.jpg'))
self.r = cv2.selectROI("Image", im)
def keyPressEvent(self, event):
if event.key() == Qt.Key_Space and self.first:
self.openselect()
self.first = False
print('Key Pressed!')
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
The keyPressEvent method is only invoked if the widget has the focus so if the focus has another application then it will not be notified, so if you want to detect keyboard events then you must handle the OS libraries, but in python they already exist libraries that report those changes as pyinput(python -m pip install pyinput):
import sys
from PyQt5 import QtCore, QtWidgets
from pynput.keyboard import Key, Listener, KeyCode
class KeyMonitor(QtCore.QObject):
keyPressed = QtCore.pyqtSignal(KeyCode)
def __init__(self, parent=None):
super().__init__(parent)
self.listener = Listener(on_release=self.on_release)
def on_release(self, key):
self.keyPressed.emit(key)
def stop_monitoring(self):
self.listener.stop()
def start_monitoring(self):
self.listener.start()
class MainWindow(QtWidgets.QWidget):
pass
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
monitor = KeyMonitor()
monitor.keyPressed.connect(print)
monitor.start_monitoring()
window = MainWindow()
window.show()
sys.exit(app.exec_())

Show sub window in main window

Can't work out how to embed a window in a main window using classes:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Qt4 tutorial using classes
This example will be built
on over time.
"""
import sys
from PyQt4 import QtGui, QtCore
class Form(QtGui.QWidget):
def __init__(self, MainWindow):
super(Form, self).__init__()
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__()
self.setGeometry(50, 50, 1600, 900)
new_window = Form(self)
self.show()
def main():
app = QtGui.QApplication(sys.argv)
main_window = MainWindow()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
This is supposed to be the single most basic bit of code using classes. How do I get the second window to show please.
As ekhumoro already pointed out, your widget needs to be a child of your mainWindow. However, I do not think that you need to call show for the widget, since it anyways gets called as soon as its parent (MainWindow) calls show. As mata pointed out correctly, the proper way to add a Widget to a MainWindow instance is to use setCentralWidget. Here is a working example for clarification:
import sys
from PyQt4 import QtGui, QtCore
class Form(QtGui.QWidget):
def __init__(self, parent):
super(Form, self).__init__(parent)
self.lbl = QtGui.QLabel("Test", self)
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__()
self.setGeometry(50, 50, 1600, 900)
new_window = Form(self)
self.setCentralWidget(new_window)
self.show()
def main():
app = QtGui.QApplication(sys.argv)
main_window = MainWindow()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

populating combo box with folders on disk using QFileSystemModel

Hi I have written this basic code trying to populate folders underneath the /Users/ directory, but I don't know what I am missing its not populating.
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
class MyWindow(QtGui.QWidget):
"""docstring for MyWindow"""
def __init__(self, parent=None):
super(MyWindow, self).__init__()
self.setup()
def setup(self):
fsm = QtGui.QFileSystemModel()
fsm.setRootPath("/Users/")
layout = QtGui.QVBoxLayout()
combo = QtGui.QComboBox()
combo.setModel(fsm)
layout.addWidget(combo)
self.setLayout(layout)
def main():
app = QtGui.QApplication(sys.argv)
win = MyWindow()
win.show()
win.raise_()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
I am getting a / in the comobobox instead of the whole list of folders under /Users/ directory.
I think its better to use QFileSystemModel instead of using os.listdir interms of efficiency and will update the view if somebody updates folder or adds folder in the /Users/ directory !
Remember that QFileSystemModel is a hierarchical model, so you need to let the QComboBox know which QModelIndex represents the children you want to display. You do that with QComboBox.setRootModelIndex()
QFileSystemModel.setRootPath() conveniently returns the QModelIndex of the path you set.
So a small change is all you need (tested on Windows) -
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
class MyWindow(QtGui.QWidget):
"""docstring for MyWindow"""
def __init__(self, parent=None):
super(MyWindow, self).__init__()
self.setup()
def setup(self):
fsm = QtGui.QFileSystemModel()
index = fsm.setRootPath("/Users/")
layout = QtGui.QVBoxLayout()
combo = QtGui.QComboBox()
combo.setModel(fsm)
combo.setRootModelIndex(index)
layout.addWidget(combo)
self.setLayout(layout)
def main():
app = QtGui.QApplication(sys.argv)
win = MyWindow()
win.show()
win.raise_()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

pyqt4 event programming (signal and slots )

I am trying to change this event code to standard signal-slot format.
But it does not work.
Can I get help?
this is slide number changing to lcd display number.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.lcd = QtGui.QLCDNumber(self)
self.sld = QtGui.QSlider(QtCore.Qt.Horizontal, self)
vbox = QtGui.QVBoxLayout()
vbox.addWidget(self.lcd)
vbox.addWidget(self.sld)
self.setLayout(vbox)
#sld.valueChanged.connect(lcd.display)
QtCore.QObject.connect(self.sld, QtCore.SIGNAL(str1), self, QtCore.SLOT("SHOW()"))
#QtCore.pyqtSlot()
def SHOW(str1):
self.lcd.display()
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Signal & slot')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You were very close with your first attempt. All you need is:
self.sld.valueChanged.connect(self.lcd.display)
(The other lines up to self.setGeometry can be deleted).

Resources