2013-04-29 48 views
8

ビューポートで永続的なスペースを占める代わりに、QListWidgetの上に描画する半透明のスクロールバーを実装したいと思います。 QMLをQListWidgetとして使用することは望ましくなく、動的コンテンツはすでに6ヶ月以上にわたって完全に開発されています。QListWidgetでスクロールバーをカスタマイズする

どうすれば実現できますか?スタイルシートは、スクロールバーの位置を決定しないので、その目的には役に立たない。私はそれがQListWidgetの上にあることを望んでいます。

私はこの付近で何かについて話している:

enter image description here

それをどのように行うかについて任意のヒントが理解されるであろう。

+0

私は、独自のQListViewベースのコントロールを作成し、スクロールバーのカスタム描画を実装することしかできないと思います。明日サンプルコードを書くつもりです。 –

+0

これはQListWidget、btwでなければなりません。これは私のアプリの要求に従って、ライブ "ウィジェット"を行に入れているので、これを使用しています。あなたはQListViewの委任システムでそれを達成することはできません。 – JasonGenX

+0

デリゲートはコンテンツの描画に使用されます。スクロールは内容ではありません。ターゲットはスクロールを隠し、既存のQListWidgetにカスタムスクロールを実装することです。 –

答えて

14

あなたがやろうとしていることは、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クラス全体を "fork"して、単にpaintEventを変更してSC_Allよりも少ないsubControlを使用することもできます。コンストラクタにsetAttribute(Qt::WA_OpaquePaintEvent, false);を追加すると、視覚的に透明になります。次に、リストウィジェットのビューポート(ビューのカスタムウィジェットと再び、トラブル)にマウスイベント(重要な何かを打っていない場合)にも転送する必要があります。

残っているのは、リストビューとスクロールバーの両方を正しい位置に置く独自のレイアウトクラスを作成することです(または手動で配置すること).QStackedLayoutはうれしいですが、1つのレイヤだけが表示される時間 - 明らかに私たちが探しているものではありません。

最後のステップでは、実際のスクロールの効果を得るために、デフォルトのスクロールバーの表示をオフにし、既定(見えない)スクロールバーの信号/スロットをスクロールバーのスロット/信号に接続します。

まもなくこれを行うにはコードの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); 
+0

私はそれをとにかくコード化することを決めたら、もっとコード/ヘルプを提供することができます。 –

+0

私は許しても、そのファイルはTransparentScrollBarクラスですか? それは単純なウィジェットだと思います。 –

+0

透明なスクロールバーで私はドミトリーSazonovの答えのようなものを意味しました。 –

2

ここにあなたのクエストインのサンプルコードがあります。

行われていない:スクロール

の マウスのドラッグを完​​了:任意のマウスホバー/休暇イベントの サポート スクロールバーがマウスイベント

のために透明であり、スクロールの サポートそれは任意のための良いスタートポイントですあなたの仕事に応じてカスタマイズ。使用法:

GUI::MegaScrollBar *bar = new GUI::MegaScrollBar(ui->listWidget); 
bar->resize(40, 30); // First arg - width of scroller 

MegaScrollBar.h

#ifndef MEGASCROLLBAR_H 
#define MEGASCROLLBAR_H 

#include <QWidget> 
#include <QPointer> 


class QAbstractItemView; 
class QResizeEvent; 

namespace GUI 
{ 

    class MegaScrollBar 
     : public QWidget 
    { 
     Q_OBJECT 

    public: 
     MegaScrollBar(QAbstractItemView *parentView); 
     ~MegaScrollBar(); 

    private slots: 
     void updatePos(); 

    private: 
     bool eventFilter(QObject *obj, QEvent *event); 
     void onResize(QResizeEvent *e); 
     void paintEvent(QPaintEvent * event); 
     void resizeEvent(QResizeEvent * event); 

     QPointer<QAbstractItemView> m_view; 
     QPointer<QWidget> m_scrollBtn; 
    }; 

} 


#endif // MEGASCROLLBAR_H 

MegaScrollBar.cpp

#include "MegaScrollBar.h" 

#include <QAbstractItemView> 
#include <QEvent> 
#include <QResizeEvent> 
#include <QScrollBar> 
#include <QDebug> 
#include <QPainter> 

#include "ScrollButton.h" 


namespace GUI 
{ 

    MegaScrollBar::MegaScrollBar(QAbstractItemView *parentView) 
     : QWidget(parentView, Qt::FramelessWindowHint) 
     , m_view(parentView) 
    { 
     Q_ASSERT(parentView); 

     setAttribute(Qt::WA_TranslucentBackground); 
     setAttribute(Qt::WA_TransparentForMouseEvents); 

     m_scrollBtn = new ScrollButton(parentView); 
     m_scrollBtn->setFixedSize(20, 40); 

     m_view->installEventFilter(this); 

     QScrollBar *sb = m_view->verticalScrollBar(); 
     connect(sb, SIGNAL(valueChanged(int)), this, SLOT(updatePos())); 
    } 

