Python 在PyQt中自定义QScrollbar

Python 在PyQt中自定义QScrollbar,python,qt,pyqt,pyqt5,Python,Qt,Pyqt,Pyqt5,通常,PyQt的默认QScrollBar对于高dpi显示来说太小。这就是为什么有必要调整它们。不管怎样,一旦你做到了,为什么不从你所能做的美学改进中获益呢 这就是如何调整QScrollBar的“外观和感觉”: ######################################## # My custom QScrollArea # # widget # ######################

通常,PyQt的默认QScrollBar对于高dpi显示来说太小。这就是为什么有必要调整它们。不管怎样,一旦你做到了,为什么不从你所能做的美学改进中获益呢

这就是如何调整QScrollBar的“外观和感觉”:

########################################
#     My custom QScrollArea            #
#     widget                           #
########################################

class MyScrollArea(QScrollArea):

    def __init__(self, parent):
        super(MyScrollArea, self).__init__(parent)
        ...

        self.setStyleSheet("""QScrollBar:vertical {
                    width: 45px;
                    margin: 45px 0 45px 0;
                    background: #32CC99;
                  }

                  QScrollBar::handle:vertical {
                    border: 10px solid grey;
                    background: white;
                    min-height: 10px;
                  }

                  QScrollBar::add-line:vertical {
                    border: 2px solid grey;
                    background: none;
                    height: 45px;
                    subcontrol-position: bottom;
                    subcontrol-origin: margin;
                  }

                  QScrollBar::sub-line:vertical {
                    border: 2px solid grey;
                    background: none;
                    height: 45px;
                    subcontrol-position: top;
                    subcontrol-origin: margin;
                  }

                  QScrollBar::up-arrow:vertical {
                    border: 5px solid grey;
                    height: 40px; 
                    width: 40px 
                  }

                  QScrollBar::down-arrow:vertical {
                    border: 5px solid grey;
                    height: 40px; 
                    width: 40px                              
                  }""")
        ...

    ### End init ###

### End Class ###
我找到了以下关于如何设置样式表的文档:

d

问题:

定制QScrollBars后,它们可以完美地工作。但是用户在单击手柄或箭头时不会得到任何视觉反馈。例如,单击箭头不会产生按下箭头的视觉反馈

下面是一个示例,说明应该如何:


我不知道如何使用样式表来实现它

我创建了三个qss文件

a、 qss

    QScrollBar:vertical{
    background: black;
    width: 10px;
}
b、 qss

c、 qss

以及守则:

class Main(QScrollArea):

    def __init__(self):

        super(Main, self).__init__()

        self.resize(300, 200)

        self.index = QWidget()
        self.index.setMinimumHeight(1000)
        self.index.setMinimumWidth(500)


        self.setWidget(self.index)
        self.setWidgetResizable(True)

        with open('a.qss', 'r') as f:
            self.a_text = f.read()
            self.setStyleSheet(self.a_text)
        with open('b.qss', 'r') as f:
            self.b_text = f.read()
        with open('c.qss', 'r') as f:
            self.c_text = f.read()

        # save values.
        self.value = 0
        self.pre_value = 0

        # save pause condition.
        self.pauseCond = True
        self.timer = QTimer()

        self.timer.timeout.connect(self.timerout)
        self.verticalScrollBar().actionTriggered.connect(self.change)
        self.timer.start(300)

    def change(self):
        # if sliding the slider(click and Mouse pulley).

        self.value = self.verticalScrollBar().sliderPosition()

        # if sliding down/right.
        if self.pre_value < self.value:
            self.setStyleSheet(self.b_text)
        # if sliding up/left.
        elif self.pre_value > self.value:
            self.setStyleSheet(self.c_text)

        self.pre_value = self.verticalScrollBar().sliderPosition()
        self.pauseCond = True

    def timerout(self):
        if not self.pauseCond:
            return 1

        # if click or pulley stop.
        if self.verticalScrollBar().sliderPosition() == self.value:
            self.setStyleSheet(self.a_text)
            self.pauseCond = False
