To, co próbujesz zrobić, jest doskonałym przykładem jednej rzeczy, która uporczywie mnie denerwuje o qt - jeśli jest jakiś efekt graficzny, o którym nie pomyśleli graficy Qt, samodzielne tworzenie to ból, ciągła walka przeciwko Qt, i zazwyczaj kończy się zrezygnowaniem.
Podejrzewam, że robisz to z małymi ekranami na głowie (telefony komórkowe? Tablety?), Więc myślę, że nie ma innego sposobu rozwiązania tego problemu.
To, co tu próbuję, jest hacky, ale poza tym prawdopodobnie musiałbyś przepisać cały pasek przewijania, aby dodać kilka brakujących szczegółów. Moja propozycja to:
#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
I 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();
}
Takie scroller będzie przezroczysty (zarówno wizualnie jak i wydarzenie mądry) w każdy z nich jest zakaz ważnych części. Nadal tworzy pewne artefakty na układających się pod nim widgetach - domyślam się, że setMask()
nigdy nie był używany w ten sposób. Aby go złagodzić, można podłączyć sygnał valueChanged()
do gniazda update()
w oknie podglądu widgetu listy. To działało dobrze na moim przykładzie z zabawkami, ale jeśli umieścisz niestandardowe widżety na liście, może to stać się nie do zniesienia. Może również spowodować problemy z wydajnością w przypadku bardziej złożonych aplikacji - zwłaszcza jeśli piszesz na platformy mobilne.
Alternatywnie można po prostu "rozwidlić" całą klasę QScrollBar i po prostu zmodyfikować jej paintEvent tak, aby używał mniej podkontroli niż SC_All - z dodatkowym setAttribute(Qt::WA_OpaquePaintEvent, false);
w konstruktorze powinien zapewnić przezroczystość wizualną. Następnie powinieneś również przekazywać zdarzenia myszy (jeśli nie trafiasz na nic ważnego) do swojego widoku widgetu listy (ponownie, problem z widżetami niestandardowymi w widoku).
Pozostaje tylko napisanie własnej klasy układu (lub ręczne jej pozycjonowanie), która spowoduje umieszczenie zarówno listview, jak i paska przewijania na właściwych pozycjach - dźwięk QStackedLayout jest przyjemny, ale pozwala na widoczność tylko jednej warstwy czas - wyraźnie nie to, czego szukamy.
Ostatni krok polega na wyłączeniu domyślnych pasków przewijania w widoku i łączeniu sygnałów/gniazd domyślnego (niewidocznego) paska przewijania z gniazdami/sygnałami paska przewijania w celu uzyskania efektu rzeczywistego przewijania.
Wkrótce będzie to wymagało wprowadzenia kodu LOT. Czy jesteś pewien, że taki prosty efekt jest tego wart?
** EDIT: **
utworzyć klasę układ dla układania widgety na szczycie siebie - to pytanie dał mi motywację do zrobienia go w końcu;)
#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
A stacklayout. plik 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;
}
Zakładając, masz już jakieś fajne przezroczysty pasek przewijania, aby go wstawić byś zrobił:
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);
Myślę, że jedynym sposobem jest stworzenie własnego sterowania opartego na QListView i zaimplementowanie niestandardowego rysunku paska przewijania (teraz tylko rysunek, ale również logika). Spróbuję napisać przykładowy kod jutro. –
Musi to być QListWidget, btw - to jest to, czego używam, gdy umieszczam "widżety" na żywo w wierszach zgodnie z wymaganiami mojej aplikacji. Nie można tego osiągnąć dzięki systemowi delegowania QListView. – JasonGenX
Delegaci służą do rysowania treści. Przewiń nie jest treścią. Celem jest ukrywanie przewijania i implementacja niestandardowego przewijania nad istniejącym QListWidget. –