Usually the default QScrollBar's from PyQt are too small for high dpi displays. That's why it can be necessary to adjust them. And once you're doing it anyway, why not take benefit from the aesthetic improvements you can make?
This is how you can tweak the 'look and feel' of your 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 ###
I found the following documentation on how to setup the style sheet:
http://doc.qt.io/qt-4.8/stylesheet-examples.html#customizing-qscrollbar d
THE PROBLEM :
After customizing the QScrollBars, they work perfectly. But the user doesn't get any visual feedback when clicking either the handle or the arrows. Clicking the arrow for example, will not result in the visual feedback that the arrow has been pressed.
Here is an example of how it should be:
I don't know how to use style sheets achieve it.
I created three qss files.
a.qss
QScrollBar:vertical{
background: black;
width: 10px;
}
b.qss
QScrollBar:vertical{
background: black;
width: 10px;
}
QScrollBar::add-page:vertical{
background: red;
}
c.qss
QScrollBar:vertical{
background: black;
width: 10px;
}
QScrollBar::sub-page:vertical{
background: red;
}
and the code:
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
I am learning English, I hope you don't mind this.
You can actually use QStyle.hitTestComplexControl()
, but it requires you to subclass the scrollbars too. In the following example I fully implemented the vertical scrollbar, you just have to fill in the basic css parts of the horizontal one.
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)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.