То, что вы пытаетесь сделать, - прекрасный пример того, что настойчиво меня раздражает qt - если есть какой-то графический эффект, о котором дизайнеры Qt не думали, создание его по себе - это боль, постоянная борьба против Qt и, как правило, заканчивается тем, что все равно отказывается.
Я подозреваю, что вы делаете это с помощью небольших экранов в вашем сознании (сотовые телефоны? Планшеты?), Поэтому я думаю, что нет другого способа решить эту проблему.
То, что я пытаюсь здесь, является взломанным, но в противном случае вам, вероятно, придется переписать всю полосу прокрутки самостоятельно, чтобы добавить эти несколько недостающих деталей. Мое суждение:
#ifndef MYSCROLLBAR_H
#define MYSCROLLBAR_H
#include <QScrollBar>
class MyScrollBar : public QScrollBar
{
Q_OBJECT
public:
explicit MyScrollBar(QWidget *parent = 0);
protected:
void showEvent (QShowEvent * event);
signals:
public slots:
void updateMask();
};
#endif // MYSCROLLBAR_H
И myscrollbar.cpp
#include "myscrollbar.h"
#include <QPaintEvent>
#include <QRegion>
#include <QStyleOptionSlider>
MyScrollBar::MyScrollBar(QWidget *parent) :
QScrollBar(parent)
{
connect(this, SIGNAL(valueChanged(int)), this, SLOT(updateMask()));
}
void MyScrollBar::updateMask(){
QStyleOptionSlider opt;
initStyleOption(&opt);
QRegion r(style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, this));
r+= style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarAddLine, this);
r+= style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSubLine, this);
setMask(r);
}
void MyScrollBar::showEvent (QShowEvent * event){
QScrollBar::showEvent(event);
updateMask();
}
Такой скроллер будет прозрачным (как визуально, так и событийно-накрест) в любом из его девитальных частей. Он по-прежнему создает некоторые артефакты на виджетах, лежащих под ним - я думаю, setMask()
никогда не должен был использоваться так. Чтобы смягчить его, вы можете подключить valueChanged()
сигнал к update()
слоту видового экрана виджета вашего списка. Это хорошо отразилось на моем примере с игрушкой, но если вы введете пользовательские виджеты в свой список, это может стать невыносимым. Это может также привести к проблемам производительности в случае более сложных приложений - особенно если вы пишете для мобильных платформ.
В качестве альтернативы вы можете просто «развить» весь класс QScrollBar и просто изменить его paintEvent, чтобы использовать меньше subControls, чем SC_All - с дополнительным setAttribute(Qt::WA_OpaquePaintEvent, false);
в конструкторе он должен обеспечивать визуальную прозрачность. Затем вы также должны перенаправить события мыши (если не нанести ничего важного) в виджет виджета списка (опять же, проблема с пользовательскими виджетами в представлении).
Теперь остается только написать собственный класс макета (или просто вручную разместить его), который будет позиционировать как списки, так и полосу прокрутки друг на друге в правильных положениях - QStackedLayout звучит хорошо, но позволяет видеть только один слой в любом заданном время - явно не то, что мы ищем.
Последний шаг - выключение отображения прокрутки по умолчанию и подключение сигналов/слотов по умолчанию (невидимая) полоса прокрутки к слотам/сигналам вашей полосы прокрутки для достижения эффекта фактической прокрутки.
Вскоре для этого потребуется кодирование LOT. Вы уверены, что такой простой эффект стоит того?
** EDIT: **
создать класс макет для укладки виджетов друг на друга - этот вопрос дал мне мотивацию, чтобы сделать это, наконец,)
#ifndef STACKLAYOUT_H
#define STACKLAYOUT_H
#include <QLayout>
class StackLayout : public QLayout
{
Q_OBJECT
public:
StackLayout();
explicit StackLayout(QWidget *parent);
~StackLayout();
void addItem (QLayoutItem * item);
int count() const;
Qt::Orientations expandingDirections() const;
bool hasHeightForWidth() const;
int heightForWidth (int w) const;
QLayoutItem * itemAt (int index) const;
bool isEmpty() const;
QSize maximumSize() const;
int minimumHeightForWidth (int w) const;
QSize minimumSize() const;
void setGeometry (const QRect & r);
QSize sizeHint() const;
QLayoutItem * takeAt (int index);
private:
QList<QLayoutItem *> itemList;
};
#endif // STACKLAYOUT_H
И stacklayout. CPP файл:
StackLayout::StackLayout()
:QLayout()
{}
StackLayout::StackLayout(QWidget *parent) :
QLayout(parent)
{
}
StackLayout::~StackLayout(){
QLayoutItem *item;
foreach (item, itemList){
delete item;
}
}
void StackLayout::addItem (QLayoutItem * item){
itemList.append(item);
}
int StackLayout::count() const{
return itemList.count();
}
Qt::Orientations StackLayout::expandingDirections() const{
Qt::Orientations result = 0;
QLayoutItem *item;
foreach (item, itemList){
result = result | item->expandingDirections();
}
return result;
}
bool StackLayout::hasHeightForWidth() const{
QLayoutItem *item;
foreach (item, itemList){
if (item->hasHeightForWidth())
return true;
}
return false;
}
int StackLayout::heightForWidth (int w) const{
int result = 0;
QLayoutItem *item;
foreach (item, itemList){
if (item->hasHeightForWidth())
result = qMax(result, item->heightForWidth(w));
}
return result;
}
QLayoutItem * StackLayout::itemAt (int index) const{
if (index<itemList.count())
return itemList[index];
return 0;
}
bool StackLayout::isEmpty() const{
QLayoutItem *item;
foreach (item, itemList){
if (!item->isEmpty())
return false;
}
return true;
}
QSize StackLayout::maximumSize() const{
QSize result=QLayout::maximumSize();
QLayoutItem *item;
foreach (item, itemList){
result = result.boundedTo(item->maximumSize());
}
return result;
}
int StackLayout::minimumHeightForWidth (int w) const{
int result = 0;
QLayoutItem *item;
foreach (item, itemList){
if (item->hasHeightForWidth())
result = qMax(result, item->minimumHeightForWidth(w));
}
return result;
}
QSize StackLayout::minimumSize() const{
QSize result=QLayout::minimumSize();
QLayoutItem *item;
foreach (item, itemList){
result = result.expandedTo(item->minimumSize());
}
return result;
}
void StackLayout::setGeometry (const QRect & r){
QLayoutItem *item;
foreach (item, itemList){
item->setGeometry(r);
}
}
QSize StackLayout::sizeHint() const{
QSize result=QSize(0,0);
QLayoutItem *item;
foreach (item, itemList){
result = result.expandedTo(item->sizeHint());
}
return result;
}
QLayoutItem * StackLayout::takeAt (int index){
if (index < itemList.count())
return itemList.takeAt(index);
return 0;
}
Предполагая, что у вас уже есть некоторые хорошие прозрачные прокрутки, чтобы вставить его, вы должны сделать следующее:
QWidget* w = new QWidget();
StackLayout* sl = new StackLayout(w);
QListView* lv = new QListView(w);
sl->addWidget(lv);
QHBoxLayout* hbl = new QHBoxLayout();
sl->addItem(hbl);
TransparentScrollBar* tsc = new TransparentScrollBar(w);
hbl->addWidget(tsc,0);
hbl->insertStretch(0,1);
Я думаю, что единственный способ - создать собственный контроль на основе QListView и реализовать собственный рисунок полосы прокрутки (теперь только рисование, но и логика). Я попытаюсь написать пример кода завтра. –
Должен быть QListWidget, кстати, это то, что я использую, когда я помещаю живые «виджеты» в строки согласно требованиям моего приложения. Вы не можете добиться этого с помощью системы делегирования QListView. – JasonGenX
Делегаты используются для рисования контента. Свиток не является содержимым. Цель состоит в том, чтобы скрыть прокрутку и реализовать пользовательский прокрутка по существующему QListWidget. –