Pyside2 中的二维可点击表面

2D clickable surface in Pyside2

我正在使用 PySide2 为项目编写一个简单的 GUI 界面。 我使用的是典型的 MVC 设计模式,为了清楚起见,我只 post 我的 GUI 代码(没有控制器和支持方法 ecc...)

代码如下:

from PySide2.QtWidgets import *
from PySide2.QtWidgets import QSizePolicy
from PySide2.QtGui import QIcon
from PySide2.QtWidgets import (QPushButton, QMainWindow)

class myView(QMainWindow):

    def __init__(self, parent=None):
        """View initializer."""

        #Creates blank view of a given size
        super().__init__()

        # Set some main window's properties
        self.setWindowTitle('8D.me')
        self.setFixedSize(800, 500) # Block user resize of the window
        self.setIcon()
        self.generalLayout = QHBoxLayout() #Layout generale

        self.button = QPushButton('test3',self)
        self.button.setSizePolicy(
            QSizePolicy.Preferred,
            QSizePolicy.Expanding)
        self.generalLayout.addWidget(QPushButton('test2',self),1)
        self.generalLayout.addWidget(self.button,3)

        # Set the central widget
        self._centralWidget = QWidget(self) #creates a QWidget object to play the role of a central widget. Remember that since your GUI class inherits from QMainWindow, you need a central widget. This object will be the parent for the rest of the GUI component.
        self.setCentralWidget(self._centralWidget)
        self._centralWidget.setLayout(self.generalLayout)

# Insert methods for creating/adding elements to the default view.
# Mehods....
    def setIcon(self):
        appIcon = QIcon('logo')
        self.setWindowIcon(appIcon)

#Insert here the public methods called by the Controller to update the view...

我的 GUI 非常简单,看起来像这样:

我想做的是更改 test 3 按钮并插入一个 2D 可点击表面。 更详细地说,我希望能够点击这个表面上的任何地方并获得鼠标点击的位置。

基本上我想创建一个 2D xy 轴并检索鼠标单击的坐标,如下所示:

然后,如果我点击位置 (1,1),我将打印类似“您点击了轴上的 (1,1)”的内容,非常简单。

我四处寻找示例、教程和文档,但没有找到任何合适的工具来创建我想要的东西。 PySide2 包中是否有任何 class 可以帮助我?

如果您从字面上理解您的目标是在图像中获得 X-Y 平面,那么可能的解决方案是使用 QGraphicsView:

import math
import sys

from PySide2.QtCore import Signal, QPointF
from PySide2.QtGui import QColor, QPainterPath
from PySide2.QtWidgets import (
    QApplication,
    QGraphicsScene,
    QGraphicsView,
    QHBoxLayout,
    QMainWindow,
    QPushButton,
    QWidget,
)


class GraphicsScene(QGraphicsScene):
    clicked = Signal(QPointF)

    def drawBackground(self, painter, rect):
        l = min(rect.width(), rect.height()) / 30

        x_left = QPointF(rect.left(), 0)
        x_right = QPointF(rect.right(), 0)
        painter.drawLine(x_left, x_right)

        right_triangle = QPainterPath()
        right_triangle.lineTo(-0.5 * math.sqrt(3) * l, 0.5 * l)
        right_triangle.lineTo(-0.5 * math.sqrt(3) * l, -0.5 * l)
        right_triangle.closeSubpath()
        right_triangle.translate(x_right)

        painter.setBrush(QColor("black"))
        painter.drawPath(right_triangle)

        y_top = QPointF(0, rect.top())
        y_bottom = QPointF(0, rect.bottom())
        painter.drawLine(y_top, y_bottom)

        top_triangle = QPainterPath()
        top_triangle.lineTo(.5*l, -0.5 * math.sqrt(3) * l)
        top_triangle.lineTo(-.5*l, -0.5 * math.sqrt(3) * l)
        top_triangle.closeSubpath()
        top_triangle.translate(y_bottom)

        painter.setBrush(QColor("black"))
        painter.drawPath(top_triangle)

    def mousePressEvent(self, event):
        sp = event.scenePos()
        self.clicked.emit(sp)
        super().mousePressEvent(event)


class MyView(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("8D.me")
        self.setFixedSize(800, 500)

        self.btn = QPushButton("test2")

        self.view = QGraphicsView()
        self.view.scale(1, -1)
        self.scene = GraphicsScene()
        self.view.setScene(self.scene)

        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QHBoxLayout(central_widget)
        layout.addWidget(self.btn)
        layout.addWidget(self.view)

        self.scene.clicked.connect(self.handle_clicked)

    def handle_clicked(self, p):
        print("clicked", p.x(), p.y())


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyView()
    w.show()
    sys.exit(app.exec_())