class Main(QScrollArea):
定义初始化(自):
超级(主,自).\uuuu初始化
自我调整大小(300200)
self.index=QWidget()
自索引设置最小高度(1000)
自索引设置最小宽度(500)
self.setWidget(self.index)
self.setWidgetResizeable(True)
以开放式('a.qss','r')作为f:
self.a_text=f.read()
self.setStyleSheet(self.a_文本)
以开放式('b.qss','r')作为f:
self.b_text=f.read()
以开放式('c.qss','r')作为f:
self.c_text=f.read()
#保存值。
self.value=0
self.pre_值=0
#保存暂停条件。
self.paussecond=True
self.timer=QTimer()
self.timer.timeout.connect(self.timerout)
self.verticalScrollBar().actionTriggered.connect(self.change)
自动定时器启动(300)
def更改(自我):
#如果滑动滑块(单击并用鼠标单击皮带轮)。
self.value=self.verticalScrollBar().sliderPosition()
#如果向下/向右滑动。
如果self.pre_值self.value:
self.setStyleSheet(self.c_文本)
self.pre_value=self.verticalScrollBar().sliderPosition()
self.paussecond=True
def时间路由(自身):
如果不是self.paussecond:
返回1
#如果单击或停止皮带轮。
如果self.verticalScrollBar().sliderPosition()==self.value:
self.setStyleSheet(self.a_文本)
self.paussecond=False

我正在学习英语,希望你不要介意。

我不知道如何使用样式表来实现它

我创建了三个qss文件

a、 qss

    QScrollBar:vertical{
    background: black;
    width: 10px;
}
b、 qss

c、 qss

以及守则:

class Main(QScrollArea):

    def __init__(self):

        super(Main, self).__init__()

        self.resize(300, 200)

        self.index = QWidget()
        self.index.setMinimumHeight(1000)
        self.index.setMinimumWidth(500)


        self.setWidget(self.index)
        self.setWidgetResizable(True)

        with open('a.qss', 'r') as f:
            self.a_text = f.read()
            self.setStyleSheet(self.a_text)
        with open('b.qss', 'r') as f:
            self.b_text = f.read()
        with open('c.qss', 'r') as f:
            self.c_text = f.read()

        # save values.
        self.value = 0
        self.pre_value = 0

        # save pause condition.
        self.pauseCond = True
        self.timer = QTimer()

        self.timer.timeout.connect(self.timerout)
        self.verticalScrollBar().actionTriggered.connect(self.change)
        self.timer.start(300)

    def change(self):
        # if sliding the slider(click and Mouse pulley).

        self.value = self.verticalScrollBar().sliderPosition()

        # if sliding down/right.
        if self.pre_value < self.value:
            self.setStyleSheet(self.b_text)
        # if sliding up/left.
        elif self.pre_value > self.value:
            self.setStyleSheet(self.c_text)

        self.pre_value = self.verticalScrollBar().sliderPosition()
        self.pauseCond = True

    def timerout(self):
        if not self.pauseCond:
            return 1

        # if click or pulley stop.
        if self.verticalScrollBar().sliderPosition() == self.value:
            self.setStyleSheet(self.a_text)
            self.pauseCond = False
class Main(QScrollArea):
定义初始化(自):
超级(主,自).\uuuu初始化
自我调整大小(300200)
self.index=QWidget()
自索引设置最小高度(1000)
自索引设置最小宽度(500)
self.setWidget(self.index)
self.setWidgetResizeable(True)
以开放式('a.qss','r')作为f:
self.a_text=f.read()
self.setStyleSheet(self.a_文本)
以开放式('b.qss','r')作为f:
self.b_text=f.read()
以开放式('c.qss','r')作为f:
self.c_text=f.read()
#保存值。
self.value=0
self.pre_值=0
#保存暂停条件。
self.paussecond=True
self.timer=QTimer()
self.timer.timeout.connect(self.timerout)
self.verticalScrollBar().actionTriggered.connect(self.change)
自动定时器启动(300)
def更改(自我):
#如果滑动滑块(单击并用鼠标单击皮带轮)。
self.value=self.verticalScrollBar().sliderPosition()
#如果向下/向右滑动。
如果self.pre_值self.value:
self.setStyleSheet(self.c_文本)
self.pre_value=self.verticalScrollBar().sliderPosition()
self.paussecond=True
def时间路由(自身):
如果不是self.paussecond:
返回1
#如果单击或停止皮带轮。
如果self.verticalScrollBar().sliderPosition()==self.value:
self.setStyleSheet(self.a_文本)
self.paussecond=False
我正在学习英语,希望您不要介意。

您可以实际使用,但它也要求您对滚动条进行子类化。 在下面的示例中,我完全实现了垂直滚动条,您只需填写水平滚动条的基本css部分

class CustomScrollBar(QtWidgets.QScrollBar):
    def __init__(self, *args, **kwargs):
        QtWidgets.QScrollBar.__init__(self, *args, **kwargs)
        self.baseSheet = '''
            QScrollBar {{
                width: 45px;
                margin: 45px 0 45px 0;
                background: #32CC99;
            }}

            QScrollBar::handle {{
                border: 10px solid grey;
                background: white;
                min-height: 10px;
            }}

            QScrollBar::add-line:vertical {{
                border: 2px solid grey;
                background: none;
                height: 45px;
                subcontrol-position: bottom;
                subcontrol-origin: margin;
            }}

            QScrollBar::sub-line:vertical {{
                border: 2px solid grey;
                background: none;
                height: 45px;
                subcontrol-position: top;
                subcontrol-origin: margin;
            }}

            QScrollBar::up-arrow:vertical {{
                subcontrol-position: bottom;
                subcontrol-origin: margin;
                {upArrow}
            }}

            QScrollBar::down-arrow:vertical {{
                subcontrol-position: bottom;
                subcontrol-origin: margin;
                {downArrow}
            }}

            QScrollBar::left-arrow:vertical {{
                subcontrol-position: bottom;
                subcontrol-origin: margin;
                {leftArrow}
            }}

            QScrollBar::right-arrow:vertical {{
                subcontrol-position: bottom;
                subcontrol-origin: margin;
                {rightArrow}
            }}
            '''
        self.arrowNormal = '''
                border-top: 5px solid lightgray;
                border-left: 5px solid lightgray;
                border-right: 5px solid gray;
                border-bottom: 5px solid gray;
            '''
        self.arrowPressed = '''
                border: 5px solid darkgray;
            '''
        self.setStyleSheet(self.baseSheet.format(
            upArrow=self.arrowNormal, 
            downArrow=self.arrowNormal, 
            leftArrow=self.arrowNormal, 
            rightArrow=self.arrowNormal))

    def mousePressEvent(self, event):
        QtWidgets.QScrollBar.mousePressEvent(self, event)
        opt = QtWidgets.QStyleOptionSlider()
        opt.initFrom(self)

        subControl = self.style().hitTestComplexControl(self.style().CC_ScrollBar, opt, event.pos(), self)
        if subControl == self.style().SC_ScrollBarAddLine:
            if self.orientation() == QtCore.Qt.Vertical:
                downArrow = self.arrowPressed
                upArrow = leftArrow = rightArrow = self.arrowNormal
            else:
                rightArrow = self.arrowPressed
                upArrow = downArrow = leftArrow = self.arrowNormal
        elif subControl == self.style().SC_ScrollBarSubLine:
            if self.orientation() == QtCore.Qt.Vertical:
                upArrow = self.arrowPressed
                downArrow = leftArrow = rightArrow = self.arrowNormal
            else:
                leftArrow = self.arrowPressed
                rightArrow = upArrow = downArrow = self.arrowNormal
        self.setStyleSheet(self.baseSheet.format(upArrow=upArrow, downArrow=downArrow, leftArrow=leftArrow, rightArrow=rightArrow))

    def mouseReleaseEvent(self, event):
        QtWidgets.QScrollBar.mouseReleaseEvent(self, event)
        self.setStyleSheet(self.baseSheet.format(
            upArrow=self.arrowNormal, 
            downArrow=self.arrowNormal, 
            leftArrow=self.arrowNormal, 
            rightArrow=self.arrowNormal))


class MyScrollArea(QtWidgets.QScrollArea):
    def __init__(self, parent=None):
        super(MyScrollArea, self).__init__(parent)
        w = QtWidgets.QWidget()
        w.setFixedSize(640, 480)
        self.setWidget(w)
        vScrollBar = CustomScrollBar(QtCore.Qt.Vertical)
        self.setVerticalScrollBar(vScrollBar)
您实际上可以使用,但它也要求您对滚动条进行子类化。 在下面的示例中,我完全实现了垂直滚动条,您只需填写水平滚动条的基本css部分

class CustomScrollBar(QtWidgets.QScrollBar):
    def __init__(self, *args, **kwargs):
        QtWidgets.QScrollBar.__init__(self, *args, **kwargs)
        self.baseSheet = '''
            QScrollBar {{
                width: 45px;
                margin: 45px 0 45px 0;
                background: #32CC99;
            }}

            QScrollBar::handle {{
                border: 10px solid grey;
                background: white;
                min-height: 10px;
            }}

            QScrollBar::add-line:vertical {{
                border: 2px solid grey;
                background: none;
                height: 45px;
                subcontrol-position: bottom;
                subcontrol-origin: margin;
            }}

            QScrollBar::sub-line:vertical {{
                border: 2px solid grey;
                background: none;
                height: 45px;
                subcontrol-position: top;
                subcontrol-origin: margin;
            }}

            QScrollBar::up-arrow:vertical {{
                subcontrol-position: bottom;
                subcontrol-origin: margin;
                {upArrow}
            }}

            QScrollBar::down-arrow:vertical {{
                subcontrol-position: bottom;
                subcontrol-origin: margin;
                {downArrow}
            }}

            QScrollBar::left-arrow:vertical {{
                subcontrol-position: bottom;
                subcontrol-origin: margin;
                {leftArrow}
            }}

            QScrollBar::right-arrow:vertical {{
                subcontrol-position: bottom;
                subcontrol-origin: margin;
                {rightArrow}
            }}
            '''
        self.arrowNormal = '''
                border-top: 5px solid lightgray;
                border-left: 5px solid lightgray;
                border-right: 5px solid gray;
                border-bottom: 5px solid gray;
            '''
        self.arrowPressed = '''
                border: 5px solid darkgray;
            '''
        self.setStyleSheet(self.baseSheet.format(
            upArrow=self.arrowNormal, 
            downArrow=self.arrowNormal, 
            leftArrow=self.arrowNormal, 
            rightArrow=self.arrowNormal))

    def mousePressEvent(self, event):
        QtWidgets.QScrollBar.mousePressEvent(self, event)
        opt = QtWidgets.QStyleOptionSlider()
        opt.initFrom(self)

        subControl = self.style().hitTestComplexControl(self.style().CC_ScrollBar, opt, event.pos(), self)
        if subControl == self.style().SC_ScrollBarAddLine:
            if self.orientation() == QtCore.Qt.Vertical:
                downArrow = self.arrowPressed
                upArrow = leftArrow = rightArrow = self.arrowNormal
            else:
                rightArrow = self.arrowPressed
                upArrow = downArrow = leftArrow = self.arrowNormal
        elif subControl == self.style().SC_ScrollBarSubLine:
            if self.orientation() == QtCore.Qt.Vertical:
                upArrow = self.arrowPressed
                downArrow = leftArrow = rightArrow = self.arrowNormal
            else:
                leftArrow = self.arrowPressed
                rightArrow = upArrow = downArrow = self.arrowNormal
        self.setStyleSheet(self.baseSheet.format(upArrow=upArrow, downArrow=downArrow, leftArrow=leftArrow, rightArrow=rightArrow))

    def mouseReleaseEvent(self, event):
        QtWidgets.QScrollBar.mouseReleaseEvent(self, event)
        self.setStyleSheet(self.baseSheet.format(
            upArrow=self.arrowNormal, 
            downArrow=self.arrowNormal, 
            leftArrow=self.arrowNormal, 
            rightArrow=self.arrowNormal))


class MyScrollArea(QtWidgets.QScrollArea):
    def __init__(self, parent=None):
        super(MyScrollArea, self).__init__(parent)
        w = QtWidgets.QWidget()
        w.setFixedSize(640, 480)
        self.setWidget(w)
        vScrollBar = CustomScrollBar(QtCore.Qt.Vertical)
        self.setVerticalScrollBar(vScrollBar)

我非常怀疑你是否能用样式表来实现它。单击箭头时,样式表无法更改滚动条句柄的状态。为此,您可能必须对QScrollBar进行子类化,然后自己绘制。我非常怀疑您是否可以使用样式表来实现它。单击箭头时,样式表无法更改滚动条句柄的状态。为此,您可能需要对QScrollBar进行子类化,并自己绘制。非常感谢!我明天会试试看:-)非常感谢!明天我将尝试测试它:-)