2017-10-13 58 views
2

我有一個應用程序可以從命令行啓動,使用可選的文件名作爲參數。如果存在這個文件應該在啓動時加載。由於文件的處理需要一些時間,因此fileOpen()會阻止程序並顯示加載指示符。完成GUI呈現後,在程序啓動時執行長時間運行的代碼

在正常操作期間,這沒關係。但是,當我嘗試在啓動時執行相同操作(如下所示)時,窗口的輪廓出現在show()之後,但其內容直到app.exec_()才呈現。

我的問題:我該如何處理這種情況?

  • app.exec_()之前,我不能把fileOpen()因爲那時GUI尚未完全呈現。而且我不能通知用戶加載仍在處理中。
  • 我不能放?之後app.exec_()因爲它不會被執行直到程序結束。

示例代碼:

def main(args): 
    app = QtGui.QApplication() 
    mainwindow = MainWindow() 
    mainwindow.show() 
    if args.filename: 
     mainwindow.fileOpen(args.filename) 
    ret_val = app.exec_() 
    sys.exit(ret_val) 

if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument('filename', help='(optional) file to load at startup') 
    args = parser.parse_args() 
    main(args) 
+0

你是什麼意思,當你說:**圖形用戶界面還沒有完全呈現**? – eyllanesc

+0

嘗試在fileOpen()內調用qApp.processEvents() – eyllanesc

回答

0

我發現,單次定時器可以解決這個問題,但我只用Openbox的窗口管理器測試它在Linux上,所以我不能保證它可以在所有平臺上運行。您可能需要調整超時的持續時間以使其在您的系統上正常工作。

下面是一個簡單的演示,對我的作品:

import sys 
from PyQt5 import QtCore, QtWidgets 

class MainWindow(QtWidgets.QWidget): 
    def __init__(self): 
     super(MainWindow, self).__init__() 
     self.edit = QtWidgets.QTextEdit(self) 
     layout = QtWidgets.QVBoxLayout(self) 
     layout.addWidget(self.edit) 

    def fileOpen(self, path): 
     QtWidgets.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) 
     QtCore.QThread.sleep(3) 
     self.edit.setText(open(path).read()) 
     QtWidgets.qApp.restoreOverrideCursor() 

def main(): 
    app = QtWidgets.QApplication(sys.argv) 
    mainwindow = MainWindow() 
    mainwindow.setGeometry(600, 100, 300, 200) 
    mainwindow.show() 
    QtCore.QTimer.singleShot(50, lambda: mainwindow.fileOpen(__file__)) 
    sys.exit(app.exec_()) 

if __name__ == '__main__': 

    main() 
0

注意:此方法不適用於Linux操作系統(X11)工作(見註釋並ekhumoro答案)

感謝所有答案。雖然他們每個人都有一些缺點(將在下面討論),他們把我帶到了正確的解決方案:

呼叫qApp.processEvents()mainwindow.show():這正是我們想要做的:

def main(args): 
    app = QtGui.QApplication() 
    mainwindow = MainWindow() 
    mainwindow.show() 
    qApp.processEvents() 
    if args.filename: 
     mainwindow.fileOpen(args.filename) 
    ret_val = app.exec_() 
    sys.exit(ret_val) 

原因:

  • 我們想要處理與主窗口繪圖相關的事件。
  • 然後執行我們的自定義代碼。
  • 然後繼續正常的事件循環。

的其他建議討論:

爲什麼我不叫qApp.processEvents()fileOpen():這將是積極的所有fileOpen()電話。在長時間運行的文件公開呼叫期間處理其他事件可能會導致意外的行爲,如果應用程序沒有按照這個設計,例如,您可以在第一次運行時發出第二個fileOpen()

爲什麼我不使用定時器來執行fileOpen():我想在GUI完全加載之後但在任何用戶輸入之前執行代碼。計時器只是正確執行正確的執行順序。此外,根據CPU,系統使用情況和其他因素,正確的延遲可能會有所不同,從而使該解決方案不夠穩固。

+0

此解決方案在X11(Linux)上不起作用。調用'qApp.processEvents()'在那裏沒有任何效果,因爲窗口管理器異步創建窗口框架(所以您正在等待* system * -level事件,而不是* application * -level事件)。某種完全跨平臺的解決方案需要基於定時器的解決方案。當然,您可以檢測平臺並相應地應用不同的方法。 (有關更多詳細信息,請參見[X11特性](https://doc.qt.io/qt-5/application-windows.html#x11-peculiarities))。 – ekhumoro

相關問題