-2

现在我的应用程序中的所有内容都非常简单,因为我刚刚开始构建它。最后可能会有两个线程可能会运行很长时间。不是因为他们有很多计算要做,而是因为我必须不断地监听 COM 端口并记录数据。

现在在正常操作期间,这不是问题,因为它做了它应该做的事情。现在可能会发生,尽管用户想要在测量完成之前关闭应用程序并且线程仍在运行。

我也得到了这个工作,但是我不确定我的方法是否正确。

我不想使用终止,因为我不确定未正确关闭的 COM 端口和其他事情发生了什么。

由于线程关闭可能需要一段时间(即使在我的简单循环线程上也需要几秒钟),我想显示一些小倒计时来告诉用户是的,关闭正在发生,只需要几秒钟。

我试图在主小部件的 QtextEdit 中显示它。但我认为这不起作用,因为我已经在我的方法中的 closeEvent 中。我还没有尝试额外的 QDialog 弹出窗口,但我想由于相同的原因它也不会工作。

有没有办法让这样的事情发生,以防止用户认为程序已经崩溃?

所以这就是我已经走了多远:

我的工人对象:

class Thread_Simulator(QtCore.QObject):
sigFin = QtCore.Signal()
sigText = QtCore.Signal(str)

def __init__(self):
    super().__init__()
    self.quit = 0

def run(self):
    i = 0
    while i < 10:
        i += 1
        self.sigText.emit(str(i))
        if self.quit == 1:
            #self.sigText.emit(__class__+" break")
            break
        sleep(2)

    self.sigFin.emit()

def end(self):
    self.quit = 1

我开始线程的地方:

    self.thread_test = QtCore.QThread()
    self.worker_test = Thread_Simulator()
    self.worker_test.moveToThread(self.thread_test)

    self.thread_test.started.connect(self.worker_test.run)
    self.worker_test.sigFin.connect(self.thread_test.quit)
    self.worker_test.sigFin.connect(self.worker_test.deleteLater)
    self.thread_test.finished.connect(self.thread_test.deleteLater)
    self.worker_test.sigText.connect(self.simulator_update)
    self.thread_test.start()

最后是我猜想当用户按下 x 按钮时发生的主应用程序的关闭事件。

def closeEvent(self, event):
    self.worker_test.end()
    print("EXITING -- Waiting for Threads to shut down")
    self.thread_test.wait(10000)
    
    return super().closeEvent(event)

另一个问题是,如果线程不再运行,关闭时会出错,因为线程已经被删除。我可以通过使用线程的完成信号设置另一个变量并检查它来解决这个问题。

也许有更好的方法来做到这一点。也让我能够展示我想到的这个倒计时的东西。


编辑:

好的,我尝试了一些事情,它可能很愚蠢,但它似乎是这样工作的。我认为我不妨让线程和工作人员保持活动状态直到程序结束,因为它们无论如何都不会改变并且可能会重新启动。因此,如果我让它们保持活动状态,它可能会占用更多内存,但重新启动工作人员也会更快,因为它们还活着。

所以我删除了 deleteLater 信号连接,而是在 closeEvent 中手动调用它们:

    self.thread_test = QtCore.QThread()
    self.worker_test = Thread_Simulator()
    self.worker_test.moveToThread(self.thread_test)

    self.thread_test.started.connect(self.worker_test.run)
    self.worker_test.sigFin.connect(self.thread_test.quit)
    self.worker_test.sigFin.connect(self.show_finished)
    #self.worker_test.sigFin.connect(self.worker_test.deleteLater)
    #self.thread_test.finished.connect(self.thread_test.deleteLater)
    self.worker_test.sigText.connect(self.simulator_update)
    self.thread_test.start()

我仍然无法显示某种消息来通知用户关闭过程(.append 不再显示)。关闭似乎工作得更快一些,并且“完成”信号仍然由工作人员正确发出。

def closeEvent(self, event): #: QtGui.QCloseEvent) -> None:
    self.log.append("EXITING -- Waiting for Threads to shut down")
    print("EXITING -- Waiting for Threads to shut down")
    self.worker_test.end()
    self.thread_test.quit()
    self.worker_test.deleteLater()
    self.thread_test.deleteLater()
    self.thread_test.wait(10000)
    
    return super().closeEvent(event)
4

1 回答 1

0

我仍然不知道这是否是正确的方法,但它对我来说是这样的。

我在主窗口的初始化中初始化了一个附加变量(self.end = None)。

我的 closeEvent 现在看起来像这样:

 def closeEvent(self, event):
    if self.thread_test.isRunning():
        print("Thread still running -- closing")
        self.worker_test.end()
        self.end = True
        self.show_shutdown_message()
        event.ignore()

    elif self.thread_test.isFinished():
        print("Thread finished -- ENDE")
        self.worker_test.deleteLater()
        self.thread_test.deleteLater()
        self.thread_test.wait(10000)
        event.accept()

工作线程的 sigFin 信号的 Slot 会对此进行检查,如果它被设置为其他任何值但没有,它将在工作线程完成后再次进入 closeEvent。

@QtCore.Slot()
def show_finished(self):
    print("Worker finished")
    if self.end is not None:
        self.close()

通过 self.show_shutdown_message() 的调用,我还可以显示一个小 QDialog 窗口,通知用户正在发生的事情。

如果有人知道更“官方”的方式来做到这一点,我仍然愿意接受建议:)

于 2021-07-28T10:29:44.053 回答