【问题标题】:execute ping command with GUI使用 GUI 执行 ping 命令
【发布时间】:2019-04-24 06:57:25
【问题描述】:

在 PyQt5 中编写 GUI 应用程序时,我遇到了奇怪的(对我来说)行为。 当我想打开一个信息窗口并在它完全加载后开始做另一件事时。我注意到在下一个代码块完成之前,信息窗口不会完全加载。

看起来是这样的

重现这种不良行为的代码

from PyQt5.QtWidgets import QApplication,QMessageBox
import sys
import os
app = QApplication(sys.argv)

box = QMessageBox()
box.setText("Text")
box.show()
os.system("ping 8.8.8.8 ")


sys.exit(app.exec())

无论我使用 QMessegBox,在另一个类中继承它还是编写自己的 QMeesgeBox 类型类,行为都是相同的。

我猜这种行为是由于 os.system() 函数而起作用的,我会使用 Process 或 Thread 来解决问题,但如果可能的话,我想确保窗口已完全加载,然后执行下一个过程正在发生。

Python 3.7.0 版

PyQt5 版本 5.12.1

【问题讨论】:

  • 您没有在消息框中添加父级,可能是因为这个?
  • 设置父级时出现同样的错误。
  • @AdrianBaczyński 检查我的答案,因为 S.Nick 的答案不正确

标签: python python-3.x pyqt pyqt5


【解决方案1】:

虽然 S.Nick 和 Guimoute 的解决方案似乎有效,但现实情况是它只让窗口显示了片刻,但如果你想与它交互,你会看到它被冻结,例如尝试移动检查它的窗口。 os.system() 任务正在阻塞,所以它必须在另一个线程中执行

import os
import sys
from PyQt5.QtWidgets import QApplication,QMessageBox

import threading
app = QApplication(sys.argv)

box = QMessageBox()
box.setText("Text")
box.show()

def task():
    os.system("ping 8.8.8.8 ") 
threading.Thread(target=task, daemon=True).start()
# or threading.Thread(target=os.system, args=("ping 8.8.8.8 ",), daemon=True).start()
sys.exit(app.exec_())

或者使用QProcess:

import sys
import os
from PyQt5.QtWidgets import QApplication,QMessageBox
from PyQt5.QtCore import QProcess

app = QApplication(sys.argv)

box = QMessageBox()
box.setText("Text")
box.show()

def on_readyReadStandardOutput():
    print(process.readAllStandardOutput().data().decode(), end="")

process = QProcess()
process.start("ping", ["8.8.8.8"])
process.readyReadStandardOutput.connect(on_readyReadStandardOutput)
sys.exit(app.exec_())

更新

import os
import sys
from PyQt5 import QtCore, QtWidgets


class PingObject(QtCore.QObject):
    finished = QtCore.pyqtSignal()

    @QtCore.pyqtSlot()
    def start(self):
        os.system("ping 8.8.8.8")
        self.finished.emit()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    box = QtWidgets.QMessageBox()
    box.setText("Text")
    box.show()
    thread = QtCore.QThread()
    thread.start()
    ping = PingObject()
    ping.moveToThread(thread)
    QtCore.QTimer.singleShot(0, ping.start)
    loop = QtCore.QEventLoop()
    ping.finished.connect(loop.quit)
    loop.exec_()
    print("finished ping")
    sys.exit(app.exec_())

另一种选择:

import os
import sys
from PyQt5 import QtCore, QtWidgets


class Thread(QtCore.QThread):
    def run(self):
        response = os.popen("ping 8.8.8.8")
        for line in response.readlines():
            print(line)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    box = QtWidgets.QMessageBox()
    box.setText("Text")
    box.show()

    thread = Thread()
    thread.start()
    ret = app.exec_()
    thread.quit()
    thread.wait()
    sys.exit(ret)

【讨论】:

  • 你的程序的线程版本对我不起作用,它以同样的方式阻塞。 QProcess() 方法在窗口在屏幕上移动时阻塞 os.system。
  • @AdrianBaczyński 真奇怪,你是在执行我的代码而不修改它吗?可能你修改错了
  • 是的,你说得对,线程上的“join()”函数会导致这种行为。
  • @AdrianBaczyński join 阻塞了线程被抛出的线程,所以现在该块不是由 os.system() 而是通过 join,在 GUI 中你不应该使用 join 因为 eventloop 实现了类似的功能
  • 你能告诉我如何使用你的线程代码来等待线程工作完成吗?
【解决方案2】:

这是一个单行解决方案:

from PyQt5.QtWidgets import QApplication,QMessageBox
import sys
import os
app = QApplication(sys.argv)

box = QMessageBox()
box.setText("Text")
box.show()
QApplication.processEvents() # <------------ this one
os.system("ping 8.8.8.8 ")

sys.exit(app.exec())

【讨论】:

  • 窗口仍然被阻塞,但行为最接近我想要的行为
  • processEvents 只是一个假的解决方案,例如尝试移动窗口,你会看到窗口被冻结
  • @eyllanesc OP 希望窗口在执行其他任务之前完全加载,没有关于窗口响应的规范。
  • @Guimute 恕我直言,窗口的响应能力是所有 GUI 的要求,没有人喜欢冻结的 GUI。所以没有必要在里面显式。
【解决方案3】:

作为一种选择。试试看:

import sys
import os
from PyQt5.QtWidgets import QApplication,QMessageBox
from PyQt5.QtCore import QTimer

app = QApplication(sys.argv)

box = QMessageBox()
box.setText("Text")
box.show()

def osSystem():
    os.system("ping 8.8.8.8 ") 

QTimer.singleShot(20, osSystem )

#os.system("ping 8.8.8.8 ")


sys.exit(app.exec())

【讨论】:

  • 这行 "QTimer.singleShot(20, osSystem )" 结束后最好的等待方式是什么?
  • 你的方法不对,比如阻止了窗口移动
猜你喜欢
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
  • 1970-01-01
  • 2021-10-23
  • 2014-05-17
  • 1970-01-01
  • 2016-06-23
相关资源
最近更新 更多