【问题标题】:PyQt creating label that follows mousePyQt 创建跟随鼠标的标签
【发布时间】:2020-10-02 21:40:30
【问题描述】:

我要存档的是一个标签,它在按下按钮后立即创建并跟随鼠标直到出现“点击”。

我的问题是我似乎无法在正确的小部件上获得“setMouseTracking(True)”命令...

    import sys
from PyQt5 import QtCore, QtGui, QtWidgets, uic
from PyQt5.QtCore import Qt


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()

        self.setGeometry(0,0,1000,1100)
        self.main = QtWidgets.QLabel()
        self.setCentralWidget(self.main)

        self.label = QtWidgets.QLabel()
        canvas = QtGui.QPixmap(900, 900)
        canvas.fill(QtGui.QColor('#ffffff')) # Fill entire canvas.
        self.label.setPixmap(canvas)

        # self.last_x, self.last_y = None, None

        self.button = QtWidgets.QPushButton('create Block')
        self.button.clicked.connect(self.buttonAction)

        vbox = QtWidgets.QVBoxLayout()
        vbox.addWidget(self.label)
        vbox.addWidget(self.button)

        self.main.setLayout(vbox)
        # self.label.setMouseTracking(True)
        self.setWindowTitle('testing')


    def mouseMoveEvent(self, e):
        # if self.last_x is None: # First event.
            # self.last_x = e.x()
            # self.last_y = e.y()
            # return # Ignore the first time.

        # painter = QtGui.QPainter(self.label.pixmap())
        # painter.drawLine(self.last_x, self.last_y, e.x(), e.y())
        # painter.end()

        try:
            self.image.move(e.x(), e.y())
        except:
            pass
        self.update()

        # Update the origin for next time.
        # self.last_x = e.x()
        # self.last_y = e.y()

    def mouseReleaseEvent(self, e):
        # self.last_x = None
        # self.last_y = None

    def buttonAction(self):
        block = QtGui.QPixmap(20, 20)
        block.fill(QtGui.QColor('blue'))
        self.image = QtWidgets.QLabel(self.label)
        self.image.setPixmap(block)
        self.image.move(20,20)
        self.image.show()

app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

我不知道我的问题是我将 setMouseTracking(True) 附加到了错误的小部件,还是完全是别的东西。 通过点击操作它可以工作,但这不是我打算做的......

编辑:修复了一些代码问题

为了澄清我的问题是什么:我在布局中有一个画布和一个按钮,一旦单击该按钮,就会创建一个新画布,它跟随鼠标指针“直到”我单击。所以我不想要任何类型的拖放操作,而是一个跟随鼠标指针的小画布。

这是需要的,因为我打算使用小画布来显示图形在某个画布位置的样子,而不是在那里打印。所以小画布就像一个模板。

【问题讨论】:

  • 抱歉这么直率,但您的问题不在于鼠标跟踪,因为您的代码有很多问题,坦率地说,我什至不知道该去哪里开始。另外,你想要做什么也不是很清楚:你想在鼠标按下时创建一个标签where?如果在按钮上按下按钮怎么办?请说明您想要实现的目标,最重要的是,检查您的代码。
  • 当“创建块”按钮被按下时,这就是为什么我不希望跟踪是一个点击动作,而只是一个跟踪,直到我点击为止。
  • 抱歉,还是有点混乱。点击按钮时会创建一个标签,那么什么在跟随鼠标?因为在您的代码中,您都试图在像素图上绘制 移动另一个像素图,而您真正想要实现的目标真的不清楚。您想在单击按钮后“绘制”线条并继续绘制直到释放鼠标吗?您是否意识到这意味着绘制的线条将始终(理论上)从按钮开始?此外,clicked 信号实际上是在释放鼠标按钮时发出的,而不是在按下鼠标按钮时发出的。
  • 对不起,那是我的错。我只是尝试快速构建一个最小的示例,并为此目的使用了一个为鼠标移动绘制线条的小程序。我可以评论一下,在我的主应用程序中,画布上正在发生其他一些事情。我希望包含新迷你画布的标签跟随鼠标,直到我单击画布上的某个位置。所以我的主要问题是我希望这个标签从点击按钮的那一刻起一直跟随鼠标,直到我用鼠标点击。但到目前为止它只跟随鼠标,而鼠标按钮被按住。
  • 创建示例时,您必须确保它们不仅最小,而且可重现(您的代码有错字,因为 QPushButton 中缺少 B)并且可读。不要急于求成,最好多花 10 到 15 分钟在一个精心定制的代码上,而不是因为其他人无法理解而浪费时间。我建议您修改代码并用它编辑问题,同时澄清那里您需要什么来集成您在 cmets 中编写的内容。请记住始终尽量做到清晰(简洁)。

