Page 1 of 2 12 LastLast
Results 1 to 20 of 26

Thread: [SOLVED] Detachable QDockWidget tabs

  1. #1
    Join Date
    Oct 2014
    Posts
    81
    Thanks
    20
    Thanked 9 Times in 9 Posts
    Qt products
    Qt5
    Platforms
    Windows
    Wiki edits
    7

    Default [SOLVED] Detachable QDockWidget tabs

    Here follows an example project of how to achieve detachable (as in, click-drag to tear off) QDockWidget tabs, something which is quite standard in commercial software but somehow not implemented in Qt.

    Qt does not support detachable dock widget tabs nor does it expose much of its docking system for us to implement it. However, by using some [stable] tricks and some research into the Qt source code we can achieve this behaviour. The inspiration for this was Toon Boom, a commercial software used for animation that was built with Qt, and it has detachable dock tabs. Some more sophisticated docking systems can be found in Adobe software such as Photoshop and Flash.

    This thread (Dragable-QDockWidget-tabs-with-no-title-bar) makes an important point: "Displaying the title in the tab and the title bar seems ugly and a waste of screen space."
    The original Qt docking system looks like this, as seen in Krita, a famous open-source digital painting application:


    You can see highlighted in red that you have the name of the panel not only on the tab but also on the dock widget title bar, wasting vertical space.

    This example project hides the title bars of dock widgets when they are tabified to compensate for that. Then it allows the user to detach the dock widget by dragging the tab or by double-clicking it.
    It also implements the concept of a 'workspace,' which is nothing more than different QMainWindow states. A suggestion is to use this workspace system to allow the user to save their own custom dock arrangements.

    Notes:

    - For this system to work it's necessary to synthesize OS-level mouse events. This is platform specific, and in the attached example you will find the implementation for Windows (using the SendInput function). There's still the need to implement and test for OS X and Linux (X11). The system is stable nonetheless.

    - This system works with graphics tablets (as in, you can detach and drag docks with the stylus). I tested it with a Wacom Bamboo graphics tablet and as such it can be used in software that supports this kind of input device.

    - This is my first major C++ usage. If you have any recommendations for improvements in the code for clarity etc. please share your thoughts here or send me a PM. I will appreciate it. The source code is heavily commented with the C++ \ Qt novice in mind. This system can probably be ported to Python with ease.

    Here's a screenshot of how it looks on my system, Windows XP:


    If you have the time, please share a screenshot of how it looks on your system. The tab close button graphic is native, but it can probably be styled with a custom pixmap using the QTabBar::close-button CSS subcontrol.

    References (these helped a lot):

    - http://qt-project.org/faq/answer/how...ed_qdockwidget
    - http://www.qtcentre.org/threads/1428...dget-is-docked
    - http://www.qtcentre.org/wiki/index.p...e=Movable_Tabs
    - http://blog.qt.digia.com/blog/2009/0...w-by-dragging/
    Attached Files Attached Files
    Last edited by Kryzon; 22nd January 2015 at 19:09.

  2. #2
    Join Date
    Dec 2014
    Posts
    49
    Thanks
    6
    Thanked 3 Times in 3 Posts
    Qt products
    Qt5 PyQt3 PyQt4
    Platforms
    Windows

    Default Re: [SOLVED] Detachable QDockWidget tabs

    This is exciting !

    however, compiling the project throws the following error

    SyntheticMouseEvent.obj:-1: error: LNK2019: unresolved external symbol __imp__SendInput@12 referenced in function "void __cdecl sendOSMouseEvent(enum SynthMouseEvent,int,int)" (?sendOSMouseEvent@@YAXW4SynthMouseEvent@@HH@Z)

  3. #3
    Join Date
    Oct 2014
    Posts
    81
    Thanks
    20
    Thanked 9 Times in 9 Posts
    Qt products
    Qt5
    Platforms
    Windows
    Wiki edits
    7

    Default Re: [SOLVED] Detachable QDockWidget tabs

    Hello.
    Just for reference, I compiled that project with the MinGW kit.

    That LNK2019 error seems to be from Visual Studio (reference).
    The fix seems to be to add "LIBS += -luser32" to your PRO file, as per this thread here: http://qt-project.org/forums/viewthread/16794

    (The PRO file is the Qt project file that you open with Qt Creator and can manually edit the project settings.)

  4. The following user says thank you to Kryzon for this useful post:

    NIteLordz (22nd January 2015)

  5. #4
    Join Date
    Dec 2014
    Posts
    49
    Thanks
    6
    Thanked 3 Times in 3 Posts
    Qt products
    Qt5 PyQt3 PyQt4
    Platforms
    Windows

    Default Re: [SOLVED] Detachable QDockWidget tabs

    Add that to the pro file worked. Time to integrate this into my system and remove those nasty title bars.

    Well done !

  6. #5
    Join Date
    May 2013
    Posts
    321
    Thanks
    9
    Thanked 8 Times in 8 Posts
    Qt products
    Qt5
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: [SOLVED] Detachable QDockWidget tabs

    Great works there, I saw the cross platform code is not finished and the code can be cleaned but apparently that works without problem.

  7. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: [SOLVED] Detachable QDockWidget tabs

    Quote Originally Posted by Kryzon View Post
    Here follows an example project of how to achieve detachable (as in, click-drag to tear off) QDockWidget tabs, something which is quite standard in commercial software but somehow not implemented in Qt.
    Qt supports detachable dock tabs since 4.0 (which was released like 9 years ago). They are used by e.g. Qt Designer.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  8. #7
    Join Date
    May 2013
    Posts
    321
    Thanks
    9
    Thanked 8 Times in 8 Posts
    Qt products
    Qt5
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: [SOLVED] Detachable QDockWidget tabs

    Can you explain how? I always saw only dock with titlebar possible, not like the example shown here.
    Last edited by Alundra; 23rd January 2015 at 14:03.

  9. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: [SOLVED] Detachable QDockWidget tabs

    Quote Originally Posted by Alundra View Post
    Can you explain how? I always saw only dock with titlebar possible, not like the example shown here.
    Just launch Qt Designer and start dragging the tabs around.

    In code I think this is controlled via QMainWindow::dockOptions property (and friends). MainWindow::AllowTabbedDocks is the flag that should be set to enable tabbing.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  10. #9
    Join Date
    Oct 2014
    Posts
    81
    Thanks
    20
    Thanked 9 Times in 9 Posts
    Qt products
    Qt5
    Platforms
    Windows
    Wiki edits
    7

    Default Re: [SOLVED] Detachable QDockWidget tabs

    From what I experimented, in Qt Designer -- and as is offered by default with Qt -- you can detach tabified dock widgets by click-dragging their title bar. Clicking the tabs themselves only switches the currently visible dock widget, there's no further interaction.

    What the example project above does is filter the events sent to the tab bars used by the internal docking system to enable the user to detach them by click-dragging the tabs or double-clicking them. It also "hides" the title bars when the dock widgets are tabified to save vertical space from the redundant information, as can be seen below (the left being the default behaviour):


    Quote Originally Posted by Alundra View Post
    Great works there, I saw the cross platform code is not finished and the code can be cleaned but apparently that works without problem.
    I'm glad that it works. If you can, please send me a private message with your suggestions on cleaning the code.

  11. #10
    Join Date
    May 2013
    Posts
    321
    Thanks
    9
    Thanked 8 Times in 8 Posts
    Qt products
    Qt5
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: [SOLVED] Detachable QDockWidget tabs

    Quote Originally Posted by wysota View Post
    Just launch Qt Designer and start dragging the tabs around.
    In code I think this is controlled via QMainWindow::dockOptions property (and friends). MainWindow::AllowTabbedDocks is the flag that should be set to enable tabbing.
    I tried, the title bar is automatically removed by default but then you must reshow it to undock and you don't have the cross on the tab bar, that looks to be basic behavior of Qt, just the automatic hiding added. The example shown in this topic add the cross and allows undock when click on the tab name and automatic hide the titlebar.
    Stuff can be changed :
    - less empty line in code.
    - empty code in destructor is not needed (DetachableDock::~DetachableDock()).
    - friend is not necessary to be used in DetachableDock, a lot of professionnal dislike to use friend, I'm in the group.
    - why pointer for tabBarList of DetachableDockManager ?
    - That's better to write DetachableDock generic and inherit it for the sample.
    - I would prefer include the code of SyntheticMouseEvent inside global namespace of DockManager since that's the only place used.
    Last edited by Alundra; 23rd January 2015 at 17:49.

  12. The following user says thank you to Alundra for this useful post:

    Kryzon (24th January 2015)

  13. #11
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: [SOLVED] Detachable QDockWidget tabs

    Quote Originally Posted by Kryzon View Post
    From what I experimented, in Qt Designer -- and as is offered by default with Qt -- you can detach tabified dock widgets by click-dragging their title bar. Clicking the tabs themselves only switches the currently visible dock widget, there's no further interaction.

    What the example project above does is filter the events sent to the tab bars used by the internal docking system to enable the user to detach them by click-dragging the tabs or double-clicking them. It also "hides" the title bars when the dock widgets are tabified to save vertical space from the redundant information, as can be seen below (the left being the default behaviour):
    Great. Just don't claim Qt doesn't offer or neglects the need for detachable dock widgets as it is not true.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  14. #12
    Join Date
    Nov 2014
    Posts
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: [SOLVED] Detachable QDockWidget tabs

    It works great on Windows!
    I tried to run it on Mac by implementing sendOSMouseEvent for Mac but it didn't work (it crashed).
    Any idea?

    My env is Mac 10.9.5 + Qt 5.4.0.
    Attached Files Attached Files

  15. #13
    Join Date
    Oct 2014
    Posts
    81
    Thanks
    20
    Thanked 9 Times in 9 Posts
    Qt products
    Qt5
    Platforms
    Windows
    Wiki edits
    7

    Default Re: [SOLVED] Detachable QDockWidget tabs

    Quote Originally Posted by shinichy View Post
    I tried to run it on Mac by implementing sendOSMouseEvent for Mac but it didn't work (it crashed).
    Any idea?
    Thank you for your interest.
    I don't have a Mac system for testing, so I can't help much. The first thing that I would do is run it in QtCreator under Debug mode so that I could identify the exact call that is causing the crash. This is the best information that we can have on the problem.

    I've looked at your implementation of sendOSMouseEvent and it seems absolutely fine.
    According to the documentation, the CGPoint event location is in global coordinates and we've been using relative so far, so I would add an #ifdef in the event filter function to use global coordinates. The following is in the eventFilter function, right when detaching the dock.

    Qt Code:
    1. if ( ( mouseEvent->pos() - clickPos ).manhattanLength() > QApplication::startDragDistance() )
    2. {
    3. if ( pressedTabIndex != -1 )
    4. {
    5. consumed = true;
    6.  
    7. /* In this release event I don't think the coordinates matter since the tab bar has
    8. mouse focus, but experimentation is required. It might need an ifdef just like below. */
    9. sendOSMouseEvent( SynthMouseEvent::MouseRelease, 0, 0 );
    10.  
    11. DetachableDock* detachingDock = dockFromTab( pressedTabBar, pressedTabIndex );
    12. detachingDock->setFloating( true );
    13.  
    14. QPoint cursorPos = QCursor::pos();
    15. detachingDock->centerTitle( cursorPos );
    16.  
    17. QApplication::processEvents();
    18. QCursor::setPos( cursorPos );
    19.  
    20. #ifdef Q_OS_WIN
    21. // Under Windows we use relative coordinates.
    22. sendOSMouseEvent( SynthMouseEvent::MousePress, 0, 0 );
    23. #endif
    24.  
    25. #ifdef Q_OS_OSX
    26. // Under OSX we use global coordinates.
    27. sendOSMouseEvent( SynthMouseEvent::MousePress, cursorPos.x(), cursorPos.y() );
    28. #endif
    29. }
    30. }
    To copy to clipboard, switch view to plain text mode 
    I don't think the coordinates matter on the release event because at that moment the tab bar will be under focus, but the press event does need accurate coordinates or else we might be clicking something other than the dock widget and it won't start its dragging mode.

  16. #14
    Join Date
    Nov 2014
    Posts
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: [SOLVED] Detachable QDockWidget tabs

    I tried global coordinates for only MousePress and both MouseRelease and MousePress, but both cases didn't work.
    I got this warning message and stacktrace (it's too long to post here, so I attached the full stack trace).

    Qt Code:
    1. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    2. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    3. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    4. The program has unexpectedly finished.
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. Exception Type: EXC_BAD_ACCESS (SIGSEGV)
    2. Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000008
    3.  
    4. Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
    5. 0 org.qt-project.QtWidgets 0x000000010bb40f47 QDockWidget::setFloating(bool) + 23
    6. 1 com.example.DetachDockExample 0x000000010b9dd624 DetachableDockManager::eventFilter(QObject*, QEvent*) + 484 (DetachableDockManager.cpp:418)
    7. 2 org.qt-project.QtCore 0x000000010c8a72f9 QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) + 217
    8. 3 org.qt-project.QtWidgets 0x000000010ba2adab QApplicationPrivate::notify_helper(QObject*, QEvent*) + 235
    9. 4 org.qt-project.QtWidgets 0x000000010ba2e65f QApplication::notify(QObject*, QEvent*) + 9551
    10. 5 org.qt-project.QtCore 0x000000010c8a6fb3 QCoreApplication::notifyInternal(QObject*, QEvent*) + 115
    11. 6 org.qt-project.QtWidgets 0x000000010ba2b73b QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool) + 987
    12. 7 org.qt-project.QtWidgets 0x000000010ba85161 QWidgetWindow::handleMouseEvent(QMouseEvent*) + 1217
    13. 8 org.qt-project.QtWidgets 0x000000010ba8439f QWidgetWindow::event(QEvent*) + 111
    14. 9 org.qt-project.QtWidgets 0x000000010ba2adbb QApplicationPrivate::notify_helper(QObject*, QEvent*) + 251
    15. 10 org.qt-project.QtWidgets 0x000000010ba2e110 QApplication::notify(QObject*, QEvent*) + 8192
    16. 11 org.qt-project.QtCore 0x000000010c8a6fb3 QCoreApplication::notifyInternal(QObject*, QEvent*) + 115
    17. 12 org.qt-project.QtGui 0x000000010c0e2d3d QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 2189
    18. 13 org.qt-project.QtGui 0x000000010c0e2671 QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 449
    19. 14 org.qt-project.QtGui 0x000000010c0e1bd3 QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent*) + 131
    20. 15 org.qt-project.QtGui 0x000000010c0cf51a QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 346
    21. 16 libqcocoa.dylib 0x000000010ecd36ff QCocoaEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 1631
    22. 17 com.example.DetachDockExample 0x000000010b9dd64f DetachableDockManager::eventFilter(QObject*, QEvent*) + 527 (DetachableDockManager.cpp:422)
    23. 18 org.qt-project.QtCore 0x000000010c8a72f9 QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) + 217
    24. 19 org.qt-project.QtWidgets 0x000000010ba2adab QApplicationPrivate::notify_helper(QObject*, QEvent*) + 235
    25. 20 org.qt-project.QtWidgets 0x000000010ba2e65f QApplication::notify(QObject*, QEvent*) + 9551
    26. 21 org.qt-project.QtCore 0x000000010c8a6fb3 QCoreApplication::notifyInternal(QObject*, QEvent*) + 115
    27. 22 org.qt-project.QtWidgets 0x000000010ba2b73b QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool) + 987
    28. 23 org.qt-project.QtWidgets 0x000000010ba85161 QWidgetWindow::handleMouseEvent(QMouseEvent*) + 1217
    29. 24 org.qt-project.QtWidgets 0x000000010ba8439f QWidgetWindow::event(QEvent*) + 111
    30. 25 org.qt-project.QtWidgets 0x000000010ba2adbb QApplicationPrivate::notify_helper(QObject*, QEvent*) + 251
    31. 26 org.qt-project.QtWidgets 0x000000010ba2e110 QApplication::notify(QObject*, QEvent*) + 8192
    32. 27 org.qt-project.QtCore 0x000000010c8a6fb3 QCoreApplication::notifyInternal(QObject*, QEvent*) + 115
    33. 28 org.qt-project.QtGui 0x000000010c0e2d3d QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 2189
    34. 29 org.qt-project.QtGui 0x000000010c0e2671 QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 449
    35. 30 org.qt-project.QtGui 0x000000010c0e1bd3 QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent*) + 131
    36. 31 org.qt-project.QtGui 0x000000010c0cf51a QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 346
    37. 32 org.qt-project.QtGui 0x000000010c0cd611 QWindowSystemInterface::flushWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 673
    38. 33 libqcocoa.dylib 0x000000010ecc9341 -[QNSView updateGeometry] + 545
    39. 34 com.apple.CoreFoundation 0x00007fff8c346e0c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    40. 35 com.apple.CoreFoundation 0x00007fff8c23a82d _CFXNotificationPost + 2893
    41. 36 com.apple.Foundation 0x00007fff91d15e4a -[NSNotificationCenter postNotificationName:object:userInfo:] + 68
    42. 37 com.apple.AppKit 0x00007fff8b0f6f81 -[NSWindow _setFrameCommon:display:stashSize:] + 1958
    43. 38 com.apple.AppKit 0x00007fff8b276492 __25-[NSWindow setStyleMask:]_block_invoke + 878
    44. 39 com.apple.AppKit 0x00007fff8b1001e8 NSPerformWithScreenUpdatesDisabled + 65
    45. 40 com.apple.AppKit 0x00007fff8b2760e5 -[NSWindow setStyleMask:] + 172
    46. 41 libqcocoa.dylib 0x000000010ecc4350 QCocoaWindow::setWindowFlags(QFlags<Qt::WindowType>) + 96
    47. 42 org.qt-project.QtGui 0x000000010c0ecfc3 QWindow::setFlags(QFlags<Qt::WindowType>) + 35
    48. 43 org.qt-project.QtWidgets 0x000000010ba582f9 QWidgetPrivate::create_sys(unsigned long long, bool, bool) + 649
    49. 44 org.qt-project.QtWidgets 0x000000010ba57119 QWidget::create(unsigned long long, bool, bool) + 425
    50. 45 org.qt-project.QtWidgets 0x000000010ba6cf14 QWidgetPrivate::setParent_sys(QWidget*, QFlags<Qt::WindowType>) + 1668
    51. 46 org.qt-project.QtWidgets 0x000000010ba576f8 QWidget::setParent(QWidget*, QFlags<Qt::WindowType>) + 952
    52. 47 org.qt-project.QtWidgets 0x000000010ba6c7be QWidgetPrivate::setWindowFlags(QFlags<Qt::WindowType>) + 158
    53. 48 org.qt-project.QtWidgets 0x000000010bb42263 QDockWidgetPrivate::setWindowState(bool, bool, QRect const&) + 307
    54. 49 org.qt-project.QtWidgets 0x000000010bb433b3 QDockWidget::setTitleBarWidget(QWidget*) + 115
    55. 50 com.example.DetachDockExample 0x000000010b9dc3dc DetachableDock::changeTitleBar(bool) + 60 (DetachableDock.cpp:44)
    56. 51 com.example.DetachDockExample 0x000000010b9dd08b DetachableDockManager::topLevelUpdateDock(DetachableDock*, DetachableDockManager::TopLevelChange) + 123 (DetachableDockManager.cpp:311)
    57. 52 com.example.DetachDockExample 0x000000010b9dcfb6 DetachableDockManager::onDockTopLevelChanged(bool) + 1302 (DetachableDockManager.cpp:179)
    58. 53 com.example.DetachDockExample 0x000000010b9e0992 DetachableDockManager::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) + 114 (moc_DetachableDockManager.cpp:83)
    59. 54 org.qt-project.QtCore 0x000000010c8d99db QMetaObject::activate(QObject*, int, int, void**) + 2987
    60. 55 org.qt-project.QtWidgets 0x000000010bb422e8 QDockWidgetPrivate::setWindowState(bool, bool, QRect const&) + 440
    61. 56 org.qt-project.QtWidgets 0x000000010bb41001 QDockWidget::setFloating(bool) + 209
    62. 57 com.example.DetachDockExample 0x000000010b9dd624 DetachableDockManager::eventFilter(QObject*, QEvent*) + 484 (DetachableDockManager.cpp:418)
    63. 58 org.qt-project.QtCore 0x000000010c8a72f9 QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) + 217
    64. 59 org.qt-project.QtWidgets 0x000000010ba2adab QApplicationPrivate::notify_helper(QObject*, QEvent*) + 235
    65. 60 org.qt-project.QtWidgets 0x000000010ba2e65f QApplication::notify(QObject*, QEvent*) + 9551
    66. 61 org.qt-project.QtCore 0x000000010c8a6fb3 QCoreApplication::notifyInternal(QObject*, QEvent*) + 115
    67. 62 org.qt-project.QtWidgets 0x000000010ba2b73b QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool) + 987
    68. 63 org.qt-project.QtWidgets 0x000000010ba85161 QWidgetWindow::handleMouseEvent(QMouseEvent*) + 1217
    69. 64 org.qt-project.QtWidgets 0x000000010ba8439f QWidgetWindow::event(QEvent*) + 111
    70. 65 org.qt-project.QtWidgets 0x000000010ba2adbb QApplicationPrivate::notify_helper(QObject*, QEvent*) + 251
    71. 66 org.qt-project.QtWidgets 0x000000010ba2e110 QApplication::notify(QObject*, QEvent*) + 8192
    72. 67 org.qt-project.QtCore 0x000000010c8a6fb3 QCoreApplication::notifyInternal(QObject*, QEvent*) + 115
    73. 68 org.qt-project.QtGui 0x000000010c0e2d3d QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 2189
    74. 69 org.qt-project.QtGui 0x000000010c0e2671 QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 449
    75.  
    76. ... continued (Please check the attached text to see the full stack trace)
    To copy to clipboard, switch view to plain text mode 
    Attached Files Attached Files

  17. The following user says thank you to shinichy for this useful post:

    Kryzon (31st January 2015)

  18. #15
    Join Date
    Oct 2014
    Posts
    81
    Thanks
    20
    Thanked 9 Times in 9 Posts
    Qt products
    Qt5
    Platforms
    Windows
    Wiki edits
    7

    Default Re: [SOLVED] Detachable QDockWidget tabs

    Do you know what code line caused the crash?
    I would keep the global coordinates, since it's the correct way. I don't think they're influencing the warning or the crash.

    I'm not sure how to fix this on OS X since I don't have a system to test it on. It must have to do with the order or the events.
    The warning is created here:
    https://qt.gitorious.org/qt/qtbase/s...nsview.mm#L765

    It probably has to do with us sending a synthetic mouse release event while the button is down, even if it's just for a quick moment, and then moving the cursor with setPos(), which causes a mouse drag event with an invalid button.

    I'll try to think of a different event order. If I'm not mistaken the crash happens in that block that detaches the dock, inside the event filter?

  19. #16
    Join Date
    Nov 2014
    Posts
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: [SOLVED] Detachable QDockWidget tabs

    The crash happens below line. I can't step into further because I can't attach Qt source code in my Qt Creator.

    Qt Code:
    1. detachingDock->setFloating( true );
    To copy to clipboard, switch view to plain text mode 

    I added debug messages around that line, then I got the following output.

    Qt Code:
    1. qDebug("before setFloating");
    2. detachingDock->setFloating( true );
    3. qDebug("after setFloating");
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. Starting /Users/shinichi/Code/build-DetachDockExample-Desktop_Qt_5_4_0_clang_64bit-Debug/DetachDockExample.app/Contents/MacOS/DetachDockExample...
    2. before setFloating
    3. after setFloating
    4. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    5. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    6. before setFloating
    7. before setFloating
    8. after setFloating
    9. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    10. before setFloating
    11. before setFloating
    12. after setFloating
    13. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    14. before setFloating
    15. The program has unexpectedly finished.
    To copy to clipboard, switch view to plain text mode 

  20. #17
    Join Date
    Oct 2014
    Posts
    81
    Thanks
    20
    Thanked 9 Times in 9 Posts
    Qt products
    Qt5
    Platforms
    Windows
    Wiki edits
    7

    Default Re: [SOLVED] Detachable QDockWidget tabs

    Thank you for the information.
    I've changed the event order when the dock is detached. It still works under Windows XP, so hopefully it works now on OS X.

    I noticed a title bar bug when undocking on a certain occasion, but I've been unable to reproduce it. So there may be improvements left to be made to this system.

    The new event order in DetachableDockManager::eventFilter is as below:

    Qt Code:
    1. if ( ( mouseEvent->pos() - clickPos ).manhattanLength() > QApplication::startDragDistance() )
    2. {
    3. // The user wants to detach a dock tab.
    4.  
    5. if ( pressedTabIndex != -1 )
    6. {
    7. consumed = true;
    8.  
    9. // *** Trying a different event order to avoid a crash on OS X.
    10.  
    11. QApplication::processEvents(); // Process all pending events to start with a clean queue.
    12.  
    13. /* It is essential to release the mouse button that is currently holding on to the tab bar
    14. so that the dock widget can be dragged. This needs to be done with an OS level event. */
    15.  
    16. #ifdef Q_OS_WIN
    17.  
    18. // On Windows we use relative mouse coordinates.
    19.  
    20. sendOSMouseEvent( SynthMouseEvent::MouseRelease, 0, 0 );
    21.  
    22. #endif
    23.  
    24. #ifdef Q_OS_OSX
    25.  
    26. // On OS X we use absolute mouse coordinates.
    27.  
    28. QPoint cursorPos = QCursor::pos();
    29. sendOSMouseEvent( SynthMouseEvent::MouseRelease, cursorPos.x(), cursorPos.y() );
    30.  
    31. #endif
    32.  
    33. /* Detach the dock that the user wants.
    34. This restores the default title bar from the top level change, and also
    35. restores the title bar of its tab bar neighbour if they were in a two-page tab bar. */
    36.  
    37. DetachableDock* detachingDock = dockFromTab( pressedTabBar, pressedTabIndex );
    38. detachingDock->setFloating( true );
    39.  
    40. // Process events right after floating the dock to avoid an animation glitch.
    41.  
    42. QApplication::processEvents();
    43.  
    44. // Centre the dock title bar on the latest cursor position so the mouse press doesn't miss it.
    45.  
    46. detachingDock->centreTitle( QCursor::pos() );
    47.  
    48. // OPTIONAL. Process events again after centering the dock so it's redrawn immediately.
    49.  
    50. QApplication::processEvents();
    51.  
    52. // Synthesize a mouse press to grab the dock that is placed on the cursor, so it can be dragged.
    53.  
    54. #ifdef Q_OS_WIN
    55. sendOSMouseEvent( SynthMouseEvent::MousePress, 0, 0 );
    56. #endif
    57.  
    58. #ifdef Q_OS_OSX
    59. sendOSMouseEvent( SynthMouseEvent::MousePress, cursorPos.x(), cursorPos.y() );
    60. #endif
    61. QApplication::processEvents(); // Make sure that these events are processed right now to avoid surprises.
    62. }
    63. }
    To copy to clipboard, switch view to plain text mode 
    If it still doesn't work, try adding a 'QApplication::processEvents()' call right before the 'detachingDock->setFloating( true )' call.

    You can also download the full project with these modifications, as attached.
    Attached Files Attached Files

  21. #18
    Join Date
    Nov 2014
    Posts
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: [SOLVED] Detachable QDockWidget tabs

    I tried your new project but it still doesn't work. Even with 'QApplication:rocessEvents()' call right before the 'detachingDock->setFloating( true )' call.
    Here's the output and the stack trace. Both seem same as before.

    Qt Code:
    1. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    2. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    3. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    4. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    5. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    6. QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
    7. The program has unexpectedly finished.
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
    2. 0 org.qt-project.QtWidgets 0x000000010e950f47 QDockWidget::setFloating(bool) + 23
    3. 1 com.example.DetachDockExample 0x000000010e7f16e0 DetachableDockManager::eventFilter(QObject*, QEvent*) + 528
    4. 2 org.qt-project.QtCore 0x000000010f6b62f9 QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) + 217
    5. 3 org.qt-project.QtWidgets 0x000000010e83adab QApplicationPrivate::notify_helper(QObject*, QEvent*) + 235
    6. 4 org.qt-project.QtWidgets 0x000000010e83e65f QApplication::notify(QObject*, QEvent*) + 9551
    7. 5 org.qt-project.QtCore 0x000000010f6b5fb3 QCoreApplication::notifyInternal(QObject*, QEvent*) + 115
    8. 6 org.qt-project.QtWidgets 0x000000010e83b73b QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool) + 987
    9. 7 org.qt-project.QtWidgets 0x000000010e895161 QWidgetWindow::handleMouseEvent(QMouseEvent*) + 1217
    10. 8 org.qt-project.QtWidgets 0x000000010e89439f QWidgetWindow::event(QEvent*) + 111
    11. 9 org.qt-project.QtWidgets 0x000000010e83adbb QApplicationPrivate::notify_helper(QObject*, QEvent*) + 251
    12. 10 org.qt-project.QtWidgets 0x000000010e83e110 QApplication::notify(QObject*, QEvent*) + 8192
    13. 11 org.qt-project.QtCore 0x000000010f6b5fb3 QCoreApplication::notifyInternal(QObject*, QEvent*) + 115
    14. 12 org.qt-project.QtGui 0x000000010eeeed3d QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 2189
    15. 13 org.qt-project.QtGui 0x000000010eeee671 QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 449
    16. 14 org.qt-project.QtGui 0x000000010eeedbd3 QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent*) + 131
    17. 15 org.qt-project.QtGui 0x000000010eedb51a QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 346
    18. 16 libqcocoa.dylib 0x0000000111adb6ff QCocoaEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 1631
    19. 17 com.example.DetachDockExample 0x000000010e7f166c DetachableDockManager::eventFilter(QObject*, QEvent*) + 412
    20. 18 org.qt-project.QtCore 0x000000010f6b62f9 QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) + 217
    21. 19 org.qt-project.QtWidgets 0x000000010e83adab QApplicationPrivate::notify_helper(QObject*, QEvent*) + 235
    22. 20 org.qt-project.QtWidgets 0x000000010e83e65f QApplication::notify(QObject*, QEvent*) + 9551
    23. 21 org.qt-project.QtCore 0x000000010f6b5fb3 QCoreApplication::notifyInternal(QObject*, QEvent*) + 115
    24. 22 org.qt-project.QtWidgets 0x000000010e83b73b QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool) + 987
    25. 23 org.qt-project.QtWidgets 0x000000010e895161 QWidgetWindow::handleMouseEvent(QMouseEvent*) + 1217
    26. 24 org.qt-project.QtWidgets 0x000000010e89439f QWidgetWindow::event(QEvent*) + 111
    27. 25 org.qt-project.QtWidgets 0x000000010e83adbb QApplicationPrivate::notify_helper(QObject*, QEvent*) + 251
    28. 26 org.qt-project.QtWidgets 0x000000010e83e110 QApplication::notify(QObject*, QEvent*) + 8192
    29. 27 org.qt-project.QtCore 0x000000010f6b5fb3 QCoreApplication::notifyInternal(QObject*, QEvent*) + 115
    30. 28 org.qt-project.QtGui 0x000000010eeeed3d QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 2189
    31. 29 org.qt-project.QtGui 0x000000010eeee671 QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 449
    32. 30 org.qt-project.QtGui 0x000000010eeedbd3 QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent*) + 131
    33. 31 org.qt-project.QtGui 0x000000010eedb51a QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 346
    34. 32 libqcocoa.dylib 0x0000000111adb6ff QCocoaEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 1631
    35. 33 com.example.DetachDockExample 0x000000010e7f16fc DetachableDockManager::eventFilter(QObject*, QEvent*) + 556
    36. 34 org.qt-project.QtCore 0x000000010f6b62f9 QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) + 217
    37. 35 org.qt-project.QtWidgets 0x000000010e83adab QApplicationPrivate::notify_helper(QObject*, QEvent*) + 235
    38. 36 org.qt-project.QtWidgets 0x000000010e83e65f QApplication::notify(QObject*, QEvent*) + 9551
    39. 37 org.qt-project.QtCore 0x000000010f6b5fb3 QCoreApplication::notifyInternal(QObject*, QEvent*) + 115
    40. 38 org.qt-project.QtWidgets 0x000000010e83b73b QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool) + 987
    41. 39 org.qt-project.QtWidgets 0x000000010e895161 QWidgetWindow::handleMouseEvent(QMouseEvent*) + 1217
    42. 40 org.qt-project.QtWidgets 0x000000010e89439f QWidgetWindow::event(QEvent*) + 111
    43. 41 org.qt-project.QtWidgets 0x000000010e83adbb QApplicationPrivate::notify_helper(QObject*, QEvent*) + 251
    44. 42 org.qt-project.QtWidgets 0x000000010e83e110 QApplication::notify(QObject*, QEvent*) + 8192
    45. 43 org.qt-project.QtCore 0x000000010f6b5fb3 QCoreApplication::notifyInternal(QObject*, QEvent*) + 115
    46. 44 org.qt-project.QtGui 0x000000010eeeed3d QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 2189
    47. 45 org.qt-project.QtGui 0x000000010eeee671 QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 449
    48. 46 org.qt-project.QtGui 0x000000010eeedbd3 QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent*) + 131
    49. 47 org.qt-project.QtGui 0x000000010eedb51a QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 346
    50. 48 libqcocoa.dylib 0x0000000111adb6ff QCocoaEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 1631
    51. 49 com.example.DetachDockExample 0x000000010e7f166c DetachableDockManager::eventFilter(QObject*, QEvent*) + 412
    52. 50 org.qt-project.QtCore 0x000000010f6b62f9 QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) + 217
    53. ...
    To copy to clipboard, switch view to plain text mode 

  22. #19
    Join Date
    Oct 2014
    Posts
    81
    Thanks
    20
    Thanked 9 Times in 9 Posts
    Qt products
    Qt5
    Platforms
    Windows
    Wiki edits
    7

    Default Re: [SOLVED] Detachable QDockWidget tabs

    From my observations on Windows, floating the dock only crashes the program if the tab bar still has the mouse focus when this happens. That is, the mouse release event for it isn't being recognised properly for some reason.

    I'll have to rely on someone's OS X expertise on this one, it's difficult to remotely debug.
    If you happen to find a solution by experimenting, please share it.

    Regards.

  23. #20
    Join Date
    Oct 2014
    Posts
    81
    Thanks
    20
    Thanked 9 Times in 9 Posts
    Qt products
    Qt5
    Platforms
    Windows
    Wiki edits
    7

    Default Re: [SOLVED] Detachable QDockWidget tabs

    Hello. Here's another try.
    I noticed that a synthesised mouse movement event is necessary to avoid having a miss-click when trying to grab the dock widget when the user is dragging the mouse really fast.
    In order to avoid that warning message on OS X, we can try to synthesize a mouse drag event with the left button set as "pressed." We can also test if the tab bar still has mouse focus after the synthesised mouse release, as a debugging measure.

    Modifications were made to the following files:

    - DetachableDockManager.cpp
    - SendOSMouseEvent.h
    - SendOSMouseEvent.mm
    - SyntheticMouseEvent.cpp

    The full project is attached.
    Attached Files Attached Files

Similar Threads

  1. QDockWidget + QTabBar, but tabs don't move
    By NIteLordz in forum Qt Programming
    Replies: 11
    Last Post: 22nd January 2015, 17:06
  2. Area for detachable QDialogs within QGridLayout
    By nicole.cpp in forum Newbie
    Replies: 3
    Last Post: 15th April 2014, 17:02
  3. Dragable QDockWidget tabs with no title bar?
    By nige in forum Qt Programming
    Replies: 1
    Last Post: 17th April 2013, 15:39
  4. Replies: 7
    Last Post: 8th April 2009, 08:42
  5. [SOLVED] QDockWidget::setVisible() doesn't work
    By Oleg in forum Qt Programming
    Replies: 2
    Last Post: 4th January 2008, 20:27

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.