Error with thread in pyqt4 - python

I have the problem. I made the thread and from there I want to open the new window. But it does not work.
import sys
from grab import Grab
from PyQt4 import QtGui, QtCore
class Requests(QtCore.QThread):
def __init__(self, parent=None):
QtCore.QThread.__init__(self, parent)
def run(self):
# here some comands
self.emit(QtCore.SIGNAL("mysignal(QString)"), 'open')
class window(QtGui.QWidget):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
self.setGeometry(100, 100, 500, 200)
self.setWindowTitle('Window')
self.label = QtGui.QLabel(u'Hello')
self.Layout = QtGui.QVBoxLayout()
self.Layout.addWidget(self.label)
self.setLayout(self.Layout)
self.c = Requests()
self.c.start()
self.connect(self.c, QtCore.SIGNAL("mysignal(QString)"), self.open_window, QtCore.Qt.QueuedConnection)
def open_window(self):
print 'open modal window'
modal_w = popup_window()
modal_w.show()
app = QtGui.QApplication(sys.argv)
main = window()
main.show()
sys.exit(app.exec_())
It is not show new window. Where is the error?

You need to connect the signal before the thread starts, and hence before the signal is emitted. If you want to show a dialog when the worker thread completes, just use the finished signal:
class Requests(QtCore.QThread):
def run(self):
# do some work...
print 'work finished'
...
self.c = Requests()
self.c.finished.connect(self.open_window)
self.c.start()
You also need to keep a reference to the dialog when opening it in the slot:
def open_window(self):
print 'open modal window'
self.modal_w = popup_window()
self.modal_w.show()

Related

PyQt: switch windows/layouts created by Qt Designer

