mouse press & release & double click events
От: nen777w  
Дата: 31.01.17 18:58
Оценка: 2 (1) +1
Столкнулся с такой проблемой.
Есть у меня самодельный контрол у которого перегружены события mousePressEvent(), mouseReleaseEvent(), mouseMoveEvent()
Поведение такое: пользователь нажимает и начинает тащить пин мышкой, затем отпускает, при этом если нажимает не по пину (mousePressEvent()), то пин сам подскакивает под мышку.
Понадобилось мне недавно добавить еще mouseDoubleClickEvent() что бы даблкликнув по контролу пользователь мог ввести значение пина.
Но тут случилась такая засада... doubleClick то приходит... но перед ним приходят и mousePressEvent() и mouseReleaseEvent(), что не годится совсем.
Есть ли нормальный способ избежать этого?
Re: mouse press & release & double click events
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 31.01.17 19:07
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Понадобилось мне недавно добавить еще mouseDoubleClickEvent() что бы даблкликнув по контролу пользователь мог ввести значение пина.

N>Но тут случилась такая засада... doubleClick то приходит... но перед ним приходят и mousePressEvent() и mouseReleaseEvent(), что не годится совсем.

В винде такое поведение в системе стандартно. как в других системах, думаю тоже.


N>Есть ли нормальный способ избежать этого?


Избежать — только логикой в своем приложении

А что не устраивает?

У дабл-клика есть размер области, в которую он должен попадать, вроде можно вытащить из настроек системы. Как и пауза между кликами. Добавь к себе логику, что если перемещение не больше чем эта область, и интервал между пресс и релиз не превышает интервала дабл клика, то перемещения нет
Маньяк Робокряк колесит по городу
Re: mouse press & release & double click events
От: AlexGin Беларусь  
Дата: 31.01.17 19:14
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Столкнулся с такой проблемой.

N>Есть у меня самодельный контрол у которого перегружены события mousePressEvent(), mouseReleaseEvent(), mouseMoveEvent()
N>Поведение такое: пользователь нажимает и начинает тащить пин мышкой, затем отпускает, при этом если нажимает не по пину (mousePressEvent()), то пин сам подскакивает под мышку.
N>Понадобилось мне недавно добавить еще mouseDoubleClickEvent() что бы даблкликнув по контролу пользователь мог ввести значение пина.
N>Но тут случилась такая засада... doubleClick то приходит... но перед ним приходят и mousePressEvent() и mouseReleaseEvent(), что не годится совсем.
N>Есть ли нормальный способ избежать этого?
???
Что значит нормальный?
Переделать логику обработки событий мыши.
Ввести булевские флаги, отслеживающие работу с мышкой. Да, это усложнит логику, но решит данную проблему.

Какие ещё возможны варианты — например, сделать "ввести значение пина" через клик правой кнопки мышки, или через контекстное меню?
Re: mouse press & release & double click events
От: SaZ  
Дата: 31.01.17 22:31
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Столкнулся с такой проблемой.

N>Есть у меня самодельный контрол у которого перегружены события mousePressEvent(), mouseReleaseEvent(), mouseMoveEvent()
N>Поведение такое: пользователь нажимает и начинает тащить пин мышкой, затем отпускает, при этом если нажимает не по пину (mousePressEvent()), то пин сам подскакивает под мышку.
N>Понадобилось мне недавно добавить еще mouseDoubleClickEvent() что бы даблкликнув по контролу пользователь мог ввести значение пина.
N>Но тут случилась такая засада... doubleClick то приходит... но перед ним приходят и mousePressEvent() и mouseReleaseEvent(), что не годится совсем.
N>Есть ли нормальный способ избежать этого?

У QApplication есть проперти doubleClickInterval, startDragDistance, startDragTime. По-хорошему их нужно учитывать при реализации своего поведения. Тогда, по идее, ваша проблема разрулится сама собой. Остальное выше написали — надо отслеживать даблклик руками.
Резюмирую: если юзер не протащил мышь достаточное расстояение (startDragDistance), то не считать это операцией перетягивания.

