[SOLVED] Handle mouse double clicked and mouse single click event



  • Hello,

    I would like to handle in a list view mouse single click and mouse double click events. So I reimplemented two slots connected to the corresponding signals of the QListView. However, when a I perform a double click, the single click is called. I also tried to reimplement the corresponding protected methods (to mousePress and mouseDoubleClick events) in subclasses of QListView, but the same issue occurs.

    Do you have some idea to avoid this behavior ?

    Thanks a lot !


  • Lifetime Qt Champion

    Hi,

    Can you share your code ?



  • Here is an extracted version of the code, showing the issue I'm encountering.

    I'm compiling in C++11.

    File main.cpp

    #include <QApplication>
    
    #include <QDebug>
    #include <QFileSystemModel>
    
    #include "ListView.hpp"
    
    void viewClicked(const QModelIndex& idx)
    {
        qDebug() << QObject::trUtf8("Item %1 has been clicked.").arg(idx.data().toString());
    }
    
    void viewDoubleClicked(const QModelIndex& idx)
    {
        qDebug() << QObject::trUtf8("Item %1 has been double clicked.").arg(idx.data().toString());
    }
    
    int testWithNoSubclass(int argc, char** argv)
    {
        QApplication app(argc, argv);
    
        QFileSystemModel fileModel;
    
        QListView view;
        view.setWindowTitle(QObject::trUtf8("Test with standard view"));
        view.setEditTriggers(QAbstractItemView::NoEditTriggers);
        view.setModel(&fileModel);
        view.setRootIndex(fileModel.setRootPath(QDir::homePath()));
        view.show();
    
        QObject::connect(&view, &QListView::clicked, &viewClicked);
        QObject::connect(&view, &QListView::doubleClicked, &viewDoubleClicked);
    
        return app.exec();
    }
    
    int testWithSubclass(int argc, char** argv)
    {
        QApplication app(argc, argv);
    
        QFileSystemModel fileModel;
    
        ListView view;
        view.setWindowTitle(QObject::trUtf8("Test with subclassed view"));
        view.setEditTriggers(QAbstractItemView::NoEditTriggers);
        view.setModel(&fileModel);
        view.setRootIndex(fileModel.setRootPath(QDir::homePath()));
        view.show();
    
        return app.exec();
    }
    
    int main(int argc, char** argv)
    {
       testWithNoSubclass(argc, argv);
       testWithSubclass(argc, argv);
    }
    

    FIle ListView.hpp

    #ifndef LISTVIEW_HPP
    #define LISTVIEW_HPP
    
    #include <QDebug>
    
    #include <QAbstractItemModel>
    #include <QListView>
    #include <QMouseEvent>
    
    class ListView : public QListView
    {
        Q_OBJECT
    
    public:
        ListView(QWidget* parent = nullptr) : QListView(parent) {}
    
    protected:
        void mousePressEvent(QMouseEvent* e)
        {
            if ( e == nullptr )
                return;
    
            QModelIndex idx = QListView::indexAt(e->pos());
    
            if ( not idx.isValid() )
                return;
    
            qDebug() << QObject::trUtf8("Item %1 has been clicked.").arg(idx.data().toString());
        }
    
        void mouseDoubleClickEvent(QMouseEvent* e)
        {
            if ( e == nullptr )
                return;
    
            QModelIndex idx = QListView::indexAt(e->pos());
    
            if ( not idx.isValid() )
                return;
    
            qDebug() << QObject::trUtf8("Item %1 has been double clicked.").arg(idx.data().toString());
        }
    };
    
    #endif // LISTVIEW_HPP
    
    

    I put the code in the header just in order to avoid copying too many files here.

    Thank you a lot !


  • Lifetime Qt Champion

    Since you have re-implemented mousePressEvent and mouseDoubleClickEvent and you don't call the base class implementation, you are breaking the base functionality



  • So, according to you, I should call QListView::mousePressEvent and QListView::mouseDoubleClickEvent in the subclassed class ? In that case, I should call it at the end of the method, should I ?

    I was insipired by the Scribber example, where some protected methods are reimplemented, but base class is not called in this example.

    I try to modify the code today, and see how it will react to single and double click events.


  • Lifetime Qt Champion

    It really depends on what you do in your subclass.

    You can ignore the base class implementation, but in the case of e.g. QAbstractItemView derived classes, the function your reimplemented handles the drag and drop part. So if you want it to work, then you need to call the base class implementation or rewrite the code (you don't want to do that)



  • The aim is to distinguish the single click from the double click. I would like to handle those two types of events independently.

    My first message was not clear about how I did it in a first time, i.e. by connecting the signals clicked(QModelIndex) and doubleClicked(QModelIndex) of a QListView to appropriate slots. However, even in this case, the first slot is called on a double click event.

    Sorry for my poor English, that is not at all my native language.


  • Lifetime Qt Champion

    Do you mean you had that problem with unmodified methods ?



  • When I connected the clicked(QModelIndex) and doubleClicked(QModelIndex) signals of QListView to the following slots :

    @mistralegna said:

    void viewClicked(const QModelIndex& idx)
    {
    qDebug() << QObject::trUtf8("Item %1 has been clicked.").arg(idx.data().toString());
    }

    void viewDoubleClicked(const QModelIndex& idx)
    {
    qDebug() << QObject::trUtf8("Item %1 has been double clicked.").arg(idx.data().toString());
    }

    the double click on an item is first calling the first slot.

    I would like to call only the second slot in case of an item's double click and only the first slot in the case of a single click.


  • Lifetime Qt Champion

    Does it also happen if you don't modify mousePressEvent ?



  • Do you mean you had that problem with unmodified methods ?

    I believe widget will always receive both single click and double click event.
    When I needed I have not found reliable way to skip single click event.

    As far as I can recall the working solution was to start a timer on a single click which in case doubleclick event arrived was destroyed.
    But most of the time it is better just to change functionality which allows both single click and double click actions to coexist.



  • @SGaist My first post showed two different implementations to handle click events. The first is just to connect the signals QAbstractItemView::clicked(const QModelIndex&) and QAbstractItemView::doubleClicked(const QModelIndex&) to respective slots.

    #include <QApplication>
    
    #include <QDebug>
    #include <QFileSystemModel>
    #include <QListView>
    
    void viewClicked(const QModelIndex& idx)
    {
        qDebug() << QObject::trUtf8("Item %1 has been clicked.").arg(idx.data().toString());
    }
    
    void viewDoubleClicked(const QModelIndex& idx)
    {
        qDebug() << QObject::trUtf8("Item %1 has been double clicked.").arg(idx.data().toString());
    }
    
    int main(int argc, char** argv)
    {
        QApplication app(argc, argv);
    
        QFileSystemModel fileModel;
    
        QListView view;
        view.setWindowTitle(QObject::trUtf8("Test with standard view"));
        view.setEditTriggers(QAbstractItemView::NoEditTriggers);
        view.setModel(&fileModel);
        view.setRootIndex(fileModel.setRootPath(QDir::homePath()));
        view.show();
    
        QObject::connect(&view, &QListView::clicked, &viewClicked);
        QObject::connect(&view, &QListView::doubleClicked, &viewDoubleClicked);
    
        return app.exec();
    }
    

    Here, there is no reimplementation at all. I'm just using base functionnalities (at least, I think I am). Unfortunately, when I double click on an item, here is the output:

    "Item data has been clicked."  // Seems to be the first click handled.
    "Item data has been double clicked."  // Double click event.
    "Item data has been clicked." // Seems to be the second click of the double click.
    

    This is quite relevant, because the view seems to have handled two single clicks and the double click. But that's not corresponding to what I'd like to have. I thought the view would have blocked the single click event when reacting to a double click.

    @alex_malyu So, according to you, does it mean that without a timer, we cannot distinguish between a single click and a double click? I'd prefer to make the distinction between those two events without any timer, if possible.

    Thank you a lot!



  • If nothing changed since Qt 4 single click event on the platforms I was working on always arrives before double click event.
    Lets look at scenario:

    1. single click occurs:

    Single click event arrives.
    If you want to do something on a single click that is only event you will get,
    So you have to react on it.

    1. double click occurs:
    • First single click event arrives.
    • second double click event arrives

    You want to ignore single click , but react on second event.

    Question: How do you know that it was double click and will not react on a single click?

    I might be missing the obvious , but the only way I found to achieve this was to start the timer when single click arrived at event handler.
    This timer was stopped at double click event handler.
    If it was not stopped slot with reaction needed on a single click was executed.

    As I said solution was not perfect and it was done for Qt 4.
    But I did not see anything better except implementing behavior when reaction on single click does not have to be avoided on double click.



  • @alex_malyu Thank you ;-)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.