I'm new to to GUI programming and this is surely a simple newbie
question ;-)
I've created a small GUI with just one Button and a progessbar. If one
presses the Button a QStateMachine is created and started and performs
a
rather long running process.
Now, what I wanna do is to update a progessbar every time I'm entering
a new State. The Problem is that I'm running thru my StateMachine but
the progessbar is updated only _after_ the QStateMachine is finished!
So what I'm missing here?
Here is a snipplet of my code:
class MainWindow(QMainWindow, Ui_mainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
# Start the QStateMashine by pressing the Button
self.pushButton.clicked.connect(self.state_mashine)
def state_mashine(self):
self.progressBar_4.setValue(0)
machine = QStateMachine(self)
prepare = QState()
prepare.entered.connect(self.prepare_dut())
flash = QState()
flash.entered.connect(self.flash_dut())
config = QState()
config.entered.connect(self.config_dut())
finish = QFinalState()
finish.entered.connect(self.finish_dut())
prepare.addTransition(flash)
flash.addTransition(config)
config.addTransition(finish)
machine.addState(prepare)
machine.addState(flash)
machine.addState(config)
machine.addState(finish)
machine.setInitialState(prepare)
machine.start()
def prepare_dut(self):
self.progressBar_4.setValue(33)
print "State 1: Prepare DUT"
time.sleep(1)
def flash_dut(self):
self.progressBar_4.setValue(66)
print "State 2: Flash DUT"
time.sleep(1)
def config_dut(self):
self.progressBar_4.setValue(80)
print "State 3: Config DUT"
time.sleep(1)
def finish_dut(self):
self.progressBar_4.setValue(100)
print "State 4: DUT finished!"
time.sleep(1)
if __name__ == '__main__':
app = QApplication(sys.argv)
frame = MainWindow()
frame.show()
app.exec_()
_______________________________________________
PySide mailing list
PyS...@lists.pyside.org
http://lists.pyside.org/listinfo/pyside
You need to give Qt a chance to process the events, when you call
machine.start() the machine starts, change states and until it finishes Qt
doesn't process any event, so the GUI isn't updated.
There's two possibilities to fix this:
- Put your state machine code into a separated thread.
- Call QCoreApplication.processEvents() on each slot used by your
QStateMachine.
this was my two cents.
--
Hugo Parente Lima
INdT - Instituto Nokia de Tecnologia
Although, you need to take care that processEvents() will never be
called while actually processing events.
Thanks for this tip!
Now I've putted my QStateMachine into a separate thread, as you
suggested,
and it works ... mostly. Now if I start my application I get two error
messages:
1. QMetaObject::connectSlotsByName: No matching signal for
on_progress()
2. QObject::setParent: Cannot set parent, new parent is in a different
thread
Msg 1 appears when I start the application. Msg 2 when I press the
start Button.
But the application is running fine. While msg 1 is surely something
related to
the multi inheritance in my application but what's the course of Msg
2?
Hope someone has a tip for me ... ;-)
- Markus
--------------------8<----schnipp---------------------------------
import time
import threading
import platform
from PySide import QtCore
from PySide import QtGui
from ui_trimeibt import Ui_mainWindow
__version__ = '0.0.1'
class MainWindow(QtGui.QMainWindow, Ui_mainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self._progress = 0
self._running = False
self.startButton.clicked.connect(self._start_machine)
self.on_progress.connect(self._update_progressbar)
def _update_progressbar(self):
self.progressBar_DUT1.setValue(self.progress)
def _reset_progressbar(self):
print "RESET"
self.progressBar_DUT1.reset()
def _state_machine(self):
machine = QtCore.QStateMachine(self)
machine.finished.connect(self._reset_progressbar)
prepare = QtCore.QState()
prepare.entered.connect(self.prepare_dut())
flash = QtCore.QState()
flash.entered.connect(self.flash_dut())
config = QtCore.QState()
config.entered.connect(self.config_dut())
finish = QtCore.QFinalState()
finish.entered.connect(self.finish_dut())
prepare.addTransition(flash)
flash.addTransition(config)
config.addTransition(finish)
machine.addState(prepare)
machine.addState(flash)
machine.addState(config)
machine.addState(finish)
machine.setInitialState(prepare)
machine.start()
def prepare_dut(self):
print "State 1: Prepare DUT"
self.progress = 20
time.sleep(1)
def flash_dut(self):
print "State 2: Flash DUT"
self.progress = 50
time.sleep(1)
def config_dut(self):
print "State 3: Config DUT"
self.progress = 70
time.sleep(1)
def finish_dut(self):
print "State 4: DUT finished!"
self.progress = 100
time.sleep(1)
@QtCore.Slot()
def _start_machine(self):
if not self._running:
self._running = True
thread = threading.Thread(target=self._state_machine)
thread.start()
def _get_progress(self):
return self._progress
def _set_progress(self, progress):
self._progress = progress
self.on_progress.emit()
on_progress = QtCore.Signal()
progress = QtCore.Property(int, _get_progress, _set_progress,
notify=on_progress)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
frame = MainWindow()
frame.show()
app.exec_()
--------------------8<----schnapp---------------------------------
2011/3/17 Markus Hubig <mhu...@imko.de>:
> 2. QObject::setParent: Cannot set parent, new parent is in a different
> thread
>
> Msg 1 appears when I start the application. Msg 2 when I press the
> start Button.
> But the application is running fine. While msg 1 is surely something
> related to
> the multi inheritance in my application but what's the course of Msg
> 2?
You pass "self" as the first parameter in this part of your code:
> def _state_machine(self):
> machine = QtCore.QStateMachine(self)
And "_state_machine" is run in a different thread (the one you
created; the other one is the implicit main thread of execution of the
application). Message 2 is pretty clear there. To avoid the error,
don't set the QStateMachine as child (by not passing "self" as the
first parameter). If you do this, however, the state machine doesn't
become a child of the object (obviously), but you need to keep a
reference to it so it doesn't get destroyed when it falls out of
scope. You can do this by having in the __init__ method of your
MainWindow:
self._machine = None
And then in the _state_machine function:
self._machine = QtCore.QStateMachine()
This avoids the second error message.
HTH.
Thomas
Yeah! I finally got it working without errors! ;-)
--------------------8<----schnipp
(trime.py)------------------------------
import platform
from PySide import QtCore
from PySide import QtGui
from ui_trimeibt import Ui_mainWindow
from statemachine import StateMachine
__version__ = '0.0.1'
class MainWindow(QtGui.QMainWindow, Ui_mainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self._progress = 0
self._running = False
self.startButton.clicked.connect(self._start_machine)
self.machine = StateMachine()
self.machine.on_progress.connect(self._update_progressbar)
self.machine.finished.connect(self._reset_progressbar)
def _update_progressbar(self):
self.progressBar_DUT1.setValue(self.machine.progress)
def _reset_progressbar(self):
print "RESET"
self.progressBar_DUT1.reset()
def _start_machine(self):
self.machine.start()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
frame = MainWindow()
frame.show()
app.exec_()
--------------------8<----schnapp (trime.py)
---------------------------------
--------------------8<----schnipp
(statemachine.py)---------------------------
import time
import platform
from PySide import QtCore
from PySide import QtGui
class StateMachine(QtCore.QThread):
def __init__(self, parent=None):
super(StateMachine, self).__init__(parent)
self._progress = 0
def run(self):
machine = QtCore.QStateMachine()
prepare.addTransition(flash)
flash.addTransition(config)
config.addTransition(finish)
def _get_progress(self):
return self._progress
def _set_progress(self, progress):
self._progress = progress
self.on_progress.emit()
on_progress = QtCore.Signal()
progress = QtCore.Property(int, _get_progress, _set_progress,
notify=on_progress)
--------------------8<----schnapp
(statemachine.py)---------------------------