Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 多个编程单击事件的意外行为_Python_Qt_Pyqt_Pyqt5 - Fatal编程技术网

Python 多个编程单击事件的意外行为

Python 多个编程单击事件的意外行为,python,qt,pyqt,pyqt5,Python,Qt,Pyqt,Pyqt5,我正在尝试使用PyQt5制作一个Tic-Tac-Toe用户界面。提供了三种模式 人与人 人类vs.人工智能 人工智能vs.人工智能游戏 所有模式都非常好,除了在模式3中,两个AI相互对抗,UI将开始加载并显示最终结果,而不是刷新每个回合的中间步骤,直到游戏开始,这是我所期望和首选的。我怎样才能做到呢?谢谢大家! 下面是我的代码: class TicTacToeUI(QtWidgets.QWidget): icons = ['icons/x-mark.png', 'icons/hollow

我正在尝试使用PyQt5制作一个Tic-Tac-Toe用户界面。提供了三种模式

人与人 人类vs.人工智能 人工智能vs.人工智能游戏 所有模式都非常好,除了在模式3中,两个AI相互对抗,UI将开始加载并显示最终结果,而不是刷新每个回合的中间步骤,直到游戏开始,这是我所期望和首选的。我怎样才能做到呢?谢谢大家!

下面是我的代码:

class TicTacToeUI(QtWidgets.QWidget):
    icons = ['icons/x-mark.png', 'icons/hollow-circle.png']

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("TicTacToe")
        self.setStyleSheet('background-color: #D7CCC8;')
        # Players
        self._players_selector = QtWidgets.QGridLayout()
        self._players = list()
        for p in range(2):
            label = QtWidgets.QLabel('Player {:}'.format(p))
            selectbox = QtWidgets.QComboBox()
            selectbox.setFixedHeight(24)
            selectbox.addItems(list(PLAYERS.keys()))
            self._players_selector.addWidget(label, 0, p)
            self._players_selector.addWidget(selectbox, 1, p)
            self._players.append(selectbox)
        self._grid = QtWidgets.QGridLayout()
        self._gameboard_buttons = dict()
        for i in range(self.m):
            for j in range(self.n):
                btn = self.create_gameboard_button(row=i, col=j)
                self._grid.addWidget(btn, i, j)
                self._gameboard_buttons.update({(i, j): btn})
        self._message_box = QtWidgets.QLabel('', parent=self)
        self._restart_button = QtWidgets.QPushButton('Start', parent=self)
        self._restart_button.setFixedHeight(32)
        self._restart_button.clicked.connect(self.restart)
        # Layout
        self._layout = QtWidgets.QVBoxLayout()
        self._layout.addLayout(self._players_selector)
        self._layout.addLayout(self._grid)
        self._layout.addWidget(self._message_box)
        self._layout.addWidget(self._restart_button)
        self.setLayout(self._layout)
        # The game
        self._game = TicTacToe()
        self._started = False

    def create_gameboard_button(self, row, col):
        btn = TicTacToeUIButton('', parent=self, style_sheet='background-color: #D7CCC8;')
        btn.setFixedSize(64, 64)
        btn.clicked.connect(functools.partial(self.click, row, col))
        return btn

    def click(self, row, col):
        if not self._started:
            pass
        elif self._game.is_ended:
            pass
        else:
            btn = self._gameboard_buttons.get((row, col))
            if btn is not None:
                if btn.is_occupied:
                    msg = 'It is occupied. Please select another one.'
                    self._message_box.setText(msg)
                else:
                    player = self._game.turn_player
                    # Icon appearance
                    for _, b in self._gameboard_buttons.items():
                        b.remove_border()
                    btn.setIcon(QtGui.QIcon(self.icons[player]))
                    btn.setIconSize(QtCore.QSize(48, 48))
                    btn.add_border('border: 1px solid #FF0000;')
                    btn.occupied_player = player
                    # Check result
                    self._game.move(row=row, col=col, player=player)
                    if self._game.winner is not None:
                        if self._game.winner == -1:
                            msg = 'Draw. What a game!'
                        else:
                            msg = 'Player {:} won. Congratulations!'
                            msg = msg.format(self._game.winner)
                    else:
                        msg = ''
                    self._message_box.setText(msg)
            # Next turn
            if self._game.is_ended:
                pass
            else:
                self._game.players[self._game.turn_player].decide_ui(self)

    def reset(self):
        self._started = True
        self._game.reset()
        self._game.player0 = PLAYERS.get(self._players[0].currentText())
        self._game.player1 = PLAYERS.get(self._players[1].currentText())
        self._restart_button.setText('Restart')
        self._message_box.setText('')
        for _, btn in self._gameboard_buttons.items():
            btn.reset()
        if self._game.player0.is_ai:
            self._game._player0.decide_ui(self)

    def restart(self):
        self.reset()
一些注意事项:

游戏将在点击“开始”/“重新启动”按钮后立即开始,玩家(无论是人类还是AI)将根据他们的判断/算法点击游戏板按钮

人类自己什么都不做,而 SomeAI.decision\u用户将根据某些算法单击游戏板按钮

TictaToe是一个存储游戏板矩阵和获胜标准的对象


如果您对玩游戏感兴趣,可以下载整套代码。

为了更好地了解整个过程,我下载了完整的应用程序

因此,在运行时,AI会让主进程保持忙碌状态,而Qt事件永远不会被处理,UI上也不会绘制任何内容

最简单的解决方案是调用每个回合,如下所示:

def click(self, row, col):
    # "click" code

    QtWidgets.qApp.processEvents()

    # Next turn
    if self._game.is_ended:
        pass
    else:
        self._game.players[self._game.turn_player].decide_ui(self)

这将处理所有未决事件,同时将显示一个动作。

您可能需要降低AI完成游戏的速度。您可以使用QTimer类进行实验。@Crispin我的一些AI每回合可能需要1-2秒,但加载几秒钟后,最终结果将直接显示出来。中间的部分看不见。