Pregunta

I have a problem i can't quite figure out for some time. I have a main window application and a QDialog that should pop out after clicking one of the buttons, but the show() method on QDialog seems to be waiting for the funcion connected to the "clicked()" signal to end! I want the dialog to show right after calling the QDialog.show() method, not after all the other code instructions in that function...

Of course in my code I am going to replace the sleep(5) part with much more complicated code, but this pictures the problem and the code I put there is irrelevant to the issue, i think (database connections and updates) being more specific:

# -*- coding: utf-8 -*-
import sys

import PyQt4 
from PyQt4 import QtCore, QtGui
from twython import Twython, TwythonError
from project import Ui_MainWindow
from time import sleep
import psycopg2, globalvals, updater
import updating, noconnection

class UpWindow(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent, QtCore.Qt.WindowStaysOnTopHint)
        self.ui = updating.Ui_updating()
        self.ui.setupUi(self)

class NoConnection(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent, QtCore.Qt.WindowStaysOnTopHint)
        self.ui = noconnection.Ui_noConnection()
        self.ui.setupUi(self)

        QtCore.QObject.connect(self.ui.noConnectionClose, QtCore.SIGNAL("clicked()"), self.close)

class MyCounter(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.noConn = NoConnection(self)
        self.upWin = UpWindow(self)

        QtCore.QObject.connect(self.ui.refreshButton,QtCore.SIGNAL("clicked()"), self.refresh)
        QtCore.QObject.connect(self.ui.manageButton,QtCore.SIGNAL("clicked()"), self.manage)

    def refresh(self):
        self.upWin.show()
        self.upWin.show
        self.upWin.setVisible(True)
        self.setEnabled(False)
        self.upWin.setEnabled(True)
        #Thats the issue - the sleep instruction is being held
        #BEFORE the showing of upWin QDialog
        sleep(5)

    def manage(self):
        print 'ok'



if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = MyCounter()
    myapp.upcontent()
    myapp.show()
    sys.exit(app.exec_())
¿Fue útil?

Solución

Think of the any Qt program as a cooperative-multitasking system. Graphics and events in general are handled by the main loop. You don't want to stay long in any slot, because the library won't process signals (say button clicks, repaints, but also other stuff) in the mean time.

If you want to do some heavy processing, or anything that needs to wait for resources while the rest of the program is chugging along, use a QThread.

Another option is to force the event processing with qApp.processEvents() (you can find qApp in QtGui), just before your sleep(5) (or whatever code you're going to put in place of it).

Edit: Now, keep in mind that forcing the event processing will just show the QDialog you're trying to popup. You can't do anything with it (remember, no event processing) without calling again qApp.processEvents() or returning from the slot.

Otros consejos

If MyCounter represents a widget that does a long computation and updates a dialog during that time, then sleep(5) is not representative of it, because during those 5 seconds the GUI can't handle events. For a "long running" function you would move the blocking part to a QThread and either poll the thread or connect to a signal it emits as it progresses, either way you would not hold up the GUI event loop during that time (for example, the polling, which takes very little time, would occur in an idle callback). The simplest way to create your test would be to use a timed callback into your MyCounter:

def refresh(self):
    ... show stuff, then:
    self.timer = QTimer()
    self.timer.timeout.connect(self.updateDialog)
    timer.start(100) # 10 times per sec

def updateDialog(self):
    #get thread status
    if self.thread.status != self.oldStatus:
        self.upWin.updateStatus( self.thread.status )
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top