I am creating an app using PyQt4. I have created two interfaces with Qt Designer. When a button is pushed I would like to switch between one layout and the other.
A sample of my code is:
from PyQt4 import QtGui, uic
form_class = uic.loadUiType("sample.ui")[0]
form_class2 = uic.loadUiType("sample2.ui")[0]
class SecondLayout(form_class2, QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
form_class2.setupUi(self)
class MainWindow(form_class, QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.btn.clicked.connect(self.open_new_window)
def open_new_window(self):
self.Window = SecondLayout()
# here I would like to switch the layout with a layout of self.Window
app = QtGui.QApplication(sys.argv)
myWindow = MainWindow(None)
myWindow.show()
app.exec_()
I have done a lot of searching and reading about QStackedLayout, but haven't been able to get it to work with layouts created in Qt Designer.
My Question is how would I be able to have one Main Window and switch its central widget but i'm not sure if that would work for the seperate menus. I have defined all the menus and widgets and status bars, etc. in Qt Designer as two different projects(both main windows) so I would like to have the main program in one of the main windows, then at some point create an instance of the second main window and switch the layout and all the widgets, menus, text edits, etc. I tried using setCentralWidget but hasn't worked for me.
Could someone please explain to me how to do this.
It sounds like you have two completely separate main windows. There is really no point in switching all the widgets, menus, toolbars, etc, because they will have no shared code. You might just as well simply hide one window, and then show the other one.
Here is a simple demo that shows one way to do that:
PyQt5
from PyQt5 import QtWidgets
class Window1(QtWidgets.QMainWindow):
def __init__(self, window2=None):
super(Window1, self).__init__()
self.setGeometry(500, 100, 100, 50)
self.button = QtWidgets.QPushButton('Go To Window 2', self)
self.button.clicked.connect(self.handleButton)
self.setCentralWidget(self.button)
self._window2 = window2
def handleButton(self):
self.hide()
if self._window2 is None:
self._window2 = Window2(self)
self._window2.show()
class Window2(QtWidgets.QMainWindow):
def __init__(self, window1=None):
super(Window2, self).__init__()
self.setGeometry(500, 100, 100, 50)
self.button = QtWidgets.QPushButton('Go To Window 1', self)
self.button.clicked.connect(self.handleButton)
self.setCentralWidget(self.button)
self._window1 = window1
def handleButton(self):
self.hide()
if self._window1 is None:
self._window1 = Window1(self)
self._window1.show()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = Window1()
window.show()
sys.exit(app.exec_())
PyQt4
from PyQt4 import QtCore, QtGui
class Window1(QtGui.QMainWindow):
def __init__(self, window2=None):
super(Window1, self).__init__()
self.setGeometry(500, 100, 100, 50)
self.button = QtGui.QPushButton('Go To Window 2', self)
self.button.clicked.connect(self.handleButton)
self.setCentralWidget(self.button)
self._window2 = window2
def handleButton(self):
self.hide()
if self._window2 is None:
self._window2 = Window2(self)
self._window2.show()
class Window2(QtGui.QMainWindow):
def __init__(self, window1=None):
super(Window2, self).__init__()
self.setGeometry(500, 100, 100, 50)
self.button = QtGui.QPushButton('Go To Window 1', self)
self.button.clicked.connect(self.handleButton)
self.setCentralWidget(self.button)
self._window1 = window1
def handleButton(self):
self.hide()
if self._window1 is None:
self._window1 = Window1(self)
self._window1.show()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window1()
window.show()
sys.exit(app.exec_())

Trigger Close Event for Tabs in PySide QTabWidget

I've written 3 separate widgets and each one contains a'closeEvent'. However the close events are NOT triggered when the widgets are placed as tabs inside the MainWindow. How can I emit a signal to properly fire the 'closeEvent' for each tab when the MainWindow closes?
I've done my best to simplify the code to focus on the main goal. I'd like to emit the close event for each tab so in the future when I add more tabs it will be more flexible and each tool will still be self contained.
import sys
from PySide import QtGui, QtCore
class TabA(QtGui.QWidget):
def __init__(self, parent=None):
super(TabA, self).__init__(parent)
self.resize(300, 300)
self.setWindowTitle('App A')
self.btn = QtGui.QPushButton("Button A")
grid = QtGui.QGridLayout()
grid.addWidget(self.btn)
self.setLayout(grid)
def closeEvent(self, event):
print "closing Tab A"
event.accept()
class TabB(QtGui.QWidget):
def __init__(self, parent=None):
super(TabB, self).__init__(parent)
self.resize(300, 300)
self.setWindowTitle('App A')
self.btn = QtGui.QPushButton("Button A")
grid = QtGui.QGridLayout()
grid.addWidget(self.btn)
self.setLayout(grid)
def closeEvent(self, event):
print "closing Tab A"
event.accept()
class TabC(QtGui.QWidget):
def __init__(self, parent=None):
super(TabC, self).__init__(parent)
self.resize(300, 300)
self.setWindowTitle('App A')
self.btn = QtGui.QPushButton("Button A")
grid = QtGui.QGridLayout()
grid.addWidget(self.btn)
self.setLayout(grid)
def closeEvent(self, event):
print "closing Tab A"
event.accept()
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.initUI()
def initUI(self):
self.resize(300, 300)
self.setWindowTitle('Tabs')
# Tabs
main_tabWidget = QtGui.QTabWidget()
main_tabWidget.addTab(TabA(), "TabA")
main_tabWidget.addTab(TabB(), "TabB")
main_tabWidget.addTab(TabC(), "TabC")
vbox = QtGui.QVBoxLayout()
vbox.addWidget(main_tabWidget)
vbox.setContentsMargins(0, 0, 0, 0)
main_widget = QtGui.QWidget()
main_widget.setLayout(vbox)
self.setCentralWidget(main_widget)
def main():
app = QtGui.QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The closeEvent method is only called for a top-level window when a close request is received, so it is not suitable for your use-case. However, there are several signals that are emitted while the application is shutting down that you can connect to.
So for instance you could do this:
class TabA(QtGui.QWidget):
def __init__(self, parent=None):
super(TabA, self).__init__(parent)
...
QtGui.qApp.aboutToQuit.connect(self.handleClose)
def handleClose(self):
print "closing Tab A"
This signal is emitted just before the event-loop exits, and there's also a QtGui.qApp.lastWindowClosed signal which is emitted just after the main window closes.
(PS: don't be tempted to use __del__ for this purpose, because the exact behaviour during shutdown is strictly undefined in PyQt, and can change between versions).

How to add tabs is Qtabwidget in a new process?

I want to add a tab in a new process on button click event and terminate it after sometime.
On Button click a new process is created but tabs are not created.
Please help me regrading this issue!!!
Here is what is tried:
from PyQt4 import Qt, QtCore, QtGui
import sys
import multiprocessing
class createProc(multiprocessing.Process):
def __init__(self,mnWndObj):
super(createProc,self).__init__()
self.Obj = mnWndObj
def run(self):
print "Process is being created!!!"
tab = QtGui.QWidget()
self.Obj.tabwnd.addTab(tab,"tab")
class MainWnd(QtGui.QWidget):
def __init__(self,parent=None):
super(MainWnd,self).__init__(parent)
self.layout = QtGui.QVBoxLayout()
self.tabwnd = QtGui.QTabWidget()
self.webwnd = Qt.QWebView()
self.webwnd.load(QtCore.QUrl("https://www.google.co.in/"))
self.webwnd.show()
self.btn = QtGui.QPushButton("Create Process")
self.layout.addWidget(self.btn)
self.layout.addWidget(self.tabwnd)
self.layout.addWidget(self.webwnd)
self.setLayout(self.layout)
self.btn.clicked.connect(self.crProc)
def crProc(self):
p = createProc(self)
p.start()
print "Process Name",p.name
if __name__=="__main__":
app = Qt.QApplication(sys.argv)
m = MainWnd()
m.show()
app.exec_()

Close second window to go back to first window

I'm developing some programe in python.
Now i can open a second window but now i will go back to my first window.
My problem is when i push the close button my first and second window close.
And i will that only my second window closed.
My code:
import sys
from PyQt4 import QtCore, QtGui
from forms.runtime_form import Ui_runtime_form
import datetime
import time
"""
The main class
First window
"""
class StartQT4(QtGui.QMainWindow):
def __init__(self, parent=None):
self.run_mode = 0
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_runtime_form()
self.ui.setupUi(self)
self.main_thread = main_thread(self)
self.main_thread.start()
self.main_thread.update_date_time.connect(self.update_date_time)
if self.run_mode == 0:
Uit = QtGui.QPushButton('Uit', self)
Uit.move(20,650)
Uit.clicked.connect(QtCore.QCoreApplication.instance().quit)
#button to open second window
bla = QtGui.QPushButton('bla', self)
bla.move(150,650)
bla.clicked.connect(self.child)
#open second window
def child(self):
test = Example(self)
test.showFullScreen()
def update_date_time(self):
#some other code
#Second window
class Example(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
Uit = QtGui.QPushButton('Uit', self)
Uit.clicked.connect(self.sluit)
Uit.move(150,50)
self.setGeometry(300, 300, 500, 150)
self.setWindowTitle('Modbus Domotica - Touchscreen')
self.show()
#Close second window
def sluit(self):
sys.exit(0)
class main_thread(QtCore.QThread):
update_date_time = QtCore.pyqtSignal()
def __init__(self, layout):
QtCore.QThread.__init__(self)
def __del__(self):
self.wait()
def run(self):
while True:
self.update_date_time.emit()
time.sleep(10)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("Cleanlooks"))
QtGui.QApplication.setPalette(QtGui.QApplication.style().standardPalette())
myapp = StartQT4()
myapp.showFullScreen()
sys.exit(app.exec_())
Of course both windows close, you are exiting Python!
#Close second window
def sluit(self):
sys.exit(0)
Instead, try -
def sluit(self):
self.close()

PyQt update gui

I'm trying to update the text in a Qt GUI object via a QThread in PyQt but I just get the error QPixmap: It is not safe to use pixmaps outside the GUI thread, then it crashes. I would really appreciate any help, thanks.
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent = None):
QMainWindow.__init__(self, parent)
self.setupUi(self)
self.output = Output()
def __del__ (self):
self.ui = None
#pyqtSignature("")
def on_goBtn_released(self):
threadnum = 1
#start threads
for x in xrange(threadnum):
thread = TheThread()
thread.start()
class Output(QWidget, Ui_Output):
def __init__(self, parent = None):
QWidget.__init__(self, parent)
self.setupUi(self)
self.ui = Ui_Output
self.show()
def main(self):
self.textBrowser.append("sdgsdgsgsg dsgdsg dsgds gsdf")
class TheThread(QtCore.QThread):
trigger = pyqtSignal()
def __init__(self):
QtCore.QThread.__init__(self)
def __del__(self):
self.wait()
def run(self):
self.trigger.connect(Output().main())
self.trigger.emit()
self.trigger.connect(Output().main())
This line is problematic. You are instantiating a class in the thread which looks like a widget. This is wrong. You shouldn't use GUI elements in a different thread. All GUI related code should run in the same thread with the event loop.
The above line is also wrong in terms of design. You emit a custom signal from your thread and this is a good way. But the object to process this signal should be the one that owns/creates the thread, namely your MainWindow
You also don't keep a reference to your thread instance. You create it in a method, but it is local. So it'll be garbage collected, you probably would see a warning that it is deleted before it is finished.
Here is a minimal working example:
import sys
from PyQt4 import QtGui, QtCore
import time
import random
class MyThread(QtCore.QThread):
trigger = QtCore.pyqtSignal(int)
def __init__(self, parent=None):
super(MyThread, self).__init__(parent)
def setup(self, thread_no):
self.thread_no = thread_no
def run(self):
time.sleep(random.random()*5) # random sleep to imitate working
self.trigger.emit(self.thread_no)
class Main(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.text_area = QtGui.QTextBrowser()
self.thread_button = QtGui.QPushButton('Start threads')
self.thread_button.clicked.connect(self.start_threads)
central_widget = QtGui.QWidget()
central_layout = QtGui.QHBoxLayout()
central_layout.addWidget(self.text_area)
central_layout.addWidget(self.thread_button)
central_widget.setLayout(central_layout)
self.setCentralWidget(central_widget)
def start_threads(self):
self.threads = [] # this will keep a reference to threads
for i in range(10):
thread = MyThread(self) # create a thread
thread.trigger.connect(self.update_text) # connect to it's signal
thread.setup(i) # just setting up a parameter
thread.start() # start the thread
self.threads.append(thread) # keep a reference
def update_text(self, thread_no):
self.text_area.append('thread # %d finished' % thread_no)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
mainwindow = Main()
mainwindow.show()
sys.exit(app.exec_())

Categories

Resources