2015-03-27 1 views
1

Dans Qt avec C++, j'ai créé une fenêtre avec un petit QWidget à l'intérieur.QWidget ne déclenche pas QEvent :: MouseMove lorsqu'il est entré avec le bouton Pressé

Le petit QWidget affiche un message chaque fois que QEvent::Enter, QEvent::Leave ou QEvent::MouseMove est déclenché. Quand un bouton de la souris est enfoncé (et maintenu) en dehors du petit QWidget, et que la souris est déplacée sur le dessus de ce petit QWidget (tout en maintenant), QEvent::MouseMove n'est pas déclenché pour ce petit QWidget. De plus, QEvent::Enter est remis à après que le bouton de la souris est relâché.

Dans la situation inverse: lorsque la souris est pressée sur le petit QWidget (et maintenu), puis que la souris est déplacée à l'extérieur, le QEvent::Leave est remis à après que le bouton de la souris est relâché.

Y at-il une solution pour récupérer QEvent::MouseMove tout le temps, même lorsque le bouton de la souris est maintenu enfoncé?

Données supplémentaires: Oui, setMouseTracking(true) est défini.

exemple d'essai:

Widget:

#ifndef MYWIDGET_HPP 
#define MYWIDGET_HPP 

#include <QWidget> 
#include <QStyleOption> 
#include <QPainter> 
#include <QEvent> 
#include <QDebug> 

class MyWidget: public QWidget 
{ 
    Q_OBJECT 
public: 
    MyWidget(QWidget* parent=nullptr): QWidget(parent) 
    { 
     setMouseTracking(true); 
    } 
protected: 

    // Paint for styling 
    void paintEvent(QPaintEvent *) 
    { 
     // Needed to allow stylesheet. 
     QStyleOption opt; 
     opt.init(this); 
     QPainter p(this); 
     style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); 
    } 

    // Show Enter and Leave event for debugging purpose 
    bool event(QEvent *e) 
    { 
     static int counting=0; 
     if (e->type() ==QEvent::Enter) 
     { 
      qDebug() << counting++ << " Enter: " << this->objectName(); 
     } 
     if (e->type() ==QEvent::Leave) 
     { 
      qDebug() << counting++ << " Leave: " << this->objectName(); 
     } 

     if (e->type() ==QEvent::MouseMove) 
     { 
      qDebug() << counting++ << " Move: " << this->objectName(); 
     } 
     return QWidget::event(e); 
    } 

}; 

#endif // MYWIDGET_HPP 

principal

#include <QApplication> 

#include <QDebug> 
#include <QWidget> 
#include <QTimer> 

#include "Testing.hpp" 


int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 

    // Create a main window 
    QWidget main; 
    main.setWindowTitle("Cursor blocked for 5s - wait and see"); 
    main.resize(500, 200); 
    main.move(200, 200); 

    // Create a MyWidget 
    MyWidget sub(&main); 
    sub.setObjectName("sub"); 
    sub.resize(50, 50); 
    sub.move(50, 50); 

    // Style the button with a hover 
    main.setStyleSheet 
    (
     "QWidget#sub{background-color: rgba(0,0,128,0.5);}" 
     "QWidget#sub:hover{background-color: rgba(128,0,0,0.5);}" 
    ); 

    // Show the window 
    main.show(); 

    return a.exec(); 

} 

Projet

QT  += core gui 

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 

SOURCES +=\ 
    main.cpp 

HEADERS +=\ 
    Testing.hpp 

RESOURCES +=\ 

CONFIG += c++11 -Wall 

TARGET = Testing 
TEMPLATE = app 

Répondre

0

Ce comportement est standard. Lorsque vous appuyez sur le bouton de la souris, le widget commence à l'attraper (appelez QWidget::grabMouse). Je pense que vous devriez revoir votre comportement, ou expliquer certains cas d'utilisation réels, lorsque vous avez besoin de suivre la souris globalement.

Si vous avez vraiment besoin de suivre la souris, vous pouvez utiliser des filtres d'événements.

pseudo-code (sans vérification):

QWidget *otherWidget = /*...*/; 
QWidget *myWidget = /*...*/; 
otherWidget->installEventFilter(myWidget); 
// you need to install filter on each widget, 
// that you want to track. 
// Care with performance 

MyWidget : QWidget 
{ 
    void handleMouseMove(QPoint pos) { /*...you code...*/ } 

    void mouseMove(QMouseEvent *e) override; 
    { 
    handleMouseMove(e->pos()); 
    QWidget::mouseMove(e); 
    } 

    bool eventFilter(QObject *obj, QEvent *e) 
    { 
    auto srcWidget = qobject_cast< QWidget * >(obj); 
    switch (e->type()) 
    { 
    case QEvent::MouseMove: 
     { 
     auto me = static_cast< QMouseEvent * >(e); 
     auto globalPos = srcWidget->mapToGlobal(me->pos()); 
     auto localPos = this->mapFromGlobal(globalPos); // Possible, you need to invalidate that poing belongs to widget 
     handleMouseMove(localPos); 
     } 
     break; 
    }; 
    return QWidget::eventFilter(obj, e); 
    } 
}; 
+0

L'utilisation est à des fins de style: vol stationnaire et le style pressé ne fonctionne pas correctement dans certaines situations (par exemple, je voudrais le style de vol stationnaire/emboutie être annulée lorsque la souris s'éteint et le hover est activé lorsque la souris entre, même si la souris est pressée). Pour corriger ces événements manquants d'entrée/sortie, j'ai besoin de MouseMove, mais cela ne fonctionne pas correctement. Le problème est que le QEvent n'est pas transmis au widget, donc les filtres ne le résolvent pas. Je pourrais mettre en œuvre mon propre système d'événements en parallèle, mais cela prend du temps. –

+0

Si vous voulez un comportement, cela est différent de la valeur par défaut dans Qt et OS - vous devriez le faire manuellement. C'est OK, ce survol n'est pas survenu lorsque la souris est pressée sur un autre widget. –

+0

Ce qui ne va pas, c'est que mouseMove ne se déclenche pas lorsque vous vous déplacez sur le widget, juste parce que le bouton a été enfoncé auparavant. –