【问题标题】:How can I resize a QSCrollBar to change it's width in runtime?如何调整 QSCrollBar 的大小以在运行时更改其宽度?
【发布时间】:2021-02-05 00:39:01
【问题描述】:

我目前正在尝试在 Qt (python) 中重现 Window 10 开始菜单滚动条,但我不知道如何调整自定义 QScrollBar 的大小以在运行时更改其宽度。

我尝试使用 QScrollBar.resize 方法(在 enterEvent 和 leaveEvent 中)调整它的大小,但它会将小部件缩放到它的“绘图区域”之外。 例如,我的滚动条设置为 QScrollArea 并且当我尝试调整它的大小时,它不会占用更多空间并移动小部件,而不是它只是在它的右侧缩放,我看不到它。

我现在找到的唯一解决方案是使用 StyleSheet,但我无法对其进行动画处理以实现我正在寻找的平滑调整大小。

有一些代码供你测试,看看有什么问题:

from PySide2 import QtWidgets, QtCore
from functools import partial

class MyTE(QtWidgets.QPlainTextEdit):
    
    def __init__(self):
        super(MyTE, self).__init__()
        
        self.setVerticalScrollBar(MyScrollBar(self))
        self.setPlainText('mmmmmmmmmmmmmmmmmmmmmmmmmmmmm'*50)
        
class MyScrollBar(QtWidgets.QScrollBar):
    
    def __init__(self, parent=None):
        super(MyScrollBar, self).__init__(parent=parent)
        self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)        
        
    def enterEvent(self, event):
        super(MyScrollBar, self).enterEvent(event)
        
        self.resize(QtCore.QSize(4, self.height()))
        
    def leaveEvent(self, event):
        super(MyScrollBar, self).leaveEvent(event)
        
        self.resize(QtCore.QSize(10, self.height()))
        
wid = MyTE()
wid.show()

【问题讨论】:

  • 完成!我能问一下你为什么删除了我留言的最后一行吗?我只是想说谢谢你的帮助..
  • 正是出于这个原因。问候是无关紧要的,因为帖子应该关注问题,所以避免问候,谢谢,关于你的专业水平的信息或不相关的信息。社区了解每个成员都对社区的任何成员表示感谢,因此无需明确表示

标签: python pyside2 qtstylesheets qscrollbar


【解决方案1】:

要使宽度变化更平滑,您可以使用QVariantAnimation

from PySide2 import QtWidgets, QtCore


class MyTE(QtWidgets.QPlainTextEdit):
    def __init__(self):
        super(MyTE, self).__init__()

        self.setVerticalScrollBar(MyScrollBar(self))

        self.setPlainText("mmmmmmmmmmmmmmmmmmmmmmmmmmmmm" * 50)


class MyScrollBar(QtWidgets.QScrollBar):
    def __init__(self, parent=None):
        super(MyScrollBar, self).__init__(parent=parent)
        self._animation = QtCore.QVariantAnimation(
            startValue=10, endValue=25, duration=500
        )
        self._animation.valueChanged.connect(self.change_width)

    def enterEvent(self, event):
        super(MyScrollBar, self).enterEvent(event)
        self._animation.setDirection(QtCore.QAbstractAnimation.Forward)
        self._animation.start()

    def leaveEvent(self, event):
        super(MyScrollBar, self).leaveEvent(event)
        self._animation.setDirection(QtCore.QAbstractAnimation.Backward)
        self._animation.start()

    def change_width(self, width):
        self.setStyleSheet("""QScrollBar:vertical{ width: %dpx;}""" % (width,))


if __name__ == "__main__":

    app = QtWidgets.QApplication()
    wid = MyTE()
    wid.show()
    app.exec_()

【讨论】:

  • 感谢您的回答!但是如果缩放适用于样式表,为什么它不适用于resize 方法?我宁愿这样做,而不是即时修改我的样式表。另外,我正在尝试在 Autodesk Maya 中使用它,但它根本无法缩放,知道吗?
  • 我已经尝试了很多小部件标志,但它似乎不是来自那里,或者我可能错过了那个。真的很好奇,样式表在 Maya 中的行为与独立的 Python 不同,我也拼命尝试调用重绘,使用 setGeometry 而不是调整大小,修改 sizeHint 方法等,但似乎没有任何效果..
【解决方案2】:

.0我终于找到了不使用样式表的方法! 感谢 eyllanesc 的回答,它给了我一个新的工作基础,我终于明白了 Qt 如何处理调整大小(我猜),我在每次我的动画值发生变化时使用 setFixedSize 的方法。

要工作,这需要有一个覆盖的sizeHint 方法,它返回动画的宽度值。 此外,这适用于 Autodesk Maya(不幸的是,eyllanesc 提供的解决方案在 Maya 中不起作用,原因不明)。

有我的解决方案:

from PySide2 import QtWidgets, QtCore, QtGui


class MyTE(QtWidgets.QPlainTextEdit):
    def __init__(self):
        super(MyTE, self).__init__()

        self.setVerticalScrollBar(MyScrollBar(self))

        self.setPlainText("mmmmmmmmmmmmmmmmmmmmmmmmmmmmm" * 50)
        self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)

    def resizeEvent(self, event):
        super(MyTE, self).resizeEvent(event)


class MyScrollBar(QtWidgets.QScrollBar):
    
    def __init__(self, parent=None):
        super(MyScrollBar, self).__init__(parent=parent)

        self._animation = QtCore.QVariantAnimation(
            startValue=10.0, endValue=25.0, duration=300
        )
        self._animation.valueChanged.connect(self.changeWidth)

        self._width = 10

    def enterEvent(self, event):
        super(MyScrollBar, self).enterEvent(event)
        self._animation.setDirection(QtCore.QAbstractAnimation.Forward)
        self._animation.start()

    def leaveEvent(self, event):
        super(MyScrollBar, self).leaveEvent(event)
        self._animation.setDirection(QtCore.QAbstractAnimation.Backward)
        self._animation.start()

    def sizeHint(self):
        """This must be overrided and return the width processed by the animation
        .. note:: In my final version I've replaced self.height() with 1 because it does not change 
        anything but self.height() was making my widget grow a bit each time.
        """
        return QtCore.QSize(self._width, self.height())

    def changeWidth(self, width):
        self._width = width  # This will allow us to return this value as the sizeHint width
        self.setFixedWidth(width) # This will ensure to scale the widget properly.


if __name__ == "__main__":

    app = QtWidgets.QApplication()
    wid = MyTE()
    wid.show()
    app.exec_()

注意:QVariantAnimation 的 startValue 和 endValue 必须是浮点型,如果它们是 int 类型的动画将不起作用(在 Qt 5.6.1 (Maya 2018) 中有效,但在 Qt 5.12.5 (Maya 2020) 中无效)

PS:如果有人对我的最终 Widget(Window 10 开始菜单滚动条)感兴趣,请私下问我。

【讨论】:

    猜你喜欢
    • 2011-12-31
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2015-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多