Question

You can customize the thickness and background image of the splitter handle

http://qt-project.org/doc/qt-4.8/stylesheet-examples.html#customizing-qsplitter

But is there a way to add a small graphical arrow button so when the user clicks on it, I can call splitter.setSizes([0, 1]) to collapse it.

collapsebutton

I could use a vbox layout with a QButton but it takes up too much space and doesn't look as nice.

Was it helpful?

Solution

You could subclass QSplitter and reimplement its createHandle method. This would allow you to return an instance of your own QSplitterHandle class, with, say, a reimplemented paintEvent.

Alternatively, and more simply, you could add buttons directly to an existing splitter handle, by setting your own layout on it.

Here's a basic demo to get you started (probably needs some tweaking to make it prettier):

PyQt5:

from PyQt5 import QtCore, QtWidgets

class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.splitter = QtWidgets.QSplitter(self)
        self.splitter.addWidget(QtWidgets.QTextEdit(self))
        self.splitter.addWidget(QtWidgets.QTextEdit(self))
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.splitter)
        handle = self.splitter.handle(1)
        layout = QtWidgets.QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        button = QtWidgets.QToolButton(handle)
        button.setArrowType(QtCore.Qt.LeftArrow)
        button.clicked.connect(
            lambda: self.handleSplitterButton(True))
        layout.addWidget(button)
        button = QtWidgets.QToolButton(handle)
        button.setArrowType(QtCore.Qt.RightArrow)
        button.clicked.connect(
            lambda: self.handleSplitterButton(False))
        layout.addWidget(button)
        handle.setLayout(layout)

    def handleSplitterButton(self, left=True):
        if not all(self.splitter.sizes()):
            self.splitter.setSizes([1, 1])
        elif left:
            self.splitter.setSizes([0, 1])
        else:
            self.splitter.setSizes([1, 0])

if __name__ == '__main__':

    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 300, 300)
    window.show()
    sys.exit(app.exec_())

PyQt4:

from PyQt4 import QtCore, QtGui

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.splitter = QtGui.QSplitter(self)
        self.splitter.addWidget(QtGui.QTextEdit(self))
        self.splitter.addWidget(QtGui.QTextEdit(self))
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.splitter)
        handle = self.splitter.handle(1)
        layout = QtGui.QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        button = QtGui.QToolButton(handle)
        button.setArrowType(QtCore.Qt.LeftArrow)
        button.clicked.connect(
            lambda: self.handleSplitterButton(True))
        layout.addWidget(button)
        button = QtGui.QToolButton(handle)
        button.setArrowType(QtCore.Qt.RightArrow)
        button.clicked.connect(
            lambda: self.handleSplitterButton(False))
        layout.addWidget(button)
        handle.setLayout(layout)

    def handleSplitterButton(self, left=True):
        if not all(self.splitter.sizes()):
            self.splitter.setSizes([1, 1])
        elif left:
            self.splitter.setSizes([0, 1])
        else:
            self.splitter.setSizes([1, 0])

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 300, 300)
    window.show()
    sys.exit(app.exec_())
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top