与 Xbox 控制器的 GUI 交互

Posted

技术标签:

【中文标题】与 Xbox 控制器的 GUI 交互【英文标题】:GUI Interaction with Xbox Controller 【发布时间】:2021-05-17 21:03:09 【问题描述】:

我希望能够使用使用 QT 设计器创建的 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

这是简单的图形用户界面:

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

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)

【问题讨论】:

【参考方案1】:

您有 2 个错误:

第一个是self.controller.button_a.when_pressed = on_button_pressed()等价于value = on_button_pressed()self.controller.button_a.when_pressed = value,所以你没有分配回调但你已经分配了None,因为这是函数返回的。

即使您更正了上述问题,也会出现另一个错误:回调是在辅助线程中调用的,因此总而言之,您将从另一个线程修改 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()

【讨论】:

你成就了我的一天。再次感谢您的好先生! @FelipeMedLev 那个错误?把完整的错误信息。我指出这一点是因为在您指出异常的 2 个 cmets 中,两条消息之间没有重合 @FelipeMedLev 我已经看到了错误,我已经更正了,再次测试。 Veo que hablas español! Para dejar el código perfecto sólo faltaría agregarle la 'b' de button en el prime for loop。感谢大师! Te dejé un cafecito ;) 嘿!我认为代码有效,因为它没有错误,但现在我正在测试,我意识到一个奇怪的行为。当我在操纵杆上移动 axis_r 时,显示屏上显示轴 trigger_r 已移动。当我移动轴 trigger_left 时,它表明我正在移动右触发器,当我移动轴 trigger_right 时,它表明 axis_r 仅在垂直轴上移动。

以上是关于与 Xbox 控制器的 GUI 交互的主要内容,如果未能解决你的问题,请参考以下文章

适用于 Xbox 360 控制器的振动 API

使用 XInput 和 VB.NET 支持 xbox 360 控制器

xboxgamedvr怎么关闭

如何在 Python 中记录 xbox/gamepad 控制器的状态?

过程控制基于matlab GUI串级控制含Matlab源码 2385期

GLFW无法识别Xbox控制器