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. Moving QDockWindow to another QMainWindow during drag.

Moving QDockWindow to another QMainWindow during drag.

Scheduled Pinned Locked Moved General and Desktop
5 Posts 2 Posters 2.5k Views
  • 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.
  • I Offline
    I Offline
    Ian Clévy
    wrote on last edited by
    #1

    Hello all,

    The title says it all : I want to change QMainWindow of a QDockWindow while I'm dragging the said QDockWindow.

    While I'm not dragging I can do this just by calling addDockWidget on the new QMainWindow. If I do the same while I'm dragging the QDockWindow a crash occures.

    I can get around it by doing a setFloating( true ) before the addDockWidget but that stops the dragging and moves the QDockWidget to the specified dock area (obviously). I want the user to be albe to continue dragging seamlessly.

    Any ideas ?

    Ian

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi and welcome to devnet,

      Can you provide a minimal sample code that can reproduce the problem ?

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

      1 Reply Last reply
      0
      • I Offline
        I Offline
        Ian Clévy
        wrote on last edited by
        #3

        I made a subclass of QDockWidget and wrote an override for the event method. This QDockWidget can be in one of two main windows, m_pMainWindow1 is the normal main window and m_pMainWindow2 is another main window used as a the central widget of m_pMainWindow1-.

        @bool MultiWindowDockWidget::event ( QEvent* in_pEvent )
        {
        switch ( in_pEvent->type() )
        {
        case QEvent::MouseButtonPress:
        case QEvent::NonClientAreaMouseButtonPress:
        {
        QMouseEvent* pMouseEvent = static_cast<QMouseEvent*>( in_pEvent );
        if( pMouseEvent->button() == Qt::LeftButton && !m_bIsDragging )
        m_bIsDragging = true;
        }
        break;
        case QEvent::Move:
        {
        if( m_bIsDragging )
        {
        if( m_pMainWindow2->rect().contains( m_pMainWindow2->mapFromGlobal( QCursor::pos() ) ) )
        {
        if( !m_pMainWindow2->children().contains( this ) )--
        {
        m_bNeedWindowChange = true;
        update();
        }
        }
        else
        {
        if( !m_pMainWindow1--->children().contains( this ) )
        {
        m_bNeedWindowChange = true;
        update();
        }
        }
        }
        }
        break;
        case QEvent::MouseButtonRelease:
        case QEvent::NonClientAreaMouseButtonRelease:
        case QEvent::NonClientAreaMouseMove:
        {
        if( m_bIsDragging )
        m_bIsDragging = false;
        }
        break;
        case QEvent::UpdateRequest:
        {
        if( m_bNeedWindowChange )
        {
        QRect oGeometry = geometry();
        setFloating( false );
        if( m_pMainWindow2->children().contains( this ) )
        {
        m_pMainWindow1->addDockWidget( Qt::LeftDockWidgetArea, this );
        }
        else
        {
        m_pMainWindow2->addDockWidget( Qt::LeftDockWidgetArea, this );
        }
        setFloating( true );
        m_bNeedWindowChange = false;--
        }
        }
        break;
        }
        return QDockWidget::event( in_pEvent );
        }@

        This is the best work around that I've found but every time the dock widget changes main window the dragging stops, so it's not an acceptable solution for the user.

        I'm also not sure if the update() method and UpdateRequest event are made to be used like this? At first, I tried to put that code directly in the Move event case but this caused a crash because the Move event is triggered by a MouseMove event. The MouseMove event crashes because it tries to do stuff with the drag state of the QDockWidget (that becomes invalid because dragging stops) after the Move event returns.

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          What does your crash say ?

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

          1 Reply Last reply
          0
          • I Offline
            I Offline
            Ian Clévy
            wrote on last edited by
            #5

            The code I posted before doesn't crash. The crash occurs when I try to change the main window during the move event.

            It's a memory violation exception when trying to acces the state attribute of the QDockWidget. From what I can gather, state holds infomation about the dragging of the QDockWidget and it is set to null when dragging isn't in progress.

            @
            if (state->dragging && !state->nca) {
            QPoint pos = event->globalPos() - state->pressPos;
            q->move(pos);

                if (!state->ctrlDrag)
                    mwlayout->hover(state->widgetItem, event->globalPos());
            
                ret = true;
            }
            

            @

            During the call to q->move(pos) I intercept the move event and change the main window, which also stops the dragging and sets state to null:

            @
            bool MultiWindowDockWidget::event ( QEvent* in_pEvent )
            {
            switch ( in_pEvent->type() )
            {
            case QEvent::MouseButtonPress:
            case QEvent::NonClientAreaMouseButtonPress:
            {
            QMouseEvent* pMouseEvent = static_cast<QMouseEvent*>( in_pEvent );
            if( pMouseEvent->button() == Qt::LeftButton && !m_bIsDragging )
            m_bIsDragging = true;
            }
            break;
            case QEvent::Move:
            {
            if( m_bIsDragging )
            {
            if( m_pMainWindow2->rect().contains( m_pMainWindow2->mapFromGlobal( QCursor::pos() ) ) )
            {
            if( !m_pMainWindow2->children().contains( this ) )
            {
            m_pMainWindow2->addDockWidget( Qt::LeftDockWidgetArea, this );
            }
            }
            else
            {
            if( !m_pMainWindow1--->children().contains( this ) )
            {
            m_pMainWindow1->addDockWidget( Qt::LeftDockWidgetArea, this );
            }
            }
            }
            }
            break;
            case QEvent::MouseButtonRelease:
            case QEvent::NonClientAreaMouseButtonRelease:
            case QEvent::NonClientAreaMouseMove:
            {
            if( m_bIsDragging )
            m_bIsDragging = false;
            }
            break;
            }
            return QDockWidget::event( in_pEvent );
            }
            @

            Once q->move(pos) returns, the QDockWidget tries to acces the state attribute if (!state->ctrlDrag) and crashes.

            Idealy I would like to change the main window during the move event and then reactivate dragging (this would stop the crash and be seamless to the user) but I don't have acces to the initDrag(), startDrag(), and endDrag() methods in QDockWidget that would enable me to do this.

            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