Python 如何在PyQt中创建操纵杆/控制器小部件?

Python 如何在PyQt中创建操纵杆/控制器小部件?,python,pyqt,pyqt4,Python,Pyqt,Pyqt4,我想创建一个类似于此的操纵杆小部件 我当前的实现使用了侧箭头 QooToButoN()/,但我不知道如何在中间创建圆。当用户点击中点并将其向箭头方向拖动时,应记录移动。我正在考虑使用paintEvent()和drapeclipse()或者甚至可能使用QDial(),但我不确定如何做到这一点 有时候,从头开始比较容易 如果您使用QWidget::MousePresseEvent(),QWidget::mouseReleaseEvent(),QWidget::mouseMoveEvent()和

我想创建一个类似于此的操纵杆小部件

我当前的实现使用了侧箭头<代码> QooToButoN()/<代码>,但我不知道如何在中间创建圆。当用户点击中点并将其向箭头方向拖动时,应记录移动。我正在考虑使用

paintEvent()
drapeclipse()
或者甚至可能使用
QDial()
,但我不确定如何做到这一点

有时候,从头开始比较容易

如果您使用
QWidget::MousePresseEvent()
QWidget::mouseReleaseEvent()
QWidget::mouseMoveEvent()
QWidget::paintEvent()
,您将能够处理操纵杆

使用
QWidget::paintEvent()
在小部件的中心绘制操纵杆

每当用户按下鼠标上的按钮时,就会调用
QWidget::MousePresseEvent()
。您可以使用它来启动操纵杆的移动

当用户释放鼠标按钮时,将调用
QWidget::mouseReleaseEvent()
。使用它重置操纵杆

QWidget::mouseMoveEvent()
被称为鼠标移动时的事件。使用它计算操纵手柄的偏移量和方向(向上、向左、向下或向右)。如果您想要某种模拟操纵杆,还可以使用中心和操纵杆之间的距离来获得0(不移动)和1(最大)之间的数字

例如:

from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
from enum import Enum

class Direction(Enum):
    Left = 0
    Right = 1
    Up = 2
    Down = 3

class Joystick(QWidget):
    def __init__(self, parent=None):
        super(Joystick, self).__init__(parent)
        self.setMinimumSize(100, 100)
        self.movingOffset = QPointF(0, 0)
        self.grabCenter = False
        self.__maxDistance = 50

    def paintEvent(self, event):
        painter = QPainter(self)
        bounds = QRectF(-self.__maxDistance, -self.__maxDistance, self.__maxDistance * 2, self.__maxDistance * 2).translated(self._center())
        painter.drawEllipse(bounds)
        painter.setBrush(Qt.black)
        painter.drawEllipse(self._centerEllipse())

    def _centerEllipse(self):
        if self.grabCenter:
            return QRectF(-20, -20, 40, 40).translated(self.movingOffset)
        return QRectF(-20, -20, 40, 40).translated(self._center())

    def _center(self):
        return QPointF(self.width()/2, self.height()/2)


    def _boundJoystick(self, point):
        limitLine = QLineF(self._center(), point)
        if (limitLine.length() > self.__maxDistance):
            limitLine.setLength(self.__maxDistance)
        return limitLine.p2()

    def joystickDirection(self):
        if not self.grabCenter:
            return 0
        normVector = QLineF(self._center(), self.movingOffset)
        currentDistance = normVector.length()
        angle = normVector.angle()

        distance = min(currentDistance / self.__maxDistance, 1.0)
        if 45 <= angle < 135:
            return (Direction.Up, distance)
        elif 135 <= angle < 225:
            return (Direction.Left, distance)
        elif 225 <= angle < 315:
            return (Direction.Down, distance)
        return (Direction.Right, distance)


    def mousePressEvent(self, ev):
        self.grabCenter = self._centerEllipse().contains(ev.pos())
        return super().mousePressEvent(ev)

    def mouseReleaseEvent(self, event):
        self.grabCenter = False
        self.movingOffset = QPointF(0, 0)
        self.update()

    def mouseMoveEvent(self, event):
        if self.grabCenter:
            print("Moving")
            self.movingOffset = self._boundJoystick(event.pos())
            self.update()
        print(self.joystickDirection())

