【问题标题】:How to kill a pure console application in PySide/PyQt?如何杀死 PySide/PyQt 中的纯控制台应用程序?
【发布时间】:2014-07-31 06:32:22
【问题描述】:

我正在尝试将代码从(旧式)PyQt 信号/插槽上的 Summerfield's article 转换为新式 PySide 代码。一个例子是一个纯控制台应用程序,我以前从未使用过它。不幸的是,当我尝试多次运行它时,我被告知之前的应用程序仍在运行。

这是一个简单的应用程序:它基本上可以让您设置一个数字,如果该数字是新的,则返回报告:

from PySide import QtCore
import sys

class TaxRate(QtCore.QObject):
    rateChangedSig=QtCore.Signal(float)

    def __init__(self):
        QtCore.QObject.__init__(self)
        self.rate = 17.5

    def getRate(self):
        return self.rate

    def setRate(self, newRate):
        if newRate != self.rate:
            self.rate = newRate
            self.rateChangedSig.emit(self.rate)  #was self.emit(SIGNAL("rateChanged"), self.rate)

@QtCore.Slot() #technically not really needed
def rateChangedSlot(value):
    print("Tax rate changed to {0:.2f} %".format(value))


if __name__=="__main__":
    qtApp = QtCore.QCoreApplication(sys.argv)  #origional had QtGui.QApplication, but there is no GUI
    vat = TaxRate()
    vat.rateChangedSig.connect(rateChangedSlot) #was vat.connect(vat, SIGNAL("rateChanged"), rateChanged)
    vat.setRate(8.5)     # A change will occur (new rate is different)

    qtApp.quit() 
    sys.exit(qtApp.exec_())

总的来说,它按预期工作,除了最后两行没有终止进程。当我尝试运行该程序两次时,第二次我的 IDE (Spyder) 总是告诉我它已经在一个单独的进程中运行。如果我尝试从命令行运行它,窗口就会挂起。

奇怪的是,当我注释掉最后两行时,我没有收到此警告。这与我的预期相反(基于之前使用 PySide GUI 应用程序和the documentation for quit() 的经验)。

按照 Zetcode 的 Closing a window 示例,我尝试将 qtApp.quit() 替换为 qtApp.instance().quit(),这产生了相同的非杀戮结果。

那么,我该如何杀死这个东西呢?

一个想法是,我什至不应该一开始就启动它 (as suggested here)。尽管它是一个纯控制台应用程序,但 Summerfield 的原始程序使用app=QtGui.QApplication(sys.argv) 进行初始化,并且它不包含最后两行。事情运行良好,多次。但是,是否担心每次运行都会创建一个新进程,所以他的程序似乎在没有警告的情况下有效地增加了进程? (请注意,在实践中,我认为我的系统上不会发生这种情况,因此由于我不明白的原因,答案似乎是“否”)。

使用 PySide 控制/初始化/终止控制台应用程序的正确方法是什么?

(暂时忽略了这个问题,为什么人们会在 Python as has been pointed out previously 中将 PySide 用于纯控制台应用程序。但如果有人有兴趣回答这个单独的问题,我可以单独开始问题)。


可能相关的帖子:

【问题讨论】:

标签: python qt pyqt pyside


【解决方案1】:

问题是因为您在调用QCoreApplication.exec_() 之前调用了QCoreApplication.quit()。对quit 的调用不会在事件循环中排队,它会立即发生。对QCoreApplication.exec_() 的调用会启动事件循环,只有在事件循环运行时调用QCoreApplication.exit()(或QCoreApplication.quit())时才会结束。

这在Qt documentation of QCoreApplication 中有所解释,但很容易错过。

我想您实际上不需要调用exec_(),因为您没有在当前代码中使用任何事件(大多数事件与窗口/鼠标/键盘有关,尽管您可能会在未来使用一些事件,例如由QTimer 生成的那些)。这真的取决于你将来想用这个程序做什么。 如果你不调用exec_(),那么你的脚本将会像你通常期望的任何Python脚本那样退出(你的代码中唯一的阻塞函数是对exec_()的调用,删除它并且没有任何东西让它继续运行。)

【讨论】:

  • 我最初并没有退出那里:没有它,进程仍然活着(基本上,只要我调用 exec_(),无论我做什么它似乎都活着) .如您所料,我添加了quit,希望它会进入事件队列。根据您的评论,我也尝试过拆分:qtApp.exec_(); qtApp.instance.quit(); sys.exit();。没有运气,过程仍然存在。我怎么杀了这个东西?如果调用 exec_() 真的很重要怎么办?关键是对于纯控制台应用程序,它不仅不重要,而且永远不应该吗?这是记录在案的,还是后天习得的?
  • qtApp.exec_() 是一个阻塞函数。它启动一个事件循环,直到有东西向它发布事件才会结束。因此,该调用之后的任何代码都不会运行(因为事件循环永远不会完成)。大多数事件是鼠标点击等,但你显然没有这些。 QTimer 是少数会发布事件的事物之一(但您显然需要在事件循环开始之前编写执行该操作的代码 - 事件将被放置在队列中,直到循环开始) .其他可能包括 Qt 网络库(但老实说,我没有完整的列表!)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多