Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
96 views
in Technique[技术] by (71.8m points)

python - execute ping command with GUI

While writing a GUI application in PyQt5 I encounter weird(for me) behavior. When I wanted to open an information window and start doing another thing after it fully loads. I noticed that the information window does not load fully until the next block of code is done.

This is how it looks

enter image description here

Code that reproduces this unwanted behavior

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())

Behavior is the same whether I use QMessegBox, inherit it in another class or write my own QMeesgeBox type class.

I guess this behavior works like this because of os.system() function and I would use Process or Thread to make a workaround, but if It is possible I would like to ensure that window is fully loaded and then the next procedure is taking place.

Python version 3.7.0

PyQt5 version 5.12.1

question from:https://stackoverflow.com/questions/66057399/pyqt5-application-getting-not-responding

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Although the solutions of S.Nick and Guimoute seems to work but the reality is that it has only made the window show a moment but if you want to interact with it you will see that it is frozen, for example try to move the window to check it. The os.system() task is blocking so it must be executed in another thread

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_())

Or use 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_())

Update

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_())

Another Option:

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)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...