А такое поведение вполне логично. Ибо, если юзер кликнет и не успеет кликнуть второй раз, то когда присылать press/release для первого клика?
Отредактировано 31.01.2017 22:33 SaZ . Предыдущая версия .
Re: mouse press & release & double click events
От: nen777w  
Дата: 01.02.17 09:04
Оценка:
N>Есть ли нормальный способ избежать этого?

Пытался сделать на таймере, (хотя это фигня полная)
Вот что я вижу в обработчиках событий. И наверно я чего то недопонимаю.

Код примерно такой:

CTOR()
{
    m_dblclick_timer.setInterval(QApplication::doubleClickInterval() + 200);
    m_dblclick_timer.setSingleShot(true);

    connect(&d->m_dblclick_timer, SIGNAL(timeout()), this, SLOT(dblclick_timeout()));
}

mousePressEvent()
{
   qDebug() << "mousePressEvent";

   if(!d->m_dblclick_timer.isActive()) {
       d->m_dblclick_timer.start();
   }

   QWidget::mousePressEvent(event);
}

mouseReleaseEvent()
{
   qDebug() << "mouseReleaseEvent";

   QWidget::mouseReleaseEvent(event);
}

mouseDoubleClickEvent()
{
  qDebug() << "mouseDoubleClickEvent";

  d->m_dblclick_timer.stop();

   QWidget::mouseDoubleClickEvent(event);
}

dblclick_timeout()
{
   qDebug() << "dblclick_timeout";
}


Результат когда делаю doubleClick:

mousePressEvent
mouseReleaseEvent
mouseDoubleClickEvent <--почему он тут а не после следующих двух?
mousePressEvent
mouseReleaseEvent
dblclick_timeout <--почему сработал timout() у него запас 200ms еще и ему сделали stop(), разве он должен сработать? Делал ради хохмы 1000ms та же катина!!!

Ладно с этим порядком событий, видимо какая то особенность реализации (надо код смотреть). Но блин почему таймер срабатывает???

Видимо прийдется выкинуть идею про mouseDoubleClickEvent() и делать что то свое основываясь на manhatanDistance().
Отредактировано 01.02.2017 9:07 nen777w . Предыдущая версия . Еще …
Отредактировано 01.02.2017 9:06 nen777w . Предыдущая версия .
Re[2]: mouse press & release & double click events
От: SaZ  
Дата: 01.02.17 09:57
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Код примерно такой:

N>...
N>Результат когда делаю doubleClick:

N>mousePressEvent

N>mouseReleaseEvent
N>mouseDoubleClickEvent <--почему он тут а не после следующих двух?

Потому что тут произошёл дабл клик. Не могу объяснить, почему именно так, но интуитивно я бы тоже событие дабл клика слал перед событием второго клика. И в винде, вроде так же сообщения идут.

N>mousePressEvent

N>mouseReleaseEvent
N>dblclick_timeout <--почему сработал timout() у него запас 200ms еще и ему сделали stop(), разве он должен сработать? Делал ради хохмы 1000ms та же катина!!!

А вот тут сложно сказать, можете сделать SSCCE? Потому что это выглядит как совсем уж кривой баг таймера. Мне всё-таки кажется, что у вас где-то в коде ошибка. Попробуйте с точностью до ms вывести время, когда вы вызываете start/stop и когда срабатывает слот таймера. Может эвент уже попадает в очередь до того, как вы стоп сделаете? Или isActive не работает в режиме singleShot.

N>Видимо прийдется выкинуть идею про mouseDoubleClickEvent() и делать что то свое основываясь на manhatanDistance().


В вашем случае — да, потому что вам нужно и одиночные клики обрабатывать.

N>Пытался сделать на таймере, (хотя это фигня полная)

N>Вот что я вижу в обработчиках событий. И наверно я чего то недопонимаю.