if __name__ == '__main__':
    # Create main application window
    app = QApplication([])
    app.setStyle(QStyleFactory.create("Cleanlooks"))
    mw = QMainWindow()
    mw.setWindowTitle('Joystick example')

    # Create and set widget layout
    # Main widget container
    cw = QWidget()
    ml = QGridLayout()
    cw.setLayout(ml)
    mw.setCentralWidget(cw)

    # Create joystick 
    joystick = Joystick()

    # ml.addLayout(joystick.get_joystick_layout(),0,0)
    ml.addWidget(joystick,0,0)

    mw.show()

    ## Start Qt event loop unless running in interactive mode or using pyside.
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QApplication.instance().exec_()
从PyQt4.QtGui导入*
从PyQt4.QtCore导入*
导入系统
从枚举导入枚举
类方向(枚举):
左=0
右=1
上升=2
向下=3
类操纵杆(QWidget):
def uuu init uuu(self,parent=None):
超级(操纵杆,自我)。\uuuuu初始\uuuuuuu(父级)
自设置最小大小(100100)
self.movingOffset=QPointF(0,0)
self.grabCenter=False
自身最大距离=50
def paintEvent(自身,事件):
油漆工=油漆工(自身)
bounds=QRectF(-self.\uuuuuMaxDistance,-self.\uuuuMaxDistance,self.\uuuMaxDistance*2,self.\uuuMaxDistance*2).已转换(self.\uCenter())
画家。抽屉(边界)
油漆工.退刀(Qt.黑色)
painter.drawerlipse(self.\u centerEllipse())
def_中心椭圆(自):
如果self.grabbenter:
返回QRectF(-20,-20,40,40).translated(self.movingOffset)
返回QRectF(-20,-20,40,40).translated(self.\u center())
def_中心(自):
返回QPointF(self.width()/2,self.height()/2)
def_边界操纵杆(自身,点):
limitLine=QLineF(自中心(),点)
如果(limitLine.length()>self.\uu maxDistance):
limitLine.setLength(自身最大距离)
返回limitLine.p2()
def操纵手柄方向(自身):
如果不是self.grabbenter:
返回0
normVector=QLineF(self.\u center(),self.movingOffset)
currentDistance=normVector.length()
角度=标准向量。角度()
距离=最小值(当前距离/自身最大距离,1.0)

如果45获得错误
NameError:name“QWidget”在尝试使用PyQt5重新创建时未定义。
QWidget
自Qt5以来已在另一个模块中移动。从PyQt5.qtwidts导入QWidget添加行

from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
from enum import Enum

class Direction(Enum):
    Left = 0
    Right = 1
    Up = 2
    Down = 3

class Joystick(QWidget):
    def __init__(self, parent=None):
        super(Joystick, self).__init__(parent)
        self.setMinimumSize(100, 100)
        self.movingOffset = QPointF(0, 0)
        self.grabCenter = False
        self.__maxDistance = 50

    def paintEvent(self, event):
        painter = QPainter(self)
        bounds = QRectF(-self.__maxDistance, -self.__maxDistance, self.__maxDistance * 2, self.__maxDistance * 2).translated(self._center())
        painter.drawEllipse(bounds)
        painter.setBrush(Qt.black)
        painter.drawEllipse(self._centerEllipse())

    def _centerEllipse(self):
        if self.grabCenter:
            return QRectF(-20, -20, 40, 40).translated(self.movingOffset)
        return QRectF(-20, -20, 40, 40).translated(self._center())

    def _center(self):
        return QPointF(self.width()/2, self.height()/2)


    def _boundJoystick(self, point):
        limitLine = QLineF(self._center(), point)
        if (limitLine.length() > self.__maxDistance):
            limitLine.setLength(self.__maxDistance)
        return limitLine.p2()

    def joystickDirection(self):
        if not self.grabCenter:
            return 0
        normVector = QLineF(self._center(), self.movingOffset)
        currentDistance = normVector.length()
        angle = normVector.angle()

        distance = min(currentDistance / self.__maxDistance, 1.0)
        if 45 <= angle < 135:
            return (Direction.Up, distance)
        elif 135 <= angle < 225:
            return (Direction.Left, distance)
        elif 225 <= angle < 315:
            return (Direction.Down, distance)
        return (Direction.Right, distance)


    def mousePressEvent(self, ev):
        self.grabCenter = self._centerEllipse().contains(ev.pos())
        return super().mousePressEvent(ev)

    def mouseReleaseEvent(self, event):
        self.grabCenter = False
        self.movingOffset = QPointF(0, 0)
        self.update()

    def mouseMoveEvent(self, event):
        if self.grabCenter:
            print("Moving")
            self.movingOffset = self._boundJoystick(event.pos())
            self.update()
        print(self.joystickDirection())

if __name__ == '__main__':
    # Create main application window
    app = QApplication([])
    app.setStyle(QStyleFactory.create("Cleanlooks"))
    mw = QMainWindow()
    mw.setWindowTitle('Joystick example')

    # Create and set widget layout
    # Main widget container
    cw = QWidget()
    ml = QGridLayout()
    cw.setLayout(ml)
    mw.setCentralWidget(cw)

    # Create joystick 
    joystick = Joystick()

    # ml.addLayout(joystick.get_joystick_layout(),0,0)
    ml.addWidget(joystick,0,0)

    mw.show()

    ## Start Qt event loop unless running in interactive mode or using pyside.
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QApplication.instance().exec_()