Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. EnterEvents not sent to QLabel, why?
Forum Updated to NodeBB v4.3 + New Features

EnterEvents not sent to QLabel, why?

Scheduled Pinned Locked Moved Unsolved General and Desktop
event handlinggamelabel
3 Posts 2 Posters 1.6k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    HangMan
    wrote on last edited by HangMan
    #1

    Hi to everyone;
    the code I posted below is a simplification taken from a solitaire game project;
    You can try it, copy and paste it in Qt editor;


    I'll describe briefly the situation along with the issue:
    You can see three labels: Label1, Label2, Label3 (I'll call them L1, L2, L3); each object (class label ) inherits from QLabel and reimplements some protected methods (QMouseEvent handlers) which enable drag & drop actions; both L1 and L2 can be dragged but they don't accept drop actions; L3, on the contrary, can't be dragged, yet it accepts drops; dropping label X on label Y will cause X to move on top of Y if Y accepts drops (otherwise X will return back to its starting position);
    An enter event is sent to the label when the mouse cursor enters it, while a leave event is sent to the label when the mouse cursor leaves it.
    Notice that when it's ok to drag, the cursor changes shape to Qt::OpenHandCursor (the standard cursor is Qt::ArrowCursor, set after mouseReleaseEvents and LeaveEvents);
    And here's the problem: drag L1 on top of L2 (clearly L1 will move back to its original position) and release without moving the cursor; now the cursor is over L2, but we entered L2 for the first time, hence Qt is supposed to deliver an enterEvent to L2 and a leaveEvent to L1; however, this won't happen (unless you move the mouse), so the cursor remains Qt::ArrowCursor; all the same we are able to drag L2; Why didn't Qt send an enter event to L2, having the cursor left L1 and entered L2? How can I fix this?
    A similar problem arises after dropping L1 (or L2) on top of L3. Now the cursor is over L1, but we already entered it, so Qt won't deliver an enter event, hence the cursor remains Qt::ArrowCursor. I want the cursor to change shape to Qt::OpenHandCursor, since we can actually drag L1;


    Here's what I tried: you can send an enterEvent using QApplication::sendEvent(...); so it suffices to check which label is under cursor (I wrote the code for labelAtPos() since QApplication::widgetAt() returns the top level widget, that is the label currently dragged, while I need the one beneath it) and send it an enter event. But this is bad because after you move the mouse Qt will automatically send both the enterEvent and the leaveEvent, thus you end up calling enterEvent() two times (I can't understand why Qt doesn't send them instantly instead of waiting until the mouse is moved).
    Now you could suggest: try to fake mouse movements using cursor().setPos(...). That seems not to work always (I don't know why but I debugged it a lot and finally discovered it).


    Guys I beg your help; Do you suggest better ways to do this? Thanks in advance. I'm using Qt 5.6.1; OS: Ubuntu 16.04 LTS


    here's my code:

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    class MainWindow : public QMainWindow
    {`
      Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = 0);
        ~MainWindow();
    };
    #endif // MAINWINDOW_H
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "label.h"
    
    #include <QApplication>
    #include <QDesktopWidget>
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
    {
        resize(300, 350);
        move(QApplication::desktop()->screen()->rect().center() - rect().center());
    }
    

    label.h

    #ifndef LABEL_H
    #define LABEL_H
    
    #include <QLabel>
    #include <QEvent>
    #include <QMouseEvent>
    
    class label : public QLabel
    {
        Q_OBJECT
    public:
        explicit label(QString name, QString color, QPoint pos, bool canDrag, bool canDrop, QWidget *parent = 0);
        bool isDraggable() const;
        bool isOkToDrop() const;
        static label * labelAtPos(QPoint p, QWidget * parent, const label * w);
    
    private:
        QString name;
        QString color;
        QPoint startDrag;
        QPoint originalPosition;
        bool canDrag;
        bool canDrop;
    
    protected:
        void mousePressEvent(QMouseEvent*);
        void mouseMoveEvent(QMouseEvent*);
        void mouseReleaseEvent(QMouseEvent *);
        void enterEvent(QEvent*);
        void leaveEvent(QEvent*);
    
    };
    
    #endif // LABEL_H
    

    label.cpp

    #include "label.h"
    #include <QApplication>
    
    bool dragging = false;
    
    label::label(QString n, QString c, QPoint p, bool drag, bool drop, QWidget *parent) : QLabel(parent)
    {
        name = n;
        color = c;
        resize(80, 100);
        setAlignment(Qt::AlignCenter);
        setText(name);
        setStyleSheet(QString("background-color: %1").arg(c));
        originalPosition = p;
        canDrag = drag;
        canDrop = drop;
        move(p);
    }
    
    bool label::isDraggable() const
    {
        return canDrag;
    }
    
    bool label::isOkToDrop() const
    {
        return canDrop;
    }
    
    void label::mousePressEvent(QMouseEvent *event)
    {
        if(event->button() == Qt::LeftButton && isDraggable()){
            raise();
            startDrag = event->pos();
            setCursor(Qt::ClosedHandCursor);
            dragging = true;
        }
        QLabel::mousePressEvent(event);
    }
    
    void label::mouseMoveEvent(QMouseEvent *event)
    {
        if(dragging){
            QPoint p = mapToParent(event->pos());
            move(p - startDrag);
        }
        QLabel::mouseMoveEvent(event);
    }
    
    void label::mouseReleaseEvent(QMouseEvent *event)
    {
        if(event->button() == Qt::LeftButton && dragging){
            setCursor(Qt::ArrowCursor);
            QPoint p = mapToParent(event->pos());
            label * lab = labelAtPos(p, parentWidget(), this);
            if(lab && lab->isOkToDrop()){
                move(lab->pos());
            }
            else
                move(originalPosition);
            dragging = false;
        }
        QLabel::mouseReleaseEvent(event);
    }
    
    void label::enterEvent(QEvent *event)
    {
        if(isDraggable())
            setCursor(Qt::OpenHandCursor);
        QLabel::enterEvent(event);
    }
    
    void label::leaveEvent(QEvent *event)
    {
        setCursor(Qt::ArrowCursor);
        QLabel::leaveEvent(event);
    }
    
    label * label::labelAtPos(QPoint p, QWidget * parent, const label * w)
    {
        // it returns the first label under w, at point p, according to reverse parent's Z-order
        // if w is null, it returns the first label at point p according to reverse parent's Z-order
    
        label * result = 0;
        bool underw = (w == 0);
        if (parent) {
            for (int j = parent->children().count()-1; j >= 0; j--) {
                label * t = qobject_cast<label *>(parent->children().at(j));
                if(t == w) underw = true;
                if (t && t != w && underw) {
                    QPoint topleft = t->mapToParent(t->rect().topLeft());
                    QPoint bottomRight = t->mapToParent(t->rect().bottomRight());
                    QRect rect(topleft, bottomRight);
                    if(rect.contains(p)){
                        result = t;
                        break;
                    };
                };
            };
        };
        return result;
    }
    

    main.cpp

    #include "mainwindow.h"
    #include "label.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        label lab1("Label 1", "#ff9966", QPoint(20, 20), true, false, &w);
        label lab2("Label 2", "#ccccff", QPoint(150, 20), true, false, &w);
        label lab3("Label 3", "#00cc66", QPoint(20, 150), false, true, &w);
        QLabel lab4("Label1, Label2: can drag, can't drop\nLabel3: can't drag, can drop", &w);
        lab4.resize(250, 100);
        lab4.move(20, 250);
        w.show();
    
        return a.exec();
    }
    
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi and welcome to devnet,

      You should also add which version of Qt your are using as well as OS.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      H 1 Reply Last reply
      0
      • SGaistS SGaist

        Hi and welcome to devnet,

        You should also add which version of Qt your are using as well as OS.

        H Offline
        H Offline
        HangMan
        wrote on last edited by
        #3

        @SGaist I edited, thanks

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved