Search code examples
qtqt4

Drag and drop widget outside source application widgets


I have a Qt Desktop aplication which has several top-level widgets. Subwidgets of top-level widgets can be moved between top-level widgets by using drag-and-drop mechanism.

The problem i have now is to drop a sub-widget outside any of existing top-level widgets and create a new top-level widget to contain this one. Lets call this separation.

Can this be done using drag-and-drop? I could not find a way where my dropEvent goes? Can i want to handle the drop event in my application even if the drop place is not allowed? Maybe a mouse release or something?

I cannot change everything now but also a question for the future. Is docking/undocking a better way to do this?

Regards Mihai


Solution

  • I found a way to do this. When drag moves outside of the application widgets QDrag object emits a targetChanged signal with 0 parameter.

    So i inherited from QDrag and then emit a custom signal in destructor if the target() is null.

    The only problem is that the cursor looks like interdiction of drop and this i could not fix because QDrag can only set cursor pixmap for valid actions like Move or Copy or Link

    Update:

    Here is the inherited class.

    class TabDrag: public QDrag
    {
        Q_OBJECT
    public:
        explicit TabDrag(QWidget *dragSource);
        ~TabDrag();
    
    signals:
        void tearOff(); /// emit tearOff signal if the QDrag object is destroyed and target was null
    };
    
    TabDrag::TabDrag(QWidget *dragSource):QDrag(dragSource)
    {
    }
    
    TabDrag::~TabDrag()
    {
        // check if we need to detach this tab
        if(!target())
        {
            emit tearOff();
        }
    }
    

    The tearOff signal should be connected to whatever you want to happen. In my case i pull out the widget from the tab and change parent to a new window.

    Example of usage

    void MyTabBar::mouseMoveEvent(QMouseEvent* event)
    {
    ..................
        TabDrag * drag = new TabDrag(this);
        drag->setMimeData(mimeData);
        drag->setPixmap(*m_tabPixmap.data());
        drag->setHotSpot(QPoint(m_dragStartPos.x() - tabAtRect.x(), m_dragStartPos.y() - tabAtRect.y()));
        drag->exec();
    
        connect(drag, SIGNAL(tearOff()), this, SLOT(onTearOff()));
    }