why QDrag->exec() is crashing on MAC but not on windows version?



  • I am using drag and drop event in Qt. On windows platform Qt with visual studio 2017. On Mac platform I am using Qt creator.

    on windows platform it is work perfectly. But on Mac it is crashing.

    I am creating the widget with help of CreateBuildExpElementWidget function, which is also install the event filter on that widget.

    QWidget* BuilderWidget::CreateBuildExpElementWidget(const BuilderContainer &bc, QUuid id) {
    	if (bc.type != BuilderContainer::ELEMENT) {
    		LOG() << "It is not an ELEMENT!";
    		return 0;
    	}
    
    	auto *w = OBJ_NAME(new QFrame(this), "node-builder-element");
    	
    
    	auto lay = NO_SPACING(NO_MARGIN(new QVBoxLayout(w)));
    
    	QSpinBox *mult;
    	QLabel *imageLbl;
    	QLabel *commentLbl;
    
    	lay->addWidget(imageLbl = OBJ_NAME(new QLabel, "node-builder-label"));
    	lay->addWidget(commentLbl = OBJ_NAME(new QLabel(bc.elem.name), "node-builder-label"));
    	lay->addWidget(mult = OBJ_NAME(new QSpinBox(), "node-builder-multiplier-single"));
    
    	commentLbl->setWordWrap(true);
    	commentLbl->hide();
    
    	QPixmap pixmap = bc.elem.ptr->GetImage();
    
    	auto imageLblSizeHint = imageLbl->sizeHint() * 0.95;
    
    	if( (pixmap.height() > imageLblSizeHint.height()) || (pixmap.width() > imageLblSizeHint.width()) ) {
    		pixmap = pixmap.scaled(imageLblSizeHint, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    	}
    
    	imageLbl->setPixmap(pixmap);
    	
    	mult->setMinimum(1);
    	mult->setMaximum(99999);
    	mult->setValue(bc.repeats);
    	mult->setSuffix("x");
    	mult->setToolTip("Number of the element repeats");
    
    	w->setAttribute(Qt::WA_Hover, true);
    	w->installEventFilter(new ElementEventFilter(w, this, imageLbl, commentLbl));
    
    	auto disconnector = new Disconnector(mult);
    	
    	*disconnector <<
    	connect(mult, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), [=](int val) {
    		SetRepeats(id, val);
    	});
    
    	return w;
    }
    

    ElementEvents

    class ElementEventFilter : public QObject {
    public:
    	ElementEventFilter(QObject *parent, BuilderWidget *bw, QWidget *image, QWidget *comment) :
    		QObject(parent), _bw(bw), pressed(false), dragged(false), entered(false), _image(image), _comment(comment) {}
    
    	bool eventFilter(QObject *obj, QEvent *e) {
    		bool ret = false;
    		
    		switch (e->type()) {
    		case QEvent::MouseButtonPress:
    			if (!IsIgnoreArea(obj, e)) {
    				pressed = true;
    				dragged = false;
    				pressButton = ((QMouseEvent*)e)->button();
    				pressPoint = ((QMouseEvent*)e)->pos();
    
    				ret = true;
    			}
    
    			break;
    
    		case QEvent::MouseMove:
    			if (pressed && !dragged) {
    				QPoint pos = ((QMouseEvent*)e)->pos();
    				QLine moveVector(pressPoint, pos);
    				auto length = qSqrt(moveVector.dx() * moveVector.dx() + moveVector.dy() * moveVector.dy());
    				if (length > 3) {
    					dragged = true;
    					ret = ProcessDrag(obj, e);
    				}
    			}
    			break;
    
    		case QEvent::MouseButtonRelease:
    			if (pressed && !dragged) {
    				ret = ProcessSelection(obj, e);
    			}
    			pressed = false;
    			dragged = false;
    			break;
    
    		case QEvent::HoverEnter:
    			entered = true;
    			break;
    
    		case QEvent::HoverMove:
    			if (entered) {
    				if (IsIgnoreArea(obj, e)) {
    					_comment->hide();
    					_image->show();
    				}
    				else {
    					_image->hide();
    					_comment->show();
    				}
    				ret = true;
    			}
    			break;
    
    		case QEvent::HoverLeave:
    			entered = false;
    			_comment->hide();
    			_image->show();
    			break;
    		}
    
    		return ret;
    	}
    
    private:
    	bool IsIgnoreArea(QObject *obj, QEvent *e) {
    		auto w = qobject_cast<QWidget*>(obj);
    		if (!w) {
    			return true;
    		}
    
    		auto me = (QMouseEvent*)e;
    
    		auto marg = w->contentsMargins();
    		QPoint bottomRight = QPoint(w->width(), w->height());
    		bottomRight -= QPoint(marg.right() - 3, marg.bottom() - 3);
    
    		QPoint topLeft = QPoint(marg.left() - 3, marg.top() - 3);
    
    		if (!QRect(topLeft, bottomRight).contains(me->pos())) {
    			return true;
    		}
    
    		return false;
    	}
    	bool ProcessSelection(QObject *obj, QEvent *e) {
    
    		auto w = qobject_cast<QWidget*>(obj);
    		if (!w) {
    			return false;
    		}
    		
    		if (IsIgnoreArea(obj, e)) {
    			return false;
    		}
    		
    		emit _bw->ElementSelected(w);
    		return true;
    	}
    	bool ProcessDrag(QObject *obj, QEvent *e) {
    	
    		QWidget *w = qobject_cast<QWidget*>(obj);
    		if (!w) {
    			return false;
    		}
    		
    		QMouseEvent *me = (QMouseEvent*)e;
    
    		if (IsIgnoreArea(obj, e)) {
    			return false;
    		}
    		
    		if (pressButton == Qt::LeftButton) {
    			auto margins = w->contentsMargins();
    			auto rect = w->rect();
    
    			QPoint startPoint;
    			startPoint.setX(margins.left() - 1);
    			startPoint.setY(margins.top() - 1);
    			QPoint endPoint;
    			endPoint.setX(rect.width() - margins.right() + 1);
    			endPoint.setY(rect.height() - margins.bottom());
    
    			QUuid id = _bw->GetId(w);
    
    			auto mime = new QMimeData;
    			mime->setData(CONTAINER_MIME_TYPE, id.toByteArray());
    
    			auto pixmap = w->grab(QRect(startPoint, endPoint));
    			pixmap = pixmap.scaledToHeight((endPoint.y() - startPoint.y()) / 2, Qt::SmoothTransformation);
    
    			QDrag *drag = new QDrag(obj);
    			drag->setMimeData(mime);
    			drag->setPixmap(pixmap);
    			drag->setHotSpot((pressPoint - QPoint(margins.left(), margins.top())) / 2);
    			
    			Qt::DropAction dropAction = drag->exec(Qt::MoveAction, Qt::MoveAction);
    
    			return true;
    		}
    
    		return false;
    	}
    
    	QPoint pressPoint;
    	Qt::MouseButton pressButton;
    	bool pressed;
    	bool dragged;
    	bool entered;
    
    	QWidget *_image;
    	QWidget *_comment;
    
    	BuilderWidget *_bw;
    };
    

    call to CreateBuildExpElementWidget and put it in container.

    void BuilderWidget::InitWidgets() {
    	for (auto it = container.elements.begin(); it != container.elements.end(); ++it) {
    		switch (it->type) {
    			case BuilderContainer::ELEMENT:
    				if (!it->w) {
    					it->w = CreateBuildExpElementWidget(*it, it->id);
    					it->w->hide();
    				}
    				break;
    		}
    	}
    }
    

    handle the drop event and delete the original widget with help DeleteContainer function.

    void BuilderWidget::dropEvent(QDropEvent *e) {
    	if (e->mimeData()->hasFormat(CONTAINER_MIME_TYPE)) {
    		if (!background.currentArea) {
    			return;
    		}
    
    		auto area = background.currentArea;
    		auto byteArray = e->mimeData()->data(CONTAINER_MIME_TYPE);
    		auto id = QUuid(byteArray);
    		BuilderContainer toMove;
    		BuilderContainer *origin = 0;
    
    		for (auto it = container.elements.begin(); it != container.elements.end(); ++it) {
    			if (it->id == id) {
    				toMove = *it;
    				origin = &(*it);
    				break;
    			}
    		}
    		if (!origin) {
    			return;
    		}
    
    		
    		toMove.id = QUuid::createUuid();
    		toMove.w = 0;
    
    		if (area->list) {
    			if ( (area->list == &container.elements) || (toMove.type == BuilderContainer::ELEMENT) ) {
    				area->list->insert(area->before, toMove);
    			}	
    		}
    		
    
    		InitWidgets();
    		DeleteContainer(origin);
    	}
    
    	background.currentArea = 0;
    	this->update();
    }
    

    DeleteContainer Function.

    void BuilderWidget::DeleteContainer(BuilderContainer *bcPtr) {
       if (!bcPtr) {
       	return;
       }
       
       auto toDeleteBc = bcPtr;
    
       HandleSelection(0);
       
       for (int i = 0; i < container.elements.count(); ++i) {
       	auto &currentBc(container.elements[i]);
       	
       	if (&currentBc == toDeleteBc) {
       		
       		currentBc.w->hide(); 
       		currentBc.w->deleteLater();
       		container.elements.removeAt(i);
       		break;
       	}
       }
    
    }
    

    Qt::DropAction dropAction = drag->exec(Qt::MoveAction, Qt::MoveAction); this line is crashing software on MAC platform. If I comment out currentBc.w->deleteLater(); inside the DeleteContainer function then it is work fine.

    what is wrong am I doing?


  • Lifetime Qt Champion

    Hi,

    What version of Qt are you using ?
    What version of macOS are you running ?
    Can you provide a complete minimal example that reproduce that behaviour ?



  • @SGaist

    @SGaist said in why QDrag->exec() is crashing on MAC but not on windows version?:

    What version of Qt are you using ?

    I am using Qt 5.13.0.

    @SGaist said in why QDrag->exec() is crashing on MAC but not on windows version?:

    What version of macOS are you running ?

    macOS version 10.13.6

    @SGaist said in why QDrag->exec() is crashing on MAC but not on windows version?:

    Can you provide a complete minimal example that reproduce that behavior ?

    Here The complete project for reproduce same behavior

    image file element1.png, element2.png
    1_1562102685775_element2.png 0_1562102685774_element1.png

    File name: ReplicaOfProject.pro

    #-------------------------------------------------
    #
    # Project created by QtCreator 2019-05-29T12:19:35
    #
    #-------------------------------------------------
    
    QT       += core gui
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = ReplicaOfProject
    TEMPLATE = app
    
    # The following define makes your compiler emit warnings if you use
    # any feature of Qt which has been marked as deprecated (the exact warnings
    # depend on your compiler). Please consult the documentation of the
    # deprecated API in order to know how to port your code away from it.
    DEFINES += QT_DEPRECATED_WARNINGS
    
    # You can also make your code fail to compile if you use deprecated APIs.
    # In order to do so, uncomment the following line.
    # You can also select to disable deprecated APIs only up to a certain version of Qt.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    
    CONFIG += c++11
    
    SOURCES += \
            BuilderWidget.cpp \
            Mainwindow.cpp \
            MainwindowUI.cpp \
            main.cpp
    
    HEADERS += \
        BuilderWidget.h \
        Mainwindow.h \
        MainwindowUI.h \
        UIEventFilters.hpp \
        UIHelper.hpp
    RESOURCES += \
        gui.qrc
    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target
    
    

    Filename: main.cpp

    #include "Mainwindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    
    

    Filename: BuilderWidget.h

    #ifndef BUILDERWIDGET_H
    #define BUILDERWIDGET_H
    
    #define ELEMENT_MIME_TYPE	"image/element"
    
    #include <QFrame>
    
    #include <QVBoxLayout>
    #include "QDebug"
    #include "quuid.h"
    #include "qlabel.h"
    #include "qlist.h"
    
    
    #include <QDragEnterEvent>
    #include <QDragLeaveEvent>
    #include <QDragMoveEvent>
    #include <QDropEvent>
    #include <QResizeEvent>
    #include <QDrag>
    #include <QMimeData>
    
    #include "UIHelper.hpp"
    #include "UIEventFilters.hpp"
    
    
    
    
    
    
    class BuilderWidget : public QFrame
    {
        Q_OBJECT
    
        typedef struct{
            QWidget *w = nullptr;
            QUuid id;
            QString imagePath;
        }BuilderContainer;
    
        struct {
                QVBoxLayout *elementsLay = nullptr;
                QWidget *selectOverlay = nullptr;
            } ui;
    
        void InitWidgets();
        void PlaceWidgets();
        QWidget* CreateBuildExpElementWidget(const BuilderContainer&);
    public:
        explicit BuilderWidget(QWidget *parent = nullptr);
        QUuid GetId(QWidget*);
        QList<BuilderContainer> container;
    protected:
        void dropEvent(QDropEvent *e);
        void dragEnterEvent(QDragEnterEvent *e);
        void dragLeaveEvent(QDragLeaveEvent *e);
        void dragMoveEvent(QDragMoveEvent *e);
    
    signals:
    
    public slots:
        void DeleteContainer(BuilderContainer*);
    };
    
    #endif // BUILDERWIDGET_H
    
    

    FileName: BuilderWidget.cpp

    #include "BuilderWidget.h"
    #define BUILDER_ELEMENT_SPACING		2
    
    BuilderWidget::BuilderWidget(QWidget *parent) : QFrame(parent)
    {
        OBJ_NAME(this, "build-exp-holder");
        this->setAcceptDrops(true);
    
    }
    QWidget* BuilderWidget::CreateBuildExpElementWidget(const BuilderContainer &bc) {
        auto label = OBJ_NAME(new QLabel, "element-builder");
    
        QPixmap pixmap(bc.imagePath);
        label->setPixmap(pixmap);
    
    
        label->setAttribute(Qt::WA_Hover, true);
        label->installEventFilter(new ElementEventFilter(label->parent(), this, label, bc.id));
    
        return label;
    
    }
    
    void BuilderWidget::DeleteContainer(BuilderContainer *bcPtr) {
        if (!bcPtr) {
                return;
         }
        auto toDeleteBc = bcPtr;
    
        for (int i = 0; i < container.count(); ++i) {
            auto &currentBc(container[i]);
            if (&currentBc == toDeleteBc) {
                currentBc.w->deleteLater();
                container.removeAt(i);
                break;
            }
        }
    
         return;
    }
    
    void BuilderWidget::InitWidgets() {
        for (auto it = container.begin(); it != container.end(); ++it) {
    
            if (!it->w) {
                    it->w = CreateBuildExpElementWidget(*it);
                    it->w->hide();
             }
    
        }
    
    }
    void BuilderWidget::PlaceWidgets() {
        if (!ui.elementsLay) {
                ui.elementsLay = NO_MARGIN(new QVBoxLayout(this));
                ui.elementsLay->setSpacing(BUILDER_ELEMENT_SPACING);
            }
            while (ui.elementsLay->count()) {
                auto item = ui.elementsLay->itemAt(0);
                ui.elementsLay->removeItem(item);
    
                delete item;
            }
    
        for (auto it = container.begin(); it != container.end(); ++it) {
            auto elemLay = NO_SPACING(NO_MARGIN(new QHBoxLayout));
    
            elemLay->addStretch(1);
            elemLay->addWidget(it->w);
            elemLay->addStretch(1);
    
            ui.elementsLay->addLayout(elemLay);
    
            if (it->w->isHidden()) {
                it->w->show();
            }
        }
    
    
        this->update();
    }
    void BuilderWidget::dropEvent(QDropEvent *e) {
    
        if (e->mimeData()->hasFormat(ELEMENT_MIME_TYPE)) {
    
            auto byteArray = e->mimeData()->data(ELEMENT_MIME_TYPE);
            auto id = QUuid(byteArray);
    
            BuilderContainer toMove;
            BuilderContainer *origin = nullptr;
    
            for (auto it = container.begin(); it != container.end(); ++it) {
                if (it->id == id) {
                    toMove = *it;
                    origin = &(*it);
                    break;
                 }
            }
            if (!origin){
                toMove.imagePath = byteArray;
            }
            toMove.id = QUuid::createUuid();
            toMove.w = nullptr;
    
            container << toMove;
            InitWidgets();
    
            if (origin){
                DeleteContainer(origin);
            }
            PlaceWidgets();
        }
    
        this->update();
    }
    void BuilderWidget::dragEnterEvent(QDragEnterEvent *e) {
    
        if (e->mimeData()->hasFormat(ELEMENT_MIME_TYPE)) {
            e->accept();
        }
        else {
            e->ignore();
        }
        this->update();
    }
    void BuilderWidget::dragLeaveEvent(QDragLeaveEvent *e) {
        this->update();
    }
    void BuilderWidget::dragMoveEvent(QDragMoveEvent *e) {
        do {
            if (!(e->mimeData()->hasFormat(ELEMENT_MIME_TYPE)) ) {
                break;
            }
            auto pos = e->pos();
    
    
            e->accept();
            this->update();
    
            return;
        } while (0);
    
    
        e->ignore();
        this->update();
    }
    
    

    FileName: Mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include "qfile.h"
    #include "qapplication.h"
    #include "qdesktopwidget.h"
    
    #include "UIEventFilters.hpp"
    
    class MainWindowUI;
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    private:
        MainWindowUI *ui;
    
        void ApplyStyle();
    };
    
    #endif // MAINWINDOW_H
    
    

    Filename: Mainwindow.cpp

    #include "Mainwindow.h"
    #include "MainwindowUI.h"
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent),ui(new MainWindowUI(this))
    {
        ui->CreateUI();
        ApplyStyle();
    }
    
    MainWindow::~MainWindow()
    {
    
    }
    
    void MainWindow::ApplyStyle() {
    
        QFile f(":/GUI/GUI.css");
        if (!f.open(QIODevice::ReadOnly))
            return;
    
        QString newStyleSheet = f.readAll();
    
        qobject_cast<QApplication *>(QApplication::instance())->setStyleSheet(newStyleSheet);
    
        f.close();
    }
    

    Filename: MainwindowUI.h

    #ifndef MAINWINDOWUI_H
    #define MAINWINDOWUI_H
    #include "Mainwindow.h"
    
    class MainWindowUI : public QObject
    {
        Q_OBJECT
    public:
        MainWindowUI(MainWindow *Parent);
        void CreateUI();
        void CraeteCentralWidget();
        QWidget* GetMainTabWidget();
        QWidget* CreateElementsListWidget();
        QWidget* CreateDragPlace();
    signals:
    
    public slots:
    
    private:
        MainWindow *m_mainWindow;
    };
    
    #endif // MAINWINDOWUI_H
    
    

    Filename: MainwindowUI.cpp

    #include "MainwindowUI.h"
    #include "UIHelper.hpp"
    #include "QListView"
    #include "QStandardItemModel"
    #include "qdebug.h"
    #include "QMimeData"
    #include "qdrag.h"
    
    
    #include "builderwidget.h"
    #define ELEMENT_MIME_TYPE	"image/element"
    
    MainWindowUI::MainWindowUI(MainWindow *parent) : m_mainWindow(parent)
    {
    
    }
    
    
    void MainWindowUI::CreateUI(){
        CraeteCentralWidget();
    }
    void MainWindowUI::CraeteCentralWidget(){
        QWidget *centralWidget = OBJ_NAME(WDG(), "central-widget");
        QGridLayout *centralLayout = NO_SPACING(NO_MARGIN(new QGridLayout(centralWidget)));
        m_mainWindow->setCentralWidget(centralWidget);
        centralLayout->addWidget(GetMainTabWidget(), 1, 0);
    
    }
    QWidget* MainWindowUI::GetMainTabWidget() {
        static QWidget *w = nullptr;
    
        if (w) {
            return w;
        }
        w = WDG();
    
       auto lay = NO_SPACING(NO_MARGIN(new QHBoxLayout(w)));
       lay->addWidget(CreateElementsListWidget());
       lay->addWidget(CreateDragPlace());
        return w;
     }
    
    QWidget* MainWindowUI::CreateElementsListWidget(){
        static QWidget *w = nullptr;
    
        if (w) {
            return w;
        }
    
        w = OBJ_NAME(WDG(), "node-list-owner");
       auto lay = NO_SPACING(NO_MARGIN(new QVBoxLayout(w)));
    
       auto elementsListHolder = OBJ_NAME(new QFrame(), "elements-list-holder");
       auto elementsListHolderLay = new QGridLayout(elementsListHolder);
    
    
       QStringList elemets = {":/GUI/element1.png",":/GUI/element2.png"};
    
    
       foreach(auto elem, elemets) {
            auto label = OBJ_NAME(new QLabel, "element-builder");
            QPixmap pixmap(elem);
            label->setPixmap(pixmap);
    
            label->installEventFilter(new UniversalEventFilter(label, [=](QObject *obj, QEvent *e) {
    
    
                            if (e->type() == QEvent::Enter) {
    
                                QWidget *w = qobject_cast<QWidget*>(obj);
    
                                if (!w) {
                                    return false;
                                }
    
                                auto marg = w->contentsMargins();
    
                                auto additionalHeight = (w->height() - marg.bottom() - marg.top()) * 0.25;
    
                                QPoint topLeft = QPoint(marg.left() - 1, marg.top() - 3);
                                QPoint bottomRight = QPoint(w->width(), w->height() + additionalHeight);
    
                                bottomRight -= QPoint(marg.right(), marg.bottom());
    
    
    
    
                                //auto  overlay  = OBJ_NAME(new QFrame(w), "hover-element-overlay");
                                auto  overlay  = OBJ_NAME(label , "hover-element-overlay");
    
                                overlay->setGeometry(QRect(topLeft + w->pos(), bottomRight + w->pos()));
    
    
                                static bool dragInAction;
                                dragInAction = false;
                                overlay->installEventFilter(new UniversalEventFilter(overlay, [=](QObject *obj, QEvent *e) {
                                    if (e->type() == QEvent::MouseButtonPress) {
                                        QWidget *w = qobject_cast<QWidget*>(obj);
                                        if (!w) {
                                            return false;
                                        }
    
                                        QMouseEvent *me = (QMouseEvent*)e;
    
                                        if (me->button() == Qt::LeftButton) {
                                            auto margins = w->contentsMargins();
                                            auto rect = w->rect();
    
                                            QPoint startPoint;
                                            startPoint.setX(margins.left() - 1);
                                            startPoint.setY(margins.top() - 1);
                                            QPoint endPoint;
                                            endPoint.setX(rect.width() - margins.right());
                                            endPoint.setY(rect.height() - margins.bottom());
    
                                           auto byteArray = QByteArray().append(elem);
    
                                            auto mime = new QMimeData;
                                            mime->setData(ELEMENT_MIME_TYPE, byteArray);
    
                                            auto pixmap = w->grab(QRect(startPoint, endPoint));
                                            pixmap = pixmap.scaledToHeight((endPoint.y() - startPoint.y()) / 2, Qt::SmoothTransformation);
    
                                            QDrag *drag = new QDrag(obj);
                                            drag->setMimeData(mime);
                                            drag->setPixmap(pixmap);
                                            drag->setHotSpot((me->pos() - QPoint(margins.left(), margins.top())) / 2);
    
                                            dragInAction = true;
                                            Qt::DropAction dropAction = drag->exec(Qt::CopyAction, Qt::CopyAction);
                                            dragInAction = false;
    
                                            return true;
                                        }
                                        return false;
                                    }
                                    if (e->type() == QEvent::Enter) {
                                        return true;
                                    }
                                    if (e->type() == QEvent::Leave) {
                                        if (dragInAction) {
                                            return false;
                                        }
    
    
                                        return true;
                                    }
                                    return false;
                                }));
    
    
                                return true;
                                }
    
    
                                return false;
                    }));
    
    
    
    
            static int column = 0;
            if (!column) {
                elementsListHolderLay->addWidget(label, 0, column);
                column++;
            }else{
                elementsListHolderLay->addWidget(label, 0,column);
                column = 0;
            }
        }
    
    
        lay->addWidget(elementsListHolder);
        lay->addStretch();
        return w;
    }
    QWidget* MainWindowUI::CreateDragPlace(){
        static QWidget *w = nullptr;
    
        if (w) {
            return w;
        }
    
        w = OBJ_NAME(WDG(), "Drag-place-widget");
         auto lay = NO_SPACING(NO_MARGIN(new QVBoxLayout(w)));
    
         lay->addWidget(new BuilderWidget(m_mainWindow));
    
        return w;
    
    }
    
    

    FileName: UIEventFilters.hpp

    #pragma once
    
    #define ELEMENT_MIME_TYPE	"image/element"
    #include "BuilderWidget.h"
    #include <QEvent>
    #include <QMouseEvent>
    
    #include <QObject>
    #include <QWidget>
    #include <QScrollArea>
    #include <QScrollBar>
    #include <qtooltip.h>
    #include <QSortFilterProxyModel>
    #include <QGraphicsDropShadowEffect>
    #include <QXmlStreamReader>
    
    #include <QtMath>
    
    
    
    #include <functional>
    
    #define EXPERIMENT_VIEW_ALL_CATEGORY	"View All"
    
    
    
    class UniversalEventFilter : public QObject {
    public:
    	UniversalEventFilter(QObject *parent, std::function<bool(QObject*, QEvent*)> lambda) :
    		QObject(parent), _lambda(lambda) {}
    
    	bool eventFilter(QObject *obj, QEvent *e) {
    		return _lambda(obj, e);
    		
    	}
    private:
    	std::function<bool(QObject*, QEvent*)> _lambda;
    };
    
    class BuilderWidget;
    class ElementEventFilter : public QObject {
    public:
        ElementEventFilter(QObject *parent, BuilderWidget *bw, QWidget *image,QUuid _id) :
            QObject(parent), _bw(bw), pressed(false), dragged(false), entered(false), _image(image),id(_id) {}
    
        bool eventFilter(QObject *obj, QEvent *e) {
            bool ret = false;
    
            switch (e->type()) {
            case QEvent::MouseButtonPress:
                if (!IsIgnoreArea(obj, e)) {
                    pressed = true;
                    dragged = false;
                    pressButton = (static_cast<QMouseEvent*>(e))->button();
                    pressPoint = (static_cast<QMouseEvent*>(e))->pos();
    
                    ret = true;
                }
    
                break;
    
            case QEvent::MouseMove:
                if (pressed && !dragged) {
                    QPoint pos = (static_cast<QMouseEvent*>(e))->pos();
                    QLine moveVector(pressPoint, pos);
                    auto length = qSqrt(moveVector.dx() * moveVector.dx() + moveVector.dy() * moveVector.dy());
                    if (length > 3) {
                        dragged = true;
                        ret = ProcessDrag(obj, e);
                    }
                }
                break;
    
            case QEvent::MouseButtonRelease:
                if (pressed && !dragged) {
                    ret = ProcessSelection(obj, e);
                }
                pressed = false;
                dragged = false;
                break;
    
            case QEvent::HoverEnter:
                entered = true;
                break;
    
            case QEvent::HoverLeave:
                entered = false;
    
                _image->show();
                break;
            default:
                break;
            }
    
            return ret;
        }
    
    private:
        bool IsIgnoreArea(QObject *obj, QEvent *e) {
            auto w = qobject_cast<QWidget*>(obj);
            if (!w) {
                return true;
            }
    
            auto me = static_cast<QMouseEvent*>(e);
    
            auto marg = w->contentsMargins();
            QPoint bottomRight = QPoint(w->width(), w->height());
            bottomRight -= QPoint(marg.right() - 3, marg.bottom() - 3);
    
            QPoint topLeft = QPoint(marg.left() - 3, marg.top() - 3);
    
            if (!QRect(topLeft, bottomRight).contains(me->pos())) {
                return true;
            }
    
            return false;
        }
        bool ProcessSelection(QObject *obj, QEvent *e) {
    
            auto w = qobject_cast<QWidget*>(obj);
            if (!w) {
                return false;
            }
    
            if (IsIgnoreArea(obj, e)) {
                return false;
            }
    
    
            return true;
        }
        bool ProcessDrag(QObject *obj, QEvent *e) {
    
            QWidget *w = qobject_cast<QWidget*>(obj);
            if (!w) {
                return false;
            }
    
            //auto me = static_cast<QMouseEvent*>(e);
    
            if (IsIgnoreArea(obj, e)) {
                return false;
            }
    
            if (pressButton == Qt::LeftButton) {
                auto margins = w->contentsMargins();
                auto rect = w->rect();
    
                QPoint startPoint;
                startPoint.setX(margins.left() - 1);
                startPoint.setY(margins.top() - 1);
                QPoint endPoint;
                endPoint.setX(rect.width() - margins.right() + 1);
                endPoint.setY(rect.height() - margins.bottom());
    
    
                auto mime = new QMimeData;
                mime->setData(ELEMENT_MIME_TYPE, id.toByteArray());
    
                auto pixmap = w->grab(QRect(startPoint, endPoint));
                pixmap = pixmap.scaledToHeight((endPoint.y() - startPoint.y()) / 2, Qt::SmoothTransformation);
    
                QDrag *drag = new QDrag(obj);
                drag->setMimeData(mime);
                drag->setPixmap(pixmap);
                drag->setHotSpot((pressPoint - QPoint(margins.left(), margins.top())) / 2);
    
                Qt::DropAction dropAction = drag->exec(Qt::MoveAction, Qt::MoveAction);
    
                return true;
            }
    
            return false;
        }
    
        QPoint pressPoint;
        Qt::MouseButton pressButton;
        bool pressed;
        bool dragged;
        bool entered;
    
        QWidget *_image;
        QUuid id;
        BuilderWidget *_bw;
    };
    
    
    

    FileName: UIHelper.hpp

    #pragma once
    
    #include <QObject>
    
    #include <QLayout>
    #include <QGridLayout>
    #include <QHBoxLayout>
    #include <QVBoxLayout>
    
    #include <QLabel>
    #include <QComboBox>
    #include <QLineEdit>
    #include <QTextEdit>
    #include <QPushButton>
    #include <QRadioButton>
    
    template<typename WidgetType>
    WidgetType* SetObjectName(WidgetType *w, const QString &name) {
    	w->setObjectName(name);
    	return w;
    }
    template<typename WidgetType>
    WidgetType* SetObjectProperty(WidgetType *w, const char *name, const QString &value) {
    	w->setProperty(name, value);
    	return w;
    }
    template<typename LayoutType>
    LayoutType* SetZeroMargin(LayoutType *l) {
    	l->setContentsMargins(0, 0, 0, 0);
    	return l;
    }
    template<typename LayoutType>
    LayoutType* SetZeroSpacing(LayoutType *l) {
    	l->setSpacing(0);
    	return l;
    }
    
    #define TR(...)         QObject::tr(__VA_ARGS__)
    //#define QObject::connect(...)    QObject::connect(__VA_ARGS__)
    
    
    
    #define WDG()			new QWidget
    #define LBL(str)		new QLabel(TR(str))
    #define CMB()			new QComboBox
    #define LED()			new QLineEdit
    #define TED()			new QTextEdit
    #define PBT(str)		new QPushButton(TR(str))
    #define RBT(str)		new QRadioButton(TR(str))
    
    
    
    #define OBJ_NAME(qobject, qstring)	SetObjectName(qobject, qstring)
    #define OBJ_PROP(w, name, val)		SetObjectProperty(w, name, val)
    
    #define NO_MARGIN(qlayout)	SetZeroMargin(qlayout)
    #define NO_SPACING(qlayout)	SetZeroSpacing(qlayout)
    

    Filename: GUI.css

    QMainWindow {
            min-width: 1366px;
            min-height: 768px;
    }
    #node-list-owner{
    border: 2px solid;
    }
    
    

    FileName: gui.qrc

    <RCC>
        <qresource prefix="/GUI">
            <file>GUI.css</file>
            <file>element1.png</file>
            <file>element2.png</file>
        </qresource>
        <qresource prefix="/"/>
    </RCC>
    
    

    Reproducing step:

    0_1562103581237_Reproduce By Following.PNG

    Here the MAC version of software is crashing at drag#2.
    software is crash at line Qt::DropAction dropAction = drag->exec(Qt::MoveAction, Qt::MoveAction); in UIEventFilters.hpp file.

    if I will comment out line currentBc.w->deleteLater(); in BuilderWidget::DeleteContainer(BuilderContainer *bcPtr) function then it is not crashing.

    What are the change I need to make?

    Just for futures use: is It any way to upload .cpp and .h file in Qt form?



  • This post is deleted!


  • @SGaist any suggestion for avoiding crash while using QDrag->exec() in MAC software?


  • Lifetime Qt Champion

    I don't have an answer currently because your example is clearly not minimal. I can confirm it crashes even with a more recent version of Qt. However, the code is pretty convoluted especially for doing drag and drop.

    I think there's room for simplification that would likely end up in a cleaner and easier to understand code base.



  • Hello Yash001
    I get similar issue with my code and manage to fix it by patching Qt... I'm wondering if the same fix would fix your issue too...
    (because I send the fix to Qt to commit, but as I can not reproduce the issue on a minimal project, they say the problem doesn't exist and they do not really want to accept my patch. So it is better if several of us report the same issue)
    On our side, the issue was raised only when we use tablet pen + drag & drop. I do not know if it is the same problem for you... (if you were using our mouse, it is more likely that our patch will not fix your issue)
    You can download the patch here :
    http://download.pointcarre.com/dev/Qt5.12.4Fix.zip
    Please let me know if it fix your issue...
    Best regards
    Sebastien


  • Lifetime Qt Champion

    Hi @Sebastien-Leon and welcome to devnet,

    Can you post the link to the bug report / gerrit review you made ?