2
votes

I'm working on an application that needs to have a menu on the left side of the screen containing multiple items (text). The only items I want to be visible are the actual text and the highlight bar. I would also like to modify the highlight bar so that: a. I can animate it, and slide it from one selection to the next b. I can use a custom pixmap with rounded corners instead of the default highlight color

I've tried using a QListWidget and stylesheets and had some success, but I don't believe it's possible to round the corners of my highlight bar using this method. I'm also not sure I can animate the movement of the bar from one item to the next:

preset_list_view->setStyleSheet("QListView {color: rgb(230, 230, 230); background-color: rgba(0,0,0,0); border-style: none} QListView::item:selected {background-image: url(:/ui_resources/elements-preset_select/highlight_bar_270x30-black_bg.bmp)}");

I've looked all over online and not found much. There is some mention of modifying the delegate of the QListWidget, but the descriptions have been vague. I'm also not sure if this would solve my animation problem.

Any ideas?

2
There is something close to what you want in the QML examples (QtSDK/Examples/4.7/declarative/modelviews/listview/highlightranges/qml/highlightranges.qml, that you run with qmlviewer). Basically it's a list with a animated transparent selection indicator which moves smoothly.alexisdm

2 Answers

4
votes

You can place a semi transparent inert widget on top of the QListWidget, and animate it when the selection changes. But you also need a delegate to disable the normal selection indicator.

A working example:

#include <QListWidget>
#include <QFrame>
#include <QPropertyAnimation>
#include <QStyledItemDelegate>

class RemoveSelectionDelegate : public QStyledItemDelegate {
public:
    RemoveSelectionDelegate(QObject *parent = 0)
        : QStyledItemDelegate(parent) {
    }

    void paint(QPainter *painter, const QStyleOptionViewItem &option,
               const QModelIndex &index) const {
        // Call the original paint method with the selection state cleared
        // to prevent painting the original selection background
        QStyleOptionViewItemV4 optionV4 =
            *qstyleoption_cast<const QStyleOptionViewItemV4 *>(&option);
        optionV4.state &= ~QStyle::State_Selected;
        QStyledItemDelegate::paint(painter, optionV4, index);
    }
};

class ListWidget : public QListWidget {
    Q_OBJECT
public:
    ListWidget(QWidget *parent = 0)
        : QListWidget(parent)
        , selectionFrame(this)
        , animation(&selectionFrame, "geometry") {
        // Create a semi-transparent frame that doesn't interact with anything
        selectionFrame.setAttribute(Qt::WA_TransparentForMouseEvents);
        selectionFrame.setFocusPolicy(Qt::NoFocus);

        // You can put your transparent image in that stylesheet
        selectionFrame.setStyleSheet("background: solid rgba(0, 0, 125, 25%);");
        selectionFrame.hide();
        animation.setDuration(250);
        animation.setEasingCurve(QEasingCurve::InOutBack);

        connect(this,
                SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
                SLOT(updateSelection(QListWidgetItem*)) );        
        setItemDelegate(new RemoveSelectionDelegate(this));
    }

private slots:
    void resizeEvent(QResizeEvent *e) {
        QListWidget::resizeEvent(e);
        updateSelection(currentItem());
    }

    void updateSelection(QListWidgetItem* current) {
        animation.stop();
        if (!current) {
            selectionFrame.hide();
            return;
        }
        if (!selectionFrame.isVisible()) {
            selectionFrame.setGeometry(visualItemRect(current));
            selectionFrame.show();
            return;
        }
        animation.setStartValue(selectionFrame.geometry());
        animation.setEndValue(visualItemRect(current));
        animation.start();
    }
private:
    QFrame selectionFrame;
    QPropertyAnimation animation;
};
1
votes

So if its just text then why not have a QDockwidget with QLabels.

For example, take a look at the 'Qt Designer's 'Widget Box' on the left, you can drag that and place it on the top. Is that what you are looking for?

You can move the dockwidget as you want.