簡體   English   中英

多次運行和退出 PyQt 應用程序

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM