【问题标题】:Moving PyQt5 App - QPushButton issue移动 PyQt5 应用程序 - QPushButton 问题
【发布时间】:2016-04-02 14:53:52
【问题描述】:

我正在使用 Python3 和 PyQt5 在 OSX 上开发一个简单的茶计时器应用程序。出于美学原因,我决定拆除窗框。为了仍然保持窗口可移动,我重载了 mousePressEvent() 和 mouseMoveEvent() 处理程序。

但是,当鼠标悬停在其中一个按钮 (QPushButton()) 上时移动窗口时,我遇到了问题。然后光标跳到最后一个点击位置,窗口从那里移动。有谁知道为什么会这样?有趣的是,在 QLabel() 对象上单击和移动时不会出现相同的问题...

如果你想尝试一下,这里有一个示例代码:

#!/usr/bin/python3
# -*- coding: utf-8 -*-

## ===============================================================
## IMPORTS

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *


## ===============================================================
## CONSTANTS

WINDOW_WIDTH = 690
WINDOW_HEIGHT = 435


## ===============================================================
## CLASSES


class Form(QWidget):
    def __init__(self, parent=None):
        super().__init__()

        self.windowPos = QPoint()       # Maybe not necessary when button click and window movement are seperated

        # Declare and specify UI elements
        self.timerLabel = QLabel("00:00")       # Might have to change data type here
        self.timerLabel.setObjectName("timerLabel")

        self.infoLabel = QLabel("No tea selected")
        self.infoLabel.setObjectName("infoLabel")

        self.teaOneButton = QPushButton("Tea One")
        self.teaOneButton.setObjectName("teaOneButton")

        self.teaTwoButton = QPushButton("Tea Two")
        self.teaTwoButton.setObjectName("teaTwoButton")

        # Arrange UI elements in a layout
        grid = QGridLayout()
        self.setLayout(grid)        # Set the QGridLayout as the window's main layout
        grid.setSpacing(0)      # Spacing between widgets - does not work if window is resized
        grid.setContentsMargins(4, 4, 4, 4)
        grid.addWidget(self.timerLabel, 0, 0, 1, -1, Qt.AlignHCenter)       # http://doc.qt.io/qt-5/qgridlayout.html#addWidget
        grid.addWidget(self.infoLabel, 1, 0, 1, -1, Qt.AlignHCenter)
        grid.addWidget(self.teaOneButton, 2, 0)
        grid.addWidget(self.teaTwoButton, 2, 1)

        self.resize(WINDOW_WIDTH, WINDOW_HEIGHT)


    # Arranging window in center of the screen by overloading showEvent method
    def showEvent(self, QShowEvent):
        self.centerOnScreen()


    def centerOnScreen(self):
        screen = QDesktopWidget()
        screenGeom = QRect(screen.screenGeometry(self))

        screenCenterX = screenGeom.center().x()
        screenCenterY = screenGeom.center().y()

        self.move(screenCenterX - self.width() / 2,
                            screenCenterY - self.height() / 2)


    # Overload mouseEvent handlers to make window moveable
    def mousePressEvent(self, QMouseEvent):
        self.windowPos = QMouseEvent.pos()
        self.setCursor(QCursor(Qt.SizeAllCursor))


    def mouseReleaseEvent(self, QMouseEvent):
        self.setCursor(QCursor(Qt.ArrowCursor))


    def mouseMoveEvent(self, QMouseEvent):
        # print (self.childAt(QMouseEvent.pos()) == QLabel)
        pos = QPoint(QMouseEvent.globalPos())
        self.window().move(pos - self.windowPos)



## ===============================================================
## MAIN LOOP

if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)

    screen = Form()
    screen.setWindowFlags(Qt.FramelessWindowHint)
    screen.show()

    sys.exit(app.exec_())

