gpt4 book ai didi

python - 如何在 QScrollArea() 之上显示 QPropertyAnimation()?

转载 作者:太空宇宙 更新时间:2023-11-03 15:33:43 28 4
gpt4 key购买 nike

1。简介

我在 Windows 10 上使用 Python 3.7 并使用 PyQt5 作为 GUI。在我的应用程序中,我得到了一个 QScrollArea()里面有一排按钮。单击时,按钮必须移出该区域。我用 QPropertyAnimation()以显示运动。


2。最小的、可重现的例子

我已经创建了一个用于测试的小型应用程序。该应用程序显示一个小 QScrollArea()里面有一堆按钮。当你点击一个按钮时,它会向右移动:

enter image description here

代码如下:

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

class MyButton(QPushButton):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setFixedWidth(300)
self.setFixedHeight(30)
self.clicked.connect(self.animate)
return

def animate(self):
self.anim = QPropertyAnimation(self, b'position')
self.anim.setDuration(3000)
self.anim.setStartValue(QPointF(self.pos().x(), self.pos().y()))
self.anim.setEndValue(QPointF(self.pos().x() + 200, self.pos().y() - 20))
self.anim.start()
return

def _set_pos_(self, pos):
self.move(pos.x(), pos.y())
return

position = pyqtProperty(QPointF, fset=_set_pos_)


class CustomMainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(100, 100, 600, 300)
self.setWindowTitle("ANIMATION TEST")

# OUTER FRAME
# ============
self.frm = QFrame()
self.frm.setStyleSheet("""
QFrame {
background: #d3d7cf;
border: none;
}
""")
self.lyt = QHBoxLayout()
self.frm.setLayout(self.lyt)
self.setCentralWidget(self.frm)

# BUTTON FRAME
# =============
self.btn_frm = QFrame()
self.btn_frm.setStyleSheet("""
QFrame {
background: #ffffff;
border: none;
}
""")
self.btn_frm.setFixedWidth(400)
self.btn_frm.setFixedHeight(200)
self.btn_lyt = QVBoxLayout()
self.btn_lyt.setAlignment(Qt.AlignTop)
self.btn_lyt.setSpacing(5)
self.btn_frm.setLayout(self.btn_lyt)

# SCROLL AREA
# ============
self.scrollArea = QScrollArea()
self.scrollArea.setStyleSheet("""
QScrollArea {
border-style: solid;
border-width: 1px;
}
""")
self.scrollArea.setWidget(self.btn_frm)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setFixedWidth(400)
self.scrollArea.setFixedHeight(150)
self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.lyt.addWidget(self.scrollArea)

# ADD BUTTONS TO BTN_LAYOUT
# ==========================
self.btn_lyt.addWidget(MyButton("Foo"))
self.btn_lyt.addWidget(MyButton("Bar"))
self.btn_lyt.addWidget(MyButton("Baz"))
self.btn_lyt.addWidget(MyButton("Qux"))
self.show()
return

if __name__== '__main__':
app = QApplication(sys.argv)
QApplication.setStyle(QStyleFactory.create('Plastique'))
myGUI = CustomMainWindow()
sys.exit(app.exec_())


3。问题

当按钮移动时,它停留在QScrollArea()中。 .我需要把它放在一切之上:

enter image description here


4。解决方案(差不多)

感谢@magrif 为我指明了正确的方向。感谢您的建议,我得到了一些工作。

所以我改变了animate()作用于此:

    def animate(self):
self.anim = QPropertyAnimation(self, b'position')
self.anim.setDuration(3000)
startpoint = self.mapToGlobal(self.pos())
endpoint = self.mapToGlobal(QPoint(self.pos().x() + 200, self.pos().y() - 20))
self.setWindowFlags(Qt.Popup)
self.show()
self.anim.setStartValue(QPointF(startpoint.x(), startpoint.y()))
self.anim.setEndValue(QPointF(endpoint.x(), endpoint.y()))
self.anim.start()
QTimer.singleShot(1000, self.hide)
return

请注意,我在 hide() 上安装了一个单次定时器一秒钟后按钮。这是因为只要此按钮表现为“弹出”(因为 self.setWindowFlags(Qt.Popup)),Qt 事件循环就会被阻止。不管怎样,一次性定时器对我来说已经足够好了。

不幸的是,我还剩下一期。当我点击第一个按钮 Foo 时,它(几乎)从最初所在的位置开始播放动画。如果我点击其他按钮之一 - 例如 Baz - 它会突然跳下大约 100 像素并从那里开始播放动画。

我认为这与 startpoint = self.mapToGlobal(self.pos()) 有关功能以及这些按钮位于 QScrollArea() 中的事实.但我不知道如何解决这个问题。


5。目的

我的目的是构建一个像这样的鼠标右键单击菜单:

enter image description here

当用户点击Grab and move 时,该按钮应该从QScrollArea() 中消失。并迅速向鼠标移动。当它到达鼠标指针时,按钮应该淡出并且可以开始拖放操作。

注意:以下与本主题相关的问题是:
Qt: How to perform a drag-and-drop without holding down the mouse button?

最佳答案

小部件的位置是相对于其父级的,因此您不应使用 startpoint = self.mapToGlobal(self.pos()),而应使用 startpoint = self.mapToGlobal(QPoint ()),因为对于小部件,topLeft 的位置是 QPoint(0, 0)

所以如果你想使用 @magrif您应该将其更改为的解决方案:

def animate(self):
startpoint = self.mapToGlobal(QPoint())
self.setWindowFlags(Qt.Popup)
self.show()
anim = QPropertyAnimation(
self,
b"pos",
self,
duration=3000,
startValue=startpoint,
endValue=startpoint + QPoint(200, -20),
finished=self.deleteLater,
)
anim.start()

但缺点是当动画运行时你不能与窗口交互。

另一种解决方案是将 QFrame 的父级更改为窗口本身:

def animate(self):
startpoint = self.window().mapFromGlobal(self.mapToGlobal(QPoint()))
self.setParent(self.window())
anim = QPropertyAnimation(
self,
b"pos",
self,
duration=3000,
startValue=startpoint,
endValue=startpoint + QPoint(200, -20),
finished=self.deleteLater,
)
anim.start()
self.show()

注意:没有必要创建 qproperty 位置,因为 qproperty pos已经存在。

关于python - 如何在 QScrollArea() 之上显示 QPropertyAnimation()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56216698/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com