![](/img/trans.png)
[英]How do I open (and close) a PyQt5 application inside a loop, and get that loop running multiple times
[英]Running and exiting PyQt application multiple times
我正在使用 PyQt 創建我自己的棋盤游戲Battleship版本。 PyQt 主窗口包含自己的和敵人的板。 棋盤由玩家“開火”的可點擊圖塊組成。 該實現支持 HUMANvsAI 和 AIvsAI 游戲。 我想通過模擬測試我的 AI 算法的強度。 例如,我想循環運行 1,000 個 AIvsAI 游戲,並獲取有關勝利百分比、平均准確率等的統計數據。
我正在努力多次運行 PyQt 應用程序來收集游戲數據,例如在 for 循環中。 具體來說,我找不到運行該應用程序、退出它並再次重新運行它的方法。 從概念上講,我正在尋找這樣的東西:
# conceptual snippet for i in range(n): app = QApplication([]) window = MainWindow(b_size, boat_dict, players) app.exec_()
調用在其他地方退出應用程序並在每次游戲結束時調用:
# conceptual snippet if is_game_over(): sys.exit(app.exec_())
但是這個簡單的解決方案打破了 for 循環。 歡迎任何關於如何多次運行和退出 PyQt 應用程序的反饋,無論是順序(例如 for 循環方法)還是並行線程。
您不應該使用sys.exit()
因為該指令用於終止程序的執行,如果您想終止 Qt 應用程序,您必須使用QCoreApplication::quit()
(或QCoreApplication::exit(0)
)。 此外,另一個改進是使用多處理:
import random
from multiprocessing import Pool
from PyQt5 import QtCore, QtWidgets
def create_app(i):
app = QtWidgets.QApplication([])
w = QtWidgets.QMainWindow()
w.setWindowTitle("Game-{}".format(i))
w.show()
# emulate end-game
def end_game():
QtCore.QCoreApplication.quit()
timeout = random.randint(1000, 2000) # 1000-2000 milliseconds
QtCore.QTimer.singleShot(timeout, end_game)
app.exec_()
# emulate results
o = {"victory": random.randint(0, 101), "average": random.randint(0, 101)}
return o
def main():
results = []
pool = Pool(processes=8)
for i in range(1000):
r = pool.apply_async(create_app, args=(i,))
results.append(r)
pool.close()
pool.join()
print([result.get() for result in results])
if __name__ == "__main__":
main()
我必須告訴你,你的問題危險地接近“過於寬泛”的旗幟。 真正的問題是:您希望如何跟蹤收集到的數據,以及您希望如何處理這些數據? 這個問題可能有很多答案。
正如您已經發現的那樣,您不能使用sys.exit
,但您可以以不同的方式收集數據。
如果您要在受控環境中運行您的應用程序,一個可能的解決方案是序列化您收集的數據,同時控制來自應用程序的整個“收集”過程
半偽代碼:
from PyQt5 import QtCore, QtWidgets
import json
class BattleShipWindow(QtWidgets.QMainWindow):
restart = QtCore.pyqtSignal()
# ...
def storeData(self, data):
# get the app data location
appDir = QtWidgets.QStandardPath.standardLocations(
QtCore.QStandardaPaths.AppDataLocation)[0]
# if it doesn't exists, create it
if not QtCore.QFile.exists(appDir):
QtCore.QDir().mkpath(appDir)
now = QtCore.QDateTime.currentDateTime()
fileName = str(now.toMSecsSinceEpoch() // 1000)
# write down the data
with open(os.path.join(appDir, fileName), 'w') as df:
df.write(json.dumps(data))
def getGameData(self):
# gather your own data here, this is just an example
return {'gameData': [1, 2, 3]}
def closeEvent(self, event):
if QtWidgets.QMessageBox.question(
self, 'Play again?',
'Play another game?',
QtWidgets.QMessageBox.Yes|QtWidgets.QMessageBox.No
) == QtWidgets.QMessageBox.Yes:
self.storeData(self.getGameData())
self.restart.emit()
class BattleShipApp(QtWidgets.QApplication):
def restart(self):
self.currentGame = BattleShipWindow()
self.currentGame.restart.connect(self.restart)
self.currentGame.show()
def exec_(self):
self.currentGame = BattleShipWindow()
self.currentGame.restart.connect(self.restart)
self.currentGame.show()
super(BattleShipApp, self).exec_()
if __name__ == '__main__':
import sys
app = BattleShipApp(sys.argv)
sys.exit(app.exec_())
注意:這是一個[半]偽代碼,我顯然沒有測試過。 它的目的是展示它的行為方式,所以不要指望它按原樣工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.