【问题讨论】:

    标签: qt python-3.x pyqt5


    【解决方案1】:

    好吧,伙计们,我想我可能已经找到了解决问题的方法。

    在我看来,问题可能在于 QPushButtons 处理 mouseMoveEvents 的方式与例如 QLabel 对象不同。对我来说这很直观,因为按钮对象可能需要与其他不可点击对象不同的鼠标事件处理。

    所以我所做的是尝试为 QPushButton 实现一个子类,重载 mouseMoveEvent 处理程序。起初我想我可能会设置处理程序以忽略该事件,以便将其委托给父小部件。这并没有改变什么。这实际上可能是一直在发生的事情。因为当我在事件处理函数中实现某种代码时,按钮不再用作移动窗口的源。自己看:

    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
    
    ## ===============================================================
    ## IMPORTS
    
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import *
    
    
    ## ===============================================================
    ## CONSTANTS
    
    WINDOW_WIDTH = 690
    WINDOW_HEIGHT = 435
    
    
    ## ===============================================================
    ## CLASSES
    
    class UnmoveableButton(QPushButton):
        def __init__(self, text=""):
            super().__init__(text)
    
        # This event function is overloaded in order to avoid the widget from delegating the event up to the parent.
        # This way, the pre-existing functionality is skipped, i.e. the window can no longer be moved while hovering over a button.
        def mouseMoveEvent(self, QMouseEvent):
            pass
    
    class Form(QWidget):
        def __init__(self, parent=None):
            super().__init__()
    
            self.windowPos = QPoint()       # Maybe not necessary when button click and window movement are seperated
    
            # Declare and specify UI elements
            self.timerLabel = QLabel("00:00")       # Might have to change data type here
            self.timerLabel.setObjectName("timerLabel")
    
            self.infoLabel = QLabel("No tea selected")
            self.infoLabel.setObjectName("infoLabel")
    
            self.teaOneButton = UnmoveableButton("Tea One")
            self.teaOneButton.setObjectName("teaOneButton")
    
            self.teaTwoButton = UnmoveableButton("Tea Two")
            self.teaTwoButton.setObjectName("teaTwoButton")
    
            # Arrange UI elements in a layout
            grid = QGridLayout()
            self.setLayout(grid)        # Set the QGridLayout as the window's main layout
            grid.setSpacing(0)      # Spacing between widgets - does not work if window is resized
            grid.setContentsMargins(4, 4, 4, 4)
            grid.addWidget(self.timerLabel, 0, 0, 1, -1, Qt.AlignHCenter)       # http://doc.qt.io/qt-5/qgridlayout.html#addWidget
            grid.addWidget(self.infoLabel, 1, 0, 1, -1, Qt.AlignHCenter)
            grid.addWidget(self.teaOneButton, 2, 0)
            grid.addWidget(self.teaTwoButton, 2, 1)
    
            self.resize(WINDOW_WIDTH, WINDOW_HEIGHT)
    
    
        # Arranging window in center of the screen by overloading showEvent method
        def showEvent(self, QShowEvent):
            self.centerOnScreen()
    
    
        def centerOnScreen(self):
            screen = QDesktopWidget()
            screenGeom = QRect(screen.screenGeometry(self))
    
            screenCenterX = screenGeom.center().x()
            screenCenterY = screenGeom.center().y()
    
            self.move(screenCenterX - self.width() / 2,
                                screenCenterY - self.height() / 2)
    
    
        # Overload mouseEvent handlers to make window moveable
        def mousePressEvent(self, QMouseEvent):
            self.windowPos = QMouseEvent.pos()
            self.setCursor(QCursor(Qt.SizeAllCursor))
    
    
        def mouseReleaseEvent(self, QMouseEvent):
            self.setCursor(QCursor(Qt.ArrowCursor))
    
    
        def mouseMoveEvent(self, QMouseEvent):
            # print (self.childAt(QMouseEvent.pos()) == QLabel)
            pos = QPoint(QMouseEvent.globalPos())
            self.window().move(pos - self.windowPos)
    
    
    
    ## ===============================================================
    ## MAIN LOOP
    
    if __name__ == '__main__':
        import sys
    
        app = QApplication(sys.argv)
    
        screen = Form()
        screen.setWindowFlags(Qt.FramelessWindowHint)
        screen.show()
    
        sys.exit(app.exec_())
    

    我认为这可能不是最优雅或最正确的解决方案,但它现在对我来说很好。如果有人知道如何改进这一点,请告诉我:)

    【讨论】:

      【解决方案2】:
      from PyQt5.QtCore import *
      from PyQt5.QtWidgets import *
      from PyQt5.QtGui import *
      

      您确定导入的成员没有命名空间冲突吗?

      【讨论】:

      • 你自己实际测试过吗?
      • 我还没有。我可以不使用最后一行(来自 PyQt5.QtGui import *),这样可以缩小范围......你认为这里可能会发生什么?
      • 看起来 QPushButton 是 QWidget { doc.qt.io/qt-5/qwidget.html } 的子类,而 QPushButton 是 QtGui {pyqt.sourceforge.net/Docs/PyQt4/qpushbutton.html} 的类成员,因此是我最初的问题。尝试删除 QtGui 看看会发生什么!
      猜你喜欢
      • 2020-03-25
      • 2018-01-13
      • 2016-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-17
      • 2012-02-13
      • 1970-01-01
      相关资源
      最近更新 更多