与 Xbox 控制器的 GUI 交互

GUI Interaction with Xbox Controller

我希望能够使用使用 QT Designer 创建的 PyQt5 在非常简单的 GUI 上显示 Xbox 控制器事件。 我正在使用 xbox360controller Python 包将控制器与我的 Python 接口进行通信。以下示例代码可以正常工作,而不是打印值我想在 GUI 上的唯一标签上设置文本:

import signal
from xbox360controller import Xbox360Controller


def on_button_pressed(button):
    print('Button {0} was pressed'.format(button.name))


def on_button_released(button):
    print('Button {0} was released'.format(button.name))


def on_axis_moved(axis):
    print('Axis {0} moved to {1} {2}'.format(axis.name, axis.x, axis.y))

try:
    with Xbox360Controller(0, axis_threshold=0.2) as controller:
        # Button A events
        controller.button_a.when_pressed = on_button_pressed
        controller.button_a.when_released = on_button_released

        # Left and right axis move event
        controller.axis_l.when_moved = on_axis_moved
        controller.axis_r.when_moved = on_axis_moved

        signal.pause()
except KeyboardInterrupt:
    pass

这是简单的 GUI:

我的想法是这样的,但是我很迷茫:

class MainWindow(Ui_MainWindow, Ui_MainClass):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.controller = Xbox360Controller(0, axis_threshold=0.2)
        self.controller.button_a.when_pressed = on_button_pressed()
        self.controller.button_a.when_released = on_button_released()

        # Left and right axis move event
        self.controller.axis_l.when_moved = on_axis_moved
        self.controller.axis_r.when_moved = on_axis_moved

    def on_button_pressed(self, button):
        print('Button {0} was pressed'.format(button.name))
        self.label_joy.setText(f'Button {0} was pressed'.format(button.name))

    def on_button_released(self, button):
        print('Button {0} was released'.format(button.name))
        self.label_joy.setText(f'Button {0} was released'.format(button.name))

    def on_axis_moved(self, axis):
        print('Axis {0} moved to {1} {2}'.format(axis.name, axis.x, axis.y)) 
        self.label_joy.setText('Axis {0} moved to {1} {2}'.format(axis.name, axis.x, axis.y))    
    

if __name__ == "__main__":
    app = QApplication([])
    form = MainWindow()
    form.show()
    sys.exit(app.exec_())

(我正在使用 Ubuntu 18.04)

您有 2 个错误:

  • 首先是self.controller.button_a.when_pressed = on_button_pressed()等同于value = on_button_pressed()self.controller.button_a.when_pressed = value,所以你没有赋值回调但是赋值了None因为这就是函数 returns.

  • 即使您更正了上述内容,也会出现另一个错误:回调是在辅助线程中调用的,因此总而言之,您会从另一个线程修改 GUI,这是 Qt 禁止的。在这种情况下,解决方案是使用 Qt 信号来传输信息,因为它们是线程安全的。

import sys
from functools import cached_property

from PyQt5 import QtCore, QtWidgets

from xbox360controller import Xbox360Controller
from xbox360controller.controller import Button, Axis, RawAxis


class Controller(QtCore.QObject):
    button_pressed = QtCore.pyqtSignal(Button)
    button_released = QtCore.pyqtSignal(Button)

    axis_moved = QtCore.pyqtSignal(object)

    def __init__(self, parent=None):
        super().__init__(parent)

        try:
            self.Xbox360_controller
        except Exception as e:
            print(e)
            sys.exit(-1)

        for button in self.Xbox360_controller.buttons:
            button.when_pressed = self._on_button_pressed
            button.when_released = self._on_button_released

        for axis in self.Xbox360_controller.axes:
            axis.when_moved = self._on_axis_moved

    @cached_property
    def Xbox360_controller(self):
        return Xbox360Controller(0, axis_threshold=0.2)

    def _on_button_pressed(self, button):
        self.button_pressed.emit(button)

    def _on_button_released(self, button):
        self.button_released.emit(button)

    def _on_axis_moved(self, axis):
        self.axis_moved.emit(axis)

    def close(self):
        self.Xbox360Controller.close()


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
        self.setCentralWidget(self.label)

    def handle_button_pressed(self, button):
        self.label.setText(f"Button {button.name} was pressed")

    def handle_button_released(self, button):
        self.label.setText(f"Button {button.name} was released")

    def handle_axis_moved(self, axis):
        if isinstance(axis, Axis):
            self.label.setText(f"Axis {axis.name} moved to {axis.x} {axis.y}")
        elif isinstance(axis, RawAxis):
            self.label.setText(f"Axis {axis.name} moved to {axis.value}")


def main():
    app = QtWidgets.QApplication(sys.argv)

    w = MainWindow()
    w.show()

    controller = Controller()
    controller.button_pressed.connect(w.handle_button_pressed)
    controller.button_released.connect(w.handle_button_released)
    controller.axis_moved.connect(w.handle_axis_moved)

    ret = app.exec_()

    controller.close()

    sys.exit(ret)


if __name__ == "__main__":
    main()