与 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 交互的主要内容,如果未能解决你的问题,请参考以下文章
使用 XInput 和 VB.NET 支持 xbox 360 控制器
如何在 Python 中记录 xbox/gamepad 控制器的状态?