    MegaScrollBar::~MegaScrollBar() 
    { 
     removeEventFilter(m_view); 
    } 

    bool MegaScrollBar::eventFilter(QObject *obj, QEvent *event) 
    { 
     switch (event->type()) 
     { 
     case QEvent::Enter: 
      m_scrollBtn->show(); 
      break; 

     case QEvent::Leave: 
      m_scrollBtn->hide(); 
      break; 

     case QEvent::Resize: 
      onResize(static_cast< QResizeEvent * >(event)); 
      break; 
     } 

     return QWidget::eventFilter(obj, event); 
    } 

    void MegaScrollBar::onResize(QResizeEvent *e) 
    { 
     const int x = e->size().width() - width(); 
     const int y = 0; 
     const int w = width(); 
     const int h = e->size().height(); 

     move(x, y); 
     resize(w, h); 

     updatePos(); 
    } 

    void MegaScrollBar::updatePos() 
    { 
     QScrollBar *sb = m_view->verticalScrollBar(); 
     const int min = sb->minimum(); 
     const int val = sb->value(); 
     const int max = sb->maximum(); 
     const int x = pos().x() + (width() - m_scrollBtn->width())/2; 

     if (max == 0) 
     { 
      m_scrollBtn->move(x, pos().y()); 
      return ; 
     } 

     const int maxY = height() - m_scrollBtn->height(); 
     const int y = (maxY * val)/max; 

     m_scrollBtn->move(x, y); 
    } 

    void MegaScrollBar::paintEvent(QPaintEvent * event) 
    { 
     Q_UNUSED(event); 
     QPainter p(this); 
     QRect rc(0, 0, rect().width() - 1, rect().height() - 1); 

     // Draw any scroll background 
     p.fillRect(rc, QColor(255, 255, 200, 100)); 
    } 

    void MegaScrollBar::resizeEvent(QResizeEvent * event) 
    { 
     Q_UNUSED(event); 
     updatePos(); 
    } 

} 

プレビュー:

Sample

設定することが可能ですスクロールボタンのyのウィジェット:ここでカスタム1:あなたはマウス操作を処理できない場合 ScrollButton.h

#ifndef SCROLLBUTTON_H 
#define SCROLLBUTTON_H 

#include <QWidget> 


namespace GUI 
{ 

    class ScrollButton 
     : public QWidget 
    { 
     Q_OBJECT 

    public: 
     ScrollButton(QWidget *parent); 
     ~ScrollButton(); 

    private: 
     void paintEvent(QPaintEvent * event); 
    }; 

} 


#endif // SCROLLBUTTON_H 

ScrollButton.cpp

#include "ScrollButton.h" 

#include <QPainter> 
#include <QGraphicsOpacityEffect> 
#include <QColor> 


namespace GUI 
{ 

    ScrollButton::ScrollButton(QWidget *parent) 
     : QWidget(parent) 
    { 
     QGraphicsOpacityEffect *op = new QGraphicsOpacityEffect(this); 
     op->setOpacity(0.5); 
     setGraphicsEffect(op); 
    } 

    ScrollButton::~ScrollButton() 
    { 
    } 

    void ScrollButton::paintEvent(QPaintEvent * event) 
    { 
     Q_UNUSED(event); 

     // Draw any scroll button 
     QPainter p(this); 
     QRect rc(5, 5, rect().width() - 6, rect().height() - 6); 

     p.fillRect(rc, QColor(0, 0, 0, 255)); 
    } 

} 

、コメントしてください。

+0

'Qt :: WA_TransparentForMouseEvents'は、そのようなスクロールバーですべてのマウス機能を無効にしませんか?私がそれを動作させるために見る唯一の方法は、ビューポートからマウスイベントをフィルタリング(または他の方法、つまりウィジェットツリーのサブクラスをおそらく傍受して)し、スクロールバーウィジェットにフィードすることです。あなたのビューにカスタムウィジェットがあれば、これはますます難しくなります。私が提案したマスクを適用することは選択肢かもしれません。 –

+0

あなたのスクロールバーは単に情報のためのものであり、それを使ってあなたのウィジェットをアクティブにスクロールするものではないのですか? –

+0

インタラクションのために、MegaScrollBar :: MegaScrollBar()に任意のウィジェットを設定することができます。 m_scrollBtnウィジェットからのマウスイベントのリダイレクトも実装する必要があります。 –

関連する問題