Я бы вместо таймеров использовал timestamp (запоминал время последнего клика через какой-нибудь QElapsedTimer) и сравнивал временной интервал между кликами в обработчике mousePress. Просто у вас таймеры выглядят как сильный оверхед.
Отредактировано 01.02.2017 9:58 SaZ . Предыдущая версия .
Re[2]: mouse press & release & double click events
От: AlexGin Беларусь  
Дата: 02.02.17 10:22
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Результат когда делаю doubleClick:


N>mousePressEvent

N>mouseReleaseEvent
N>mouseDoubleClickEvent <--почему он тут а не после следующих двух?
Вот здесь (в теле метода-обработчика mouseDoubleClickEvent) я бы и установил флажок типа:
   bool bIsDoubleClick = true;

Этот флажок — мембер твоего окна (виджета), где обрабатываются события от мышки.

N>mousePressEvent

N>mouseReleaseEvent
В обработчике события mouseReleaseEvent (в конце) — я сбросил бы упомянутый выше флажок.

N>dblclick_timeout <--почему сработал timout() у него запас 200ms еще и ему сделали stop(), разве он должен сработать? Делал ради хохмы 1000ms та же катина!!!

В практической реализации — можно обойтись даже и без таймера.

N>Ладно с этим порядком событий, видимо какая то особенность реализации (надо код смотреть). Но блин почему таймер срабатывает???

Вообще — убрать этот таймер (здесь он не нужен).

N>Видимо прийдется выкинуть идею про mouseDoubleClickEvent() и делать что то свое основываясь на manhatanDistance().

Не обязательно — сделать в обработчике mousePressEvent:
    if (bIsDoubleClick)
    {
        // Здесь делаем всё, что требуется для двойного клика...
    }
Отредактировано 02.02.2017 10:25 AlexGin . Предыдущая версия . Еще …
Отредактировано 02.02.2017 10:24 AlexGin . Предыдущая версия .
Re: mouse press & release & double click events
От: XOOIOOX  
Дата: 02.02.17 16:39
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Есть у меня самодельный контрол у которого перегружены события mousePressEvent(), mouseReleaseEvent(), mouseMoveEvent()


Может проще было ивент-фильтр на контрол повесить и логику работы в одном месте в нем же прописать?

N>но перед ним приходят и mousePressEvent() и mouseReleaseEvent(), что не годится совсем.


Думаю, что даблклик включает в себя пресс-ивент в этом случае. Все же, это довольно низкий уровень обработки событий.


У меня в самодельных контролах сделано примерно так (очень упрощенно):

bool MegaSuperControl::eventFilter(QObject *obj, QEvent *evt)
{
    if (obj == this)
    {
        QMouseEvent *me = static_cast<QMouseEvent *>(evt);
        QWheelEvent *we = static_cast<QWheelEvent *>(evt);

        switch (evt->type())
        {
            case QEvent::MouseButtonPress:                    // обычный клик бутоном
            {
                // то-се
                return true;
                break;
            }

            case QEvent::MouseButtonDblClick:                // даблклик бутоном
            {
                // пятое-десятое
                return true;
                break;
            }

            case QEvent::Wheel:                                // колесо
            {
                // тыр-пыр
                return true;
                break;
            }

            case QEvent::MouseMove & QEvent::HoverEnter:        // мышь двигается и она на нашем контроле
            {
                // восемь дыр
                return true;
                break;
            }

            case QEvent::Paint:                                // рисовалка
            {
                // рисуем наш контрол
                return true;
                break;
            }

            case QEvent::MouseButtonRelease:                    // отпустили кнопку мыши
            {
                // обрабатываем как следует
                return true;
                break;
            }

            default:
            {
                // не наш ивент
                return false;
                break;
            }
        }
    }
    else
    {
        // ваще не наш ивент
        return false;
    }
}


И не нужно запариваться с какими-то безумными таймерами. Ну их нафиг.

ЗЫ. Да, и нужно не забыть метод ивент-фильтра в классе контрола ставить в паблик, а не в протектед, как в доке Qt предлагается, иначе утечка памяти после деструкции класса. Недавно столкнулся с этим. Особенно заметно, если прога какой-нибудь плагин к чему-то и в контроле массивы на куче создаются.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.