Search code examples
c++qtqwidgetqgraphicsview

Disable auto-selecting items in QListWidget on click+drag


I've spent better half of today trying to resolve seemingly trivial QListWidget behavior customization: when used presses mouse left button and moves mouse cursor, the content of ListWidget is scrolled and selection is moved to another item that happens to appear under mouse cursor. I am alright with scrolling, but I want to avoid selecting all consequtive items because this causes timely operation in my program. Finally I would like to keep list content scrolling on mouse press and move, but select items only by clicking directly on them. Drag-n-drop is disabled for this list (which is default behavior) and it should be; I've tried to disable it explicitly: no changes whatsoever.

I have read all available docs on Qt related classes like QListWidget, QListWidgetItem, QListView, you name it! Tried to make sense of source code for these widgets; dug up StackOverflow and Google... but sadly no result :(

Here is all relevant code for my QListWidget: single selection, nothing fancy:

QListWidget* categoryListWidget;
...
categoryListWidget = new QListWidget();
categoryListWidget->move(offsetX, offsetY);
categoryListWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
categoryListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
categoryListWidget->setFocusPolicy(Qt::NoFocus);
categoryListWidget->setStyleSheet(listQSS);
...
categoryListWidget->clear();
new QListWidgetItem(tr("1 - Sample Category 1"), categoryListWidget);
new QListWidgetItem(tr("2 - Sample Category 2"), categoryListWidget);
new QListWidgetItem(tr("3 - Sample Category 3 with a very long name"), categoryListWidget);
new QListWidgetItem(tr("4 - Sample Category 4"), categoryListWidget);

C++/Qt 5.5 if that's somehow relevant, both Win and Mac platforms share similar behavior.


Solution

  • For the sake of whoever stumbles upon the same question, here is my solution: subclass QListWidget and make child class ignore mouseMove events when leftButton is pressed.

    Header:

    class QtListWidget: public QListWidget
    { // QListWidget clone that suppresses item selection on mouse click+drag
    private:
        bool    mousePressed;
    public:
         QtListWidget():QListWidget(), mousePressed(false) {}
    protected:
        virtual void mousePressEvent(QMouseEvent *event);
        virtual void mouseMoveEvent(QMouseEvent *event);
        virtual void mouseReleaseEvent(QMouseEvent *event);
    };
    

    Source:

    //////////////////////////////////////////////////////////////////////////
    void QtListWidget::mousePressEvent(QMouseEvent *event){
    //    qDebug() << "QtListWidget::mousePressEvent";
        if(event->button() == Qt::LeftButton)
            mousePressed = true;
        QListWidget::mousePressEvent(event);
    }
    
    void QtListWidget::mouseMoveEvent(QMouseEvent *event){
    //    qDebug() << "QtListWidget::mouseMoveEvent";
        if(!mousePressed)   // disable click+drag
            QListWidget::mouseMoveEvent(event);
    }
    
    void QtListWidget::mouseReleaseEvent(QMouseEvent *event){
    //    qDebug() << "QtListWidget::mouseReleaseEvent";
        if(event->button() == Qt::LeftButton)
            mousePressed = false;
        QListWidget::mouseReleaseEvent(event);
    }
    //////////////////////////////////////////////////////////////////////////
    

    Usage is trivial, for as many List Widgets as you need:

    QtListWidget* categoryListWidget;
    // all original code above would still work as expected
    ...
    

    Want it done right? then do it yourself! :)