自定义QListWidget上的滚动条

Jas*_*enX 8 qt

我想实现我自己的半透明滚动条,它在QListWidget的顶部绘制,而不是在视口中占用永久空间.我不希望使用QML作为我的QListWidget,它的动态内容已经完全开发了6个月了.

我怎样才能做到这一点.样式表对于此目的是无用的,因为它们不会确定滚动条的位置.我希望它在QListWidget之上,而不是在它的一边,占用它的空间.

我在谈论附近的事情:

在此输入图像描述

任何关于如何做到这一点的提示将不胜感激.

j_k*_*bik 16

你要做的是一个完美的例子,一直让我厌倦了关于qt的事情 - 如果Qt的设计师没有想到的某些图形效果,那么你自己创造它就是痛苦,不断对抗Qt,以及通常以放弃为结束.

我怀疑你用小屏幕做手机(手机?平板电脑?),所以我猜没有其他方法可以解决这个问题.

我在这里尝试的是hacky,但是否则你可能不得不自己重写整个滚动条只是为了添加那些缺少的细节.我的主张是:

#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
Run Code Online (Sandbox Code Playgroud)

在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();
}
Run Code Online (Sandbox Code Playgroud)

这种卷轴在任何非重要部分都是透明的(在视觉和事件方面).它仍然会在它下面的小部件上创建一些工件 - 我想setMask()这绝不应该像这样使用.要缓解它,您可以将valueChanged()信号连接到update()列表小部件的视口的插槽.这在我的玩具示例中运行良好,但如果您在列表中嵌入自定义小部件,则可能无法忍受应对.在更复杂的应用程序的情况下,它也可能会导致性能问题 - 特别是如果您为移动平台编写.

或者你可以"分叉"整个QScrollBar类,只需修改它的paintEvent,使用比SC_All少的subControls - setAttribute(Qt::WA_OpaquePaintEvent, false);在构造函数中添加额外的它应该提供视觉透明度.然后你还应该将鼠标事件(如果没有击中任何重要的事件)转发到列表窗口小部件的视口(再次,在视图中的自定义窗口小部件的麻烦).

现在剩下的就是编写自己的布局类(或者只是手动定位它),它会将listview和滚动条彼此放在正确的位置 - QStackedLayout听起来不错,但它只允许在任何给定时间看到一个图层 - 显然不是我们在寻找什么.

最后一步是在视图上关闭默认滚动条,并将默认(不可见)滚动条的信号/插槽连接到滚动条的插槽/信号,以实现实际滚动的效果.

不久这将需要一个LOT编码得到完成的.你确定这么简单的效果值得吗?

**编辑:**

我创建了一个用于堆叠小部件的布局类 - 这个问题让我有动力去做最后的事情;)

#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
Run Code Online (Sandbox Code Playgroud)

和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;
}
Run Code Online (Sandbox Code Playgroud)

假设你已经有一些漂亮的透明滚动条,要插入它你会做:

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);
Run Code Online (Sandbox Code Playgroud)