[英]QApplication in a non-main thread of second process with pyQt4: is this code legal, and if not, why does it work?
我和我的合作者用 python 2.7 和 pyQt4 編寫了一個集成開發環境 (IDE),它已經完美運行了十多年。 我現在必須將它移植到 pyqt5,但我遇到了幾個問題。 這篇文章與我的第一個問題有關。 在將其聲明為重復之前,請仔細閱讀底部的問題。 這是因為我不明白我在這里問其他精確問題的相關帖子中的答案。
我的 IDE 的架構如下:
第二個進程(比如 P2)由 P1 創建。 P2 的主線程運行無限循環,等待來自 P1 的代碼片段(通過隊列)在 P2 的不同非主線程中執行。
雖然大部分要運行的代碼段是非 gui 的,但 P2 的一個(並且只有一個)非主線程是一個 Qt 線程,運行一個可以運行 Qt 代碼段的 QApplication。
這個 QApplication(比如 app)有一個以 app.exec_() 開始的正常事件循環,但也可以接收一個帶有 gui 函數的信號,作為相應插槽的參數運行。
這是用於此的代碼,它完美地工作。 (遺憾的是我不能在這里粘貼合理大小的獨立代碼,但應該足以理解和回答問題)
"""
This model helps to execute GUI code in a QT thread.
"""
import time, sys
from threading import Thread
from PyQt4.QtCore import *
from PyQt4.QtGui import *
#from pyview.identifyThreads import identify
signalConnected = False
def _runGuiCodeSignal(f):
f()
def execInGui(f):
_ensureGuiThreadIsRunning()
global app
if app == None:
raise Exception("Invalid application handle!")
app.emit(SIGNAL("runGuiCode(PyQt_PyObject)"), f)
def _createApplication():
#from pyview.identifyThreads import identify
global app
global signalConnected
global _runGuiCodeSignal
app = QApplication(sys.argv) #
app.setQuitOnLastWindowClosed(False) #
app.connect(app, SIGNAL("runGuiCode(PyQt_PyObject)"), _runGuiCodeSignal, Qt.QueuedConnection | Qt.UniqueConnection)
signalConnected = True
if app.thread() != QThread.currentThread():
raise Exception("Cannot start QT application from side thread! You will have to restart your process...")
#identify(message='in createApplication just before app.exec')
app.exec_()
def _ensureGuiThreadIsRunning():
#from pyview.identifyThreads import identify
global app
global signalConnected
global _runGuiCodeSignal
app = QApplication.instance()
if app == None:
thread = Thread(target=_createApplication)
#identify('in _ensureGuiThreadIsRunning')
print "Creating new Qt application in thread ", thread
thread.daemon = True
thread.start()
while thread.is_alive() and (app == None or app.startingUp()):
time.sleep(0.01)
else:
if not signalConnected:
print app.connect(app, SIGNAL("runGuiCode(PyQt_PyObject)"), _runGuiCodeSignal,
Qt.QueuedConnection | Qt.UniqueConnection)
signalConnected = True
當定義一個函數 f 來創建一個帶有各種小部件的 QWindow,並在 P2 的任何線程中運行 execinGUI(f) 時,QApplication 是在一個新的其他非主線程中創建的,或者如果它已經存在則被檢索(像這樣只有一個進程 P2 中的 QThread),一切正常。
現在我的問題是:
上面的代碼是否違反了任何 Qt4 規則,因為它在非主線程中啟動了 QApplication?
QT4文檔的哪一頁告訴我們禁止像我們所做的那樣處理?
進程主線程的定義是什么? 運行 process.run() 函數的線程?
什么是 Qt 主線程? 根據定義,它是進程的主線程還是可以是另一個線程?
為什么我們沒有錯誤“QApplication 未在主線程中創建”?
Qt4 如何識別事件循環是否在進程的主線程中運行?
對這些問題的答案的很多元素在這里問,可以發現有(同時看到答案和評論,從JKSH特別是)。
總而言之,“主線程”的含義對於 Qt 和系統而言可能不同,具體取決於平台。 在 linux 和 windows 上,Qt 的主線程只是第一個與 Qt 相關的線程(小心所有其他線程中的導入)。 它不是運行 process.run() 的線程。 在 OS X 中,情況有所不同,Qt 和進程的“主線程”是相同的。 在這方面,這些文件似乎被專家認為是不准確的......
因此,對這篇文章的確切問題的初步答案是:
1) 上面的代碼是否違反了任何 Qt4 規則,因為它在非主線程中啟動了 QApplication?
=> 沒有
2)QT4文檔的哪一頁告訴我們禁止像我們所做的那樣處理?
=> 無,因為“主線程”從未在 pyQt4 文檔中正確定義
3)進程主線程的定義是什么? 運行 process.run() 函數的線程?
=> 是的
4)什么是Qt主線程? 根據定義,它是進程的主線程還是可以是另一個線程?
=> 它是引用第一個 Qt 對象的線程(注意進程主線程中的導入)。 它不是進程的主線程。 它們可以不同。
5)為什么我們沒有錯誤“QApplication was not created in the main thread”?
=> 因為它是在Qt所謂的“主線程”中創建的,雖然它與進程所謂的“主線程”不同。
6) Qt4 如何識別事件循環是否在進程的主線程中運行?
=> 它根本不在 Windows 和 linux 上。
如果此答案包含任何錯誤,請更正此答案。
Qt 文檔中沒有明確定義主線程的概念。 實際上,進程的主線程(執行 Process.run 函數的進程)可以不同於主 Qt 線程(像 QApplication 一樣實例化第一個 Qt 對象的線程),盡管兩個“主”線程通常是相同的.
有效代碼結構示例:
下面的函數將在進程'非主線程'thread-1'中運行,它將立即成為Qt的主線程。
def startThread1():
app = QApplication(sys.argv)
app.exec_() # enter event loop
下面的代碼在進程的主線程中運行,不要與進程的主 Qt 和獨特的 GUI 線程混淆。
thread1 = Thread(target=self.startThread1)
thread1.start()
input('I am busy until you press enter')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.