标签: python qt user-interface pyqt5


【解决方案1】:

你的逻辑存在一些概念问题。

首先,鼠标跟踪仅适用于设置它的小部件。此外,如果小部件接受鼠标移动事件,则父级将不会收到它。

在您的情况下,您没有收到它,因为您正在主窗口中实现 mouseMoveEvent,如果没有按下鼠标按钮(如大多数小部件),默认情况下会忽略它。

虽然您可以尝试在“目标”小部件父(在您的情况下,画布和主窗口)上设置它,但您肯定会在某个时候遇到一些问题如果任何底层小部件接受鼠标移动;由于您只需要在实际的“画布”上进行“预览”,因此无需创建新的小部件,因为您可以直接在画布上绘制,最后仅在需要时在实际的像素图上绘制。

这是一个可能的实现:

class Canvas(QtWidgets.QLabel):
    def __init__(self):
        super().__init__()
        pixmap = QtGui.QPixmap(900, 900)
        pixmap.fill(QtCore.Qt.white)
        self.setPixmap(pixmap)
        self.setMouseTracking(True)
        self.preview = False

    def startPreview(self):
        self.preview = True
        self.update()

    def drawMiniCanvas(self, pos):
        pm = self.pixmap()
        qp = QtGui.QPainter(pm)
        qp.setBrush(QtCore.Qt.blue)
        if self.size() != pm.size():
            # if the pixmap is smaller than the actual size of the canvas, the position
            # must be translated to its contents before painting
            alignment = self.alignment()
            pmRect = pm.rect()
            if alignment == QtCore.Qt.AlignCenter:
                pmRect.moveCenter(self.rect().center())
            else:
                if alignment & QtCore.Qt.AlignHCenter:
                    pmRect.moveLeft((self.width() - pm.width()) / 2)
                elif alignment & QtCore.Qt.AlignRight:
                    pmRect.moveRight(self.width())
                if alignment & QtCore.Qt.AlignVCenter:
                    pmRect.moveTop((self.height() - pm.height()) / 2)
                elif alignment & QtCore.Qt.AlignBottom:
                    pmRect.moveBottom(self.height())
            pos -= pmRect.topLeft()
        qp.drawRect(pos.x(), pos.y(), 20, 20)
        qp.end()
        self.setPixmap(pm)

    def mouseMoveEvent(self, event):
        if self.preview:
            self.update()

    def mousePressEvent(self, event):
        if self.preview:
            if event.button() == QtCore.Qt.LeftButton:
                self.drawMiniCanvas(event.pos())
            self.preview = False

    def paintEvent(self, event):
        super().paintEvent(event)
        if self.preview:
            qp = QtGui.QPainter(self)
            qp.drawRect(self.rect().adjusted(0, 0, -1, -1))
            pos = self.mapFromGlobal(QtGui.QCursor.pos())
            qp.setBrush(QtCore.Qt.blue)
            qp.drawRect(pos.x(), pos.y(), 20, 20)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.setGeometry(0,0,1000,1100)
        self.main = QtWidgets.QLabel()
        self.setCentralWidget(self.main)

        self.canvas = Canvas()

        self.button = QtWidgets.QPushButton('create Block')
        self.button.clicked.connect(self.canvas.startPreview)

        vbox = QtWidgets.QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.button)

        self.main.setLayout(vbox)
        self.setWindowTitle('testing')

请注意,根据您的代码,我已将主小部件保留为 QLabel,但我强烈建议避免这样做:QLabel 对其大小进行了复杂的管理,即使您向其添加布局,布局要求也会总是被忽视;您应该改用 QWidget。

最后,虽然上面的代码有效,但它只是基于您的问题的一个简单示例;如果要创建绘图工具,则不应该使用QLabel,并且由于各种原因:例如,如果要支持缩放以适应内容,则不仅drawMiniCanvas中的坐标计算不起作用(由于缩放),但它也不会绘制任何东西,这是由于 QLabel 在使用 setScaledContents(True) 时缓存其内容的方式(而且,它不会尊重纵横比)。

对于高级和交互式绘画,通常最好使用 QGraphicsView 中显示的 QGraphicsScene。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多