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

2024-04-25

1. Intro

我工作于Python 3.7在 Windows 10 上并使用PyQt5对于图形用户界面。在我的申请中,我得到了一个QScrollArea()里面有一系列按钮。单击时,按钮必须移到该区域之外。我用一个QPropertyAnimation()以显示运动。

 

2. 最小的、可重复的示例

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

这是代码:

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()。我需要把它放在一切之上:

 

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()一秒钟后按下按钮。这是因为只要此按钮表现为“弹出窗口”,Qt 事件循环就会被阻止(因为self.setWindowFlags(Qt.Popup))。无论如何,一次性计时器对我来说已经足够好了。

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

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

 

5. 目的

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

当用户点击抓取并移动,该按钮应该从QScrollArea()并快速向鼠标移动。当它到达鼠标指针时,按钮应该淡出并且拖放可以开始操作。

Note: The following question related to this topic is this one:
Qt: How to perform a drag-and-drop without holding down the mouse button? https://stackoverflow.com/questions/56263595/qt-how-to-perform-a-drag-and-drop-without-holding-down-the-mouse-button


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

所以如果你想使用@magrif https://stackoverflow.com/users/4607234/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 位置,因为 qpropertypos https://doc.qt.io/qt-5/qwidget.html#pos-prop已经存在。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 QScrollArea() 之上显示 QPropertyAnimation()? 的相关文章

随机推荐

  • 在 shell 脚本中禁止输出到屏幕

    你好 我写了一个小脚本 usr bin ksh for i in DAT do awk BEGIN OFS FS 3 353 3 353861958962 print i gt gt i changed awk 3 353 i change
  • 选项卡视觉选择

    In many GUIs when I select a section of text and then hit the Tab or Shift Tab button the selected section will indent i
  • XML-RPC Odoo - C# 多个搜索条件

    当使用 CookComputing XML RPC net 尝试仅使用一个条件搜索 mail notification 模型时 这相当简单 因为您只需调用 object args new object 1 object subargs ne
  • 从 SQLDataReader 读取结果时出现无效转换异常

    我的存储过程 UserName nvarchar 64 AS BEGIN SELECT MPU UserName SUM TS Monday as Monday TS Monday contains float value FROM dbo
  • 如何更改 vuetify v2 中 scss 中的断点?

    我正在使用 scss 文件 我想更改 vuetify v2 中 css 端的断点 我在 vuetify 升级指南中找不到任何参考 在 1 5 版本中我做了 style x styl grid breakpoints xs 0 sm 476p
  • Laravel - 获取客户端 IP 地址 - 始终获取 127.0.0.1 结果

    我无法获取客户端的 IP 地址 我需要该地址来确定他的当前位置 我使用了 request gt ip SERVER REMOTE ADDR 并且总是得到 127 0 0 1 结果 这不是我想要的 我究竟做错了什么 有时您的客户端通过代理使用
  • pyQt4 - 如何选择表格行并禁用编辑单元格

    我使用以下命令创建 QTableWidget self table QtGui QTableWidget self table setObjectName table self table setSelectionBehavior QtGu
  • 如何使用实体框架和成员资格表初始化数据库

    我有一个使用 Entity Framework 5 0 Code First 的 MVC4 Web 应用程序 在 Global asax cs 中 我有一个引导程序 用于初始化 Entity Database 强制初始化数据库并初始化成员资
  • 如何将谓词与包含的属性一起包含在内?

    目前 我有一个函数 允许我查询数据库 同时在结果中包含一些其他相关表 以防止返回数据库 否则如果我不这样做 我知道会发生这种情况 public class EntityRepository
  • 如何拦截来自 iframe 的 http 请求?

    我以编程方式在网页中设置 iframe 的 URL 我必须知道此 URL 更改会触发哪些 http 请求 CSS 脚本 图像等加载的 URL 我拦截了 XMLHttpRequest 但这个对象从未被调用过 如何拦截这些http请求 是否有另
  • Node.js (Express) 带有路由器的错误处理中间件

    这是我的应用程序结构 app js routes index js The ExpressJS应用程序创建错误处理程序development and production环境 这是来自的代码片段app js app use routes r
  • 物化滑动选项卡在模态中不起作用

    我遇到了一个奇怪的问题 我在物化选项卡上使用滑动 当我在没有模式的情况下滑动时 它工作正常 但是当我将它们包含在模式中时 滑动功能不再工作 document ready function modal modal tabs tabs swip
  • 如何获取可公开访问的 crashlytics 报告 url?

    我想与一些第三方分享我的 crashlytics 崩溃报告 如何获得如下所示的可公开访问的网址 http crashes to s 419b5b28766 http crashes to s 419b5b28766 我是新来的 这是一个旧的
  • SchedPolicy:set_timerslack_ns 写入失败:不允许操作

    当我运行 Android 应用程序时 我在 Logcat 中遇到了这个问题 有谁知道这个问题以及如何解决它 依赖项是 implementation com android support appcompat v7 25 3 0 implem
  • 32x8 寄存器文件 VHDL 测试台

    我已经用 vhdl 编写了该电路的汇编代码 我想用测试台来模拟它 RegWrite 1 位输入 时钟 写寄存器个数 3位输入 写地址 写入数据 32 位输入 数据输入 读取 寄存器编号 A 3 位输入 读取地址 读取寄存器编号 B 3 位输
  • Spring Cloud 配置服务器无法使用本地属性文件

    我一直在玩弄位于此处的 github 上的 Spring Cloud 项目 https github com spring cloud spring cloud config https github com spring cloud sp
  • redis-cli 重定向到 127.0.0.1

    我在PC1上启动Redis集群 然后在PC2上连接它 当需要重定向到另一个集群节点时 它会显示Redirected to slot 7785 located at 127 0 0 1 但应该显示Redirected to slot 7785
  • 壁纸更换事件

    我可以在广播接收器中获取壁纸更改事件吗 我需要检测用户是否更改了壁纸 我怎样才能做到呢 我正在做的是这样的 我有一个可以自动更改壁纸的应用程序 如果用户使用不同的应用程序手动更改它 我想注意到它并询问用户是否要将新壁纸添加到我的应用程序的列
  • Kafka 消费者通过 JMX 滞后

    我正在尝试监控 Kafka 0 10 中消费者组的滞后情况 我们的消费者在 Kafka 而不是 ZooKeper 中跟踪他们的偏移量 这意味着我可以使用以下方式获取数据 bin kafka consumer groups sh bootst
  • 如何在 QScrollArea() 之上显示 QPropertyAnimation()?

    1 Intro 我工作于Python 3 7在 Windows 10 上并使用PyQt5对于图形用户界面 在我的申请中 我得到了一个QScrollArea 里面有一系列按钮 单击时 按钮必须移到该区域之外 我用一个QPropertyAnim