Pyqt Gui 在循环中冻结
Posted
技术标签:
【中文标题】Pyqt Gui 在循环中冻结【英文标题】:Pyqt Gui Freezes while in loop 【发布时间】:2014-07-14 14:01:57 【问题描述】:我正在使用 PyQt 制作端口扫描程序,但是当我激活循环时 Gui 冻结。我该如何解决这个问题?我添加了 time.sleep() 函数,但它仍然冻结。这是它冻结的功能。谢谢。
try:
time.sleep(1)
hostname=self.adres.text()
hostip=socket.gethostbyname(hostname)
uyari1="Scanning remote host, \n".format(hostip)
self.durum.append(uyari1)
print(uyari1)
for port in range(1,1025):
time.sleep(0.1)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex((hostip, port))
if result == 0:
time.sleep(0.01)
print ("Port : \t Open".format(port))
self.durum.append("Port : \t Open\n".format(port))
sock.close()
完整代码:
import socket,os,time
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(596, 412)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.label = QtGui.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(120, -10, 331, 91))
self.label.setObjectName(_fromUtf8("label"))
self.label_2 = QtGui.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(10, 90, 91, 16))
self.label_2.setObjectName(_fromUtf8("label_2"))
self.adres = QtGui.QLineEdit(self.centralwidget)
self.adres.setGeometry(QtCore.QRect(100, 90, 371, 22))
self.adres.setObjectName(_fromUtf8("adres"))
self.durum = QtGui.QTextEdit(self.centralwidget)
self.durum.setGeometry(QtCore.QRect(10, 140, 571, 191))
self.durum.setObjectName(_fromUtf8("durum"))
self.baslat = QtGui.QPushButton(self.centralwidget)
self.baslat.setGeometry(QtCore.QRect(480, 90, 101, 21))
self.baslat.setObjectName(_fromUtf8("baslat"))
self.dosyaya = QtGui.QPushButton(self.centralwidget)
self.dosyaya.setGeometry(QtCore.QRect(490, 340, 91, 25))
self.dosyaya.setObjectName(_fromUtf8("dosyaya"))
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 596, 21))
self.menubar.setObjectName(_fromUtf8("menubar"))
MainWindow.setMenuBar(self.menubar)
self.hakkindaa = QtGui.QPushButton(self.centralwidget)
self.hakkindaa.setGeometry(QtCore.QRect(10, 340, 91, 25))
self.hakkindaa.setObjectName(_fromUtf8("hakkindaa"))
self.hakkindaa.setText("Hakkında")
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
MainWindow.setStatusBar(self.statusbar)
QtCore.QObject.connect(self.hakkindaa, QtCore.SIGNAL(_fromUtf8("clicked()")), self.hakkinda)
QtCore.QObject.connect(self.dosyaya, QtCore.SIGNAL(_fromUtf8("clicked()")), self.dosyayaya)
QtCore.QObject.connect(self.baslat, QtCore.SIGNAL(_fromUtf8("clicked()")), self.baslat_btn)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def hakkinda(self):
QtGui.QMessageBox.about(None, "About", "Ege Öz 2014")
def baslat_btn(self):
try:
time.sleep(1)
hostname=self.adres.text()
hostip=socket.gethostbyname(hostname)
uyari1="Scanning remote host, \n".format(hostip)
self.durum.append(uyari1)
print(uyari1)
for port in range(1,1025):
time.sleep(0.1)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex((hostip, port))
if result == 0:
time.sleep(0.01)
print ("Port : \t Open".format(port))
self.durum.append("Port : \t Open\n".format(port))
sock.close()
except socket.gaierror:
self.durum.append("Hostname could not be resolved.")
print("Hostname could not be resolved.")
self.adres.setText("")
except socket.error:
self.durum.append("Could not connect to server.")
print("Could not connect to server.")
self.adres.setText("")
def dosyayaya(self):
self.durum.append("Saving log file to home directory...")
ev=os.getenv("USER")
data=self.durum.toPlainText()
yol="/home/"+ev+"/portscanner.log"
f = open (yol,"w")
f.write(data)
f.close()
self.durum.append("Log file saved.")
print ("Log file saved.")
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "Port Scanner", None))
self.label.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:11pt; font-weight:600;\">Port Scanner</span></p><p>Enter the remote host adress and press start.</p></body></html>", None))
self.label_2.setText(_translate("MainWindow", "Remote Host:", None))
self.baslat.setText(_translate("MainWindow", "Start Scanning", None))
self.dosyaya.setText(_translate("MainWindow", "Save to file", None))
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
【问题讨论】:
【参考方案1】:您应该在 for 循环中调用 QtCore.QCoreApplication.processEvents()
以使 Qt 的事件循环继续传入事件(来自键盘或鼠标)。
【讨论】:
【参考方案2】:虽然现在调用QtCore.QCoreApplication.processEvents()
有效,但我在网络上的许多地方都读到它应该是最后的手段。不幸的是,没有一个消息来源清楚地解释了原因——但请参见示例
所以这似乎是允许的,但总的来说,使用QTimer
或QThread
似乎是更好的设计。
【讨论】:
我同意这一点。我也宁愿在单独的线程(或线程池)中执行此操作并将消息发送到 GUI 线程。我刚刚提供了一个快速修复。 我在Qt's C++ doc 中找到了解释:在耗时的计算过程中重复调用 QEventLoop::processEvents() 可以防止 GUI 阻塞。但是,此解决方案不能很好地扩展,因为对 processEvents() 的调用可能发生得太频繁或不够频繁,具体取决于硬件。 再次感谢。我去看看以上是关于Pyqt Gui 在循环中冻结的主要内容,如果未能解决你的问题,请参考以下文章
PyQt5如何使用python在迭代循环中更新单元格值Qtablewidget