2
votes

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

1

1 Answers

2
votes

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()));
}