Введение
В этой статье соберём более полные, законченные примеры кастомизации сложных составных виджетов — чекбокса с собственными иконками состояний и полностью переработанного скроллбара, которые на практике одни из самых частых объектов кастомизации, поскольку их вид по умолчанию особенно сильно отличается от современного, «плоского» дизайна большинства приложений.
Концепция
Скроллбар — один из самых составных стандартных виджетов с точки зрения количества псевдоэлементов: помимо ::handle (ползунок) у него есть ::add-line/::sub-line (кнопки прокрутки на краях, которые в современном дизайне обычно скрывают вовсе) и ::add-page/::sub-page (область трека до и после ползунка). Полная кастомизация скроллбара под «плоский» современный стиль обычно означает скрытие кнопок прокрутки и явную стилизацию только трека и ползунка.
Пример кода: Кастомизация стандартных виджетов через QSS
app.setStyleSheet(R"(
/* Чекбокс с разными иконками для каждого состояния */
QCheckBox {
spacing: 8px;
font-size: 14px;
}
QCheckBox::indicator {
width: 20px;
height: 20px;
border-radius: 4px;
border: 2px solid #d1d5db;
background-color: white;
}
QCheckBox::indicator:hover {
border-color: #2563eb;
}
QCheckBox::indicator:checked {
background-color: #2563eb;
border-color: #2563eb;
image: url(:/icons/check-white.svg);
}
/* Промежуточное состояние "частично выбрано" — отдельная иконка */
QCheckBox::indicator:indeterminate {
background-color: #93c5fd;
border-color: #93c5fd;
image: url(:/icons/dash-white.svg);
}
QCheckBox::indicator:disabled {
background-color: #f3f4f6;
border-color: #e5e7eb;
}
/* Полностью переработанный вертикальный скроллбар в современном плоском стиле */
QScrollBar:vertical {
background: transparent;
width: 10px;
margin: 0;
}
/* Скрытие кнопок прокрутки сверху и снизу — характерно для современного минималистичного дизайна */
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
height: 0px;
background: none;
}
/* Трек до и после ползунка — делаем прозрачным, видимым остаётся только сам ползунок */
QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
background: transparent;
}
/* Сам ползунок скроллбара */
QScrollBar::handle:vertical {
background-color: #cbd5e1;
border-radius: 5px;
min-height: 30px;
}
QScrollBar::handle:vertical:hover {
background-color: #94a3b8;
}
)");
Пояснения к коду
Для чекбокса показаны четыре различных состояния индикатора: обычное, при наведении (:hover), отмеченное (:checked), и специфичное для трёхпозиционных чекбоксов промежуточное состояние (:indeterminate, используемое, например, в чекбоксе «выбрать все», когда выбрана только часть элементов списка) — каждое состояние получает собственную комбинацию цвета фона и иконки, что даёт пользователю чёткую визуальную обратную связь о текущем состоянии без необходимости вглядываться в мелкие детали.
Стилизация скроллбара демонстрирует распространённый паттерн «минималистичного» скроллбара: кнопки прокрутки (::add-line/::sub-line) скрываются заданием нулевой высоты и пустого фона, область трека (::add-page/::sub-page) делается прозрачной, и визуально остаётся только сам ползунок (::handle) — именно так выглядит большинство современных скроллбаров в популярных приложениях, разительно отличаясь от объёмного, с явными кнопками стрелок скроллбара классического стиля Windows.
Подводные камни
- Полное скрытие кнопок прокрутки скроллбара через нулевую высоту может оставить нефункциональную, но пустую область на месте бывшей кнопки, если не задать
background: noneдополнительно — в некоторых версиях/стилях Qt может остаться нежелательная остаточная рамка или фон даже при нулевом размере элемента, что нужно явно проверять визуально после применения стиля. - Указание иконок через
image: url(...)требует, чтобы соответствующие файлы были встроены в приложение через Qt Resource System (основной цикл статей, файл.qrc) — путь, начинающийся с:/, ссылается именно на встроенный ресурс, а не на файл в файловой системе; забытая регистрация ресурса в.qrc-файле приводит к тому, что иконка просто не отображается, без явной ошибки в QSS. - Стилизация
QCheckBox::indicator:indeterminateимеет смысл только если код приложения действительно использует трёхпозиционный режим чекбокса (setCheckState(Qt::PartiallyChecked)илиsetTristate(true)) — если виджет используется только в обычном двухпозиционном режиме, написанные стили для промежуточного состояния просто никогда не будут применены, и это не ошибка, а признак избыточного, не используемого кода стилей. - Слишком тонкий или почти невидимый ползунок скроллбара (типичная «ультра-минималистичная» эстетика) может ухудшить доступность для пользователей с нарушениями зрения или для пользователей, использующих устройства с не самой точной координацией движений мыши/тач-панели — стоит балансировать эстетические предпочтения дизайна с практической применимостью элемента управления, особенно учитывая темы доступности, разобранные в отдельном цикле статей (200–209).