How to make QSplitter responds to double clicking?

Heads up! You've already completed this tutorial.

Scoodood | 2020-09-25 05:16:36 UTC | #1

The default QSplitter Widget only has splitterMoved signal. I would like to add a doubleClicked signal so that I can make the QSplitter widget can move all the way to the left on a double clicking event, and then double clicking it again will restore to its previous position. Below are my starter code. Any idea how to go from here?

python
from PySide2 import QtWidgets, QtCore

class Example(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()      
        splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
        textedit1 = QtWidgets.QTextEdit()
        textedit2 = QtWidgets.QTextEdit()
        splitter.addWidget(textedit1)
        splitter.addWidget(textedit2)
        splitter.setSizes([200,200])
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(splitter)
        self.setLayout(layout)        
        splitter.splitterMoved.connect(self.handler)

        # trying to do something like this...
        #splitter.doubleClicked.connect(self.handler)

    def handler(self, pos):
        print('pos', pos)

if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    w = Example()
    w.show()
    app.exec_()

martin | 2020-09-30 20:45:37 UTC | #2

Hey @Scoodood I knocked together a simple custom widget for this -- it implements a double click event handler which stores and restores a slide position.

python

class ToggleSplitter(QtWidgets.QSplitter):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Store the previos size of the left hand panel.
        self._previous_state = None

    def mouseDoubleClickEvent(self, e):
        sizes = self.sizes()
        if sizes[0] == 0 and self._previous_state:
            sizes = self._previous_state
        else:
            # Store the size so we can return to it.
            self._previous_state = sizes[:] # store copy so change below doesn't affect stored.
            sizes[0] = 0

        self.setSizes(sizes)

If you run it you'll notice the slight problem -- you can't actually double click on the splitter itself, just on the (tiny space) in the frame next to it. Move your mouse around the edge of the splitter until it turns into an arrow, then double click.

The problem is that QSplitter is a compound widget with the handles themselves QSplitterHandle objects. However, QSplitter has a createHandle method we can override allowing us to return our own custom handles -- and we can put our double-click handler on there instead.

Full working example ...

Over 15,000 developers have bought Create GUI Applications with Python & Qt!
Create GUI Applications with Python & Qt6
Take a look

Downloadable ebook (PDF, ePub) & Complete Source code

Also available from Leanpub and Amazon Paperback

[[ discount.discount_pc ]]% OFF for the next [[ discount.duration ]] [[discount.description ]] with the code [[ discount.coupon_code ]]

Purchasing Power Parity

Developers in [[ country ]] get [[ discount.discount_pc ]]% OFF on all books & courses with code [[ discount.coupon_code ]]

python
from PySide2 import QtWidgets, QtCore



class ToggleSplitterHandle(QtWidgets.QSplitterHandle):

    def mouseDoubleClickEvent(self, e):
        self.parent().toggle_collapse()


class ToggleSplitter(QtWidgets.QSplitter):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Store the previos size of the left hand panel.
        self._previous_state = None

    def createHandle(self):
        return ToggleSplitterHandle(self.orientation(), self)

    def toggle_collapse(self):
        sizes = self.sizes()
        if sizes[0] == 0 and self._previous_state:
            sizes = self._previous_state
        else:
            # Store the size so we can return to it.
            self._previous_state = sizes[:] # store copy so change below doesn't affect stored.
            sizes[0] = 0

        self.setSizes(sizes)



class Example(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()      
        splitter = ToggleSplitter(QtCore.Qt.Horizontal)
        textedit1 = QtWidgets.QTextEdit()
        textedit2 = QtWidgets.QTextEdit()
        splitter.addWidget(textedit1)
        splitter.addWidget(textedit2)
        splitter.setSizes([200,200])
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(splitter)
        self.setLayout(layout)        
        splitter.splitterMoved.connect(self.handler)

    def handler(self, pos):
        print('pos', pos)

if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    w = Example()
    w.show()
    app.exec_()

Scoodood | 2020-09-30 20:59:09 UTC | #3

PyQt/PySide 1:1 Coaching with Martin Fitzpatrick — Save yourself time and frustration. Get one on one help with your Python GUI projects. Working together with you I'll identify issues and suggest fixes, from bugs and usability to architecture and maintainability.

Book Now 60 mins ($195)

Thanks @martin. This is awesome!!

Packaging Python Applications with PyInstaller by Martin Fitzpatrick — This step-by-step guide walks you through packaging your own Python applications from simple examples to complete installers and signed executables.

More info Get the book


Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak
Martin Fitzpatrick

How to make QSplitter responds to double clicking? was written by Martin Fitzpatrick .

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt. Martin founded PythonGUIs to provide easy to follow GUI programming tutorials to the Python community. He has written a number of popular Python books on the subject.