I'm trying to learn how to customize a QScrollArea
scrollbar without using stylesheets.
My goal is to exclude the top and bottom arrows and draw only the slider with a rounded rect.
I partially got it working but I'm struggling with two things, there's a black border around the slider, and the page control is not being updated/drawn correctly:
#include "scrollarea.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::dellClass())
{
ui->setupUi(this);
ScrollArea* scrollArea = new ScrollArea(this);
scrollArea->setFrameShape(QFrame::NoFrame);
scrollArea->setLineWidth(0);
scrollArea->setWidgetResizable(true);
QWidget* widget = new QWidget(scrollArea);
widget->setObjectName("w");
widget->setStyleSheet("#w { background-color: rgba(40, 80, 120, 50); }");
QVBoxLayout* layout = new QVBoxLayout(widget);
for (int i = 0; i < 20; i++)
{
QPushButton* btn = new QPushButton(widget);
btn->setFixedHeight(32);
layout->insertWidget(i, btn);
}
scrollArea->setWidget(widget);
ui->centralWidget->layout()->addWidget(scrollArea);
}
scrollarea.h
class VProxyStyle : public QProxyStyle
{
public:
VProxyStyle(QStyle *style = nullptr) : QProxyStyle(style) { }
QRect subControlRect(QStyle::ComplexControl cc, const QStyleOptionComplex* opt, QStyle::SubControl sc, const QWidget *widget = nullptr) const override
{
// https://doc.qt.io/qt-6/qstyle.html
// SC_ScrollBarGroove:
// Special sub-control which contains the area in which the slider handle may move
if (cc == CC_ScrollBar || sc == QStyle::SC_ScrollBarGroove)
{
QRect rect = QProxyStyle::subControlRect(cc, opt, sc, widget);
// Exclude the top and bottom arrows area.
rect.setTop(0);
rect.setBottom(rect.bottom() + 17);
return rect;
}
// The rect of top and bottom arrows.
if (sc == QStyle::SC_ScrollBarAddLine || sc == QStyle::SC_ScrollBarSubLine) {
return QRect();
}
return QProxyStyle::subControlRect(cc, opt, sc, widget);
}
};
class VScrollBar : public QScrollBar
{
Q_OBJECT
public:
VScrollBar(Qt::Orientation orientation, QWidget *parent) : QScrollBar(orientation, parent)
{
VProxyStyle *proxyStyle = new VProxyStyle(style());
setStyle(proxyStyle);
}
void paintEvent(QPaintEvent *event) override
{
//QScrollBar::paintEvent(event);
QPainter painter(this);
//painter.eraseRect(event->rect());
painter.setRenderHint(QPainter::Antialiasing);
QRect sliderRect = sliderHandleRect();
painter.setBrush(Qt::red);
painter.drawRoundedRect(sliderRect, 8, 8);
}
QRect sliderHandleRect() const
{
QStyleOptionSlider opt;
initStyleOption(&opt);
return style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, this);
}
};
class ScrollArea : public QScrollArea
{
Q_OBJECT
public:
ScrollArea(QWidget* parent = 0) : QScrollArea(parent) {
setVerticalScrollBar(new VScrollBar(Qt::Vertical, this));
}
};