在线程中使用Pyside6

发布于 2025-01-22 09:29:20 字数 1535 浏览 0 评论 0原文

QT有一个有希望的SCXML模块。由于PYSCXML已过时,因此没有其他本机Python SCXML库,它使我可以运行SCXML statemachine。这就是为什么我尝试pyside6。

由于尽管有SCXML库,但我不需要任何QT,因此我考虑过在单独的线程中运行QCoreApplication,以便将事件循环放在那里。 根据文档,QSCXMLSTATATEMACHINE需要一个。

不幸的是,我的start_statemachine()方法不会返回,但是statemachine开始工作。

欢迎有关如何在线程中启动QSCXMLSTATATEMACHINE的任何建议。

from PySide6.QtCore import QCoreApplication, QObject
from PySide6.QtScxml import QScxmlStateMachine
from PySide6.QtCore import QTimer
import threading


def start_statemachine(filename):
    app = QCoreApplication()
    mysm = MyStateMachine(filename)
    mysm.start_sm()
    app.exec()


class MyStateMachine(QObject):

    def __init__(self, filename):
        super(MyStateMachine, self).__init__()
        self.sm = QScxmlStateMachine.fromFile(filename)
        self.counter = 0
        self.timer = QTimer()
        self.timer.setInterval(2000)
        self.timer.timeout.connect(self.recurring_timer)
        self.timer.start()

    def start_sm(self):
        print('starting statemachine')
        self.sm.setRunning(True)

    def recurring_timer(self):
        print(self.sm.activeStateNames())
        self.counter += 1
        print("Counter: %d" % self.counter)
        print('statemachine running status: ' + str(self.sm.isRunning()))


if __name__ == '__main__':
    x = threading.Thread(target=start_statemachine('statemachine.scxml'))
    x.start() #won't be reached
    while True:
        pass #do something else
    x.join()

Qt has a promising SCXML module. Since PySCXML is obsolete, there is no other native python scxml library, which lets me run a scxml statemachine. That's why I try PySide6.

Since I don't need any Qt despite of the scxml library, I thought about running the QCoreApplication in a seperate thread, in order to have the event-loop right there.
According to the documentation QScxmlStateMachine needs one.

Unfortunately my start_statemachine() method doesn't return, but the statemachine starts working.

Any advice on how to start a QScxmlStateMachine in a thread is welcomed.

from PySide6.QtCore import QCoreApplication, QObject
from PySide6.QtScxml import QScxmlStateMachine
from PySide6.QtCore import QTimer
import threading


def start_statemachine(filename):
    app = QCoreApplication()
    mysm = MyStateMachine(filename)
    mysm.start_sm()
    app.exec()


class MyStateMachine(QObject):

    def __init__(self, filename):
        super(MyStateMachine, self).__init__()
        self.sm = QScxmlStateMachine.fromFile(filename)
        self.counter = 0
        self.timer = QTimer()
        self.timer.setInterval(2000)
        self.timer.timeout.connect(self.recurring_timer)
        self.timer.start()

    def start_sm(self):
        print('starting statemachine')
        self.sm.setRunning(True)

    def recurring_timer(self):
        print(self.sm.activeStateNames())
        self.counter += 1
        print("Counter: %d" % self.counter)
        print('statemachine running status: ' + str(self.sm.isRunning()))


if __name__ == '__main__':
    x = threading.Thread(target=start_statemachine('statemachine.scxml'))
    x.start() #won't be reached
    while True:
        pass #do something else
    x.join()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦与时光遇 2025-01-29 09:29:20

线程目标需要是参考 to在外部线程中会调用的函数,但是您在另一个线程中未运行start_statemachine()实际将其执行到位:

x = threading.Thread(target=start_statemachine('statemachine.scxml'))
                                              ^^^^^^^^^^^^^^^^^^^^^^

您的程序被在内粘住,甚至没有创建线程,因为构造函数仍在“等待” start_statemachine()返回,并且由于exec()正在阻止,没有其他事情发生。

一个基本的解决方案可能是使用lambda:

x = threading.Thread(target=lambda: start_statemachine('statemachine.scxml'))

但是您需要访问该应用程序才能退出它:x.join()不会无能为力,因为qcoreApplication事件循环将继续前进,因此有可能创建一个基本类,以提供对应用程序的参考:

class StateMachineWrapper:
    app = None
    def __init__(self, filename):
        self.filename = filename

    def start(self):
        self.app = QCoreApplication([])
        mysm = MyStateMachine(self.filename)
        mysm.start_sm()
        self.app.exec()

# ...

if __name__ == '__main__':
    statemachine = StateMachineWrapper('statemachine.scxml')
    x = threading.Thread(target=statemachine.start)
    x.start()
    while True:
        pass #do something else

    if statemachine.app:
        statemachine.app.quit()

    x.join()

The thread target needs to be a reference to a function that will be called in the external thread, but you're not running start_statemachine() in another thread: you're actually executing it in place:

x = threading.Thread(target=start_statemachine('statemachine.scxml'))
                                              ^^^^^^^^^^^^^^^^^^^^^^

Your program is stuck there, no thread is even created because the constructor is still "waiting" for start_statemachine() to return, and since exec() is blocking, nothing else happens.

A basic solution could be to use a lambda:

x = threading.Thread(target=lambda: start_statemachine('statemachine.scxml'))

But you'll need access to the application in order to be able to quit it: x.join() won't do nothing, because the QCoreApplication event loop will keep going, so a possibility is to create a basic class that provides a reference to the application:

class StateMachineWrapper:
    app = None
    def __init__(self, filename):
        self.filename = filename

    def start(self):
        self.app = QCoreApplication([])
        mysm = MyStateMachine(self.filename)
        mysm.start_sm()
        self.app.exec()

# ...

if __name__ == '__main__':
    statemachine = StateMachineWrapper('statemachine.scxml')
    x = threading.Thread(target=statemachine.start)
    x.start()
    while True:
        pass #do something else

    if statemachine.app:
        statemachine.app.quit()

    x.join()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文