2014-07-14 106 views
1

我正在用PyQt製作端口掃描器程序,但是當我激活循環時Gui會凍結。我該如何解決這個問題?我添加了time.sleep()函數,但它仍然凍結。這是它凍結的功能。謝謝。Pyqt Gui在循環中凍結

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

回答

4

你應該內調用QtCore.QCoreApplication.processEvents()你的for循環,使Qt的事件循環繼續傳入事件(從鍵盤或鼠標)。

+0

謝謝,它現在工作。 – user3755771

4

儘管現在調用QtCore.QCoreApplication.processEvents()現在可以使用,但我在網絡上的很多地方都讀過它應該是最後的選擇。不幸的是,沒有一個源解釋清楚爲什麼 - 但見例如

所以它似乎允許的,但在一般情況下,似乎是使用QTimerQThread更好的設計。

+1

我同意這一點。我還會在單獨的線程(或線程池)中執行此操作,並將消息發送到GUI線程。我剛剛提供了一個快速修復。 – Antoine

+0

我在[Qt的C++文檔](http://qt-project.org/doc/qt-4.8/thread-basics.html)中找到了解釋:在耗時的計算過程中重複調用QEventLoop :: processEvents()防止GUI阻塞。然而,這個解決方案不能很好地擴展,因爲對processEvents()的調用可能經常發生,或者經常發生,這取決於硬件。 – Antoine

+0

再次感謝。我會看他們 – user3755771