1

I try to toggle a splitter container between two widgets keeping the actual size of the splitter. For this I use QSplitter.sizes() to read the actual size and QSplitter.setSizes() after I toggle my widgets.

The problem is that I have a QToolButton which I resize with setFixedSize() in a resizeEvent(), and because of this when I set the new size, it often doesn't work.

I write a little script to reproduce this : In the left part of the splitter, I have a button to toggle the right part of the splitter between two classes (which are QWidgets).

A little precision : I want to keep my QToolbutton in a 1:1 aspect ratio.

Here a demo : https://webmshare.com/play/5Bmvn

So here the script :

from PyQt4 import QtGui, QtCore

minSize = 50
maxSize = 350

class mainWindow(QtGui.QWidget):
    def __init__(self):
        super(mainWindow, self).__init__()

        self.layout = QtGui.QVBoxLayout(self)

        self.splitter = QtGui.QSplitter(QtCore.Qt.Horizontal, self)
        self.splitter.setHandleWidth(20)
        self.layout.addWidget(self.splitter)

        wgt_left = QtGui.QWidget()
        lyt_left = QtGui.QVBoxLayout(wgt_left)

        self.btn_toggleSplitter = QtGui.QPushButton('Toggle Button')
        self.btn_toggleSplitter.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding)
        self.btn_toggleSplitter.setCheckable(True)
        lyt_left.addWidget(self.btn_toggleSplitter)

        self.splitter.addWidget(wgt_left)

        self.first = panel('1')
        self.second = panel('2')
        self.splitter.addWidget(self.first)

        self.width = self.first.size()


        self.btn_toggleSplitter.clicked.connect(self.ToggleParent)

    def ToggleParent(self):
        self.sizes = self.splitter.sizes()

        if self.btn_toggleSplitter.isChecked() == True:
            self.first.setParent(None)
            self.splitter.addWidget(self.second)

        else :
            self.second.setParent(None)
            self.splitter.addWidget(self.first)

        self.splitter.setSizes(self.sizes)


class panel(QtGui.QWidget):
    def __init__(self, text):
        super(panel, self).__init__()

        lyt_main = QtGui.QVBoxLayout(self)

        lyt_icon = QtGui.QHBoxLayout()

        self.tbtn_icon = QtGui.QToolButton()
        self.tbtn_icon.setText(text)

        self.tbtn_icon.setMinimumSize(QtCore.QSize(minSize,minSize))
        self.tbtn_icon.setMaximumSize(QtCore.QSize(maxSize,maxSize))
        lyt_icon.addWidget(self.tbtn_icon)

        lyt_horizontal = QtGui.QHBoxLayout()
        lyt_horizontal.addWidget(QtGui.QPushButton('3'))
        lyt_horizontal.addWidget(QtGui.QPushButton('4'))

        lyt_main.addWidget(QtGui.QLabel('Below me is the QToolButton'))
        lyt_main.addLayout(lyt_icon)
        lyt_main.addLayout(lyt_horizontal)
        lyt_main.addWidget(QtGui.QPlainTextEdit())


    def resizeEvent(self, event):
        w = panel.size(self).width()
        h = panel.size(self).height()
        size = min(h, w)-22
        if size >= maxSize:
            size = maxSize
        elif size <= minSize:
            size = minSize

        self.tbtn_icon.setFixedSize(size, size)


app = QtGui.QApplication([])
window = mainWindow()
window.resize(600,300)
window.show()
app.exec_()

Thanks

  • It's actually my first paragraph : I want to toggle a splitter container between two widgets while keeping the actual size of the splitter. The widgets are QToolbuttons with a resizeEvent. – Cuissedemouche Dec 03 '18 at 00:04
  • I wanted to keep the square aspect ratio, but yes you are write because I just figured out that I can just take the width of the widget then set the height with it ! Thanks. – Cuissedemouche Dec 03 '18 at 09:59
  • It's difficult to write code in a comment so here a link with the modifications : https://pastebin.com/FNxNqpf7. I hope it will be easier to understand me with it. I still have one problem with this method (that I already had before). When I resize the splitter, if my window is small, it will resize the window according to the QToolButton, and I can't decreased the size of my window. I want to have the possibility to resize the QToolButton when I decrease the window size height. – Cuissedemouche Dec 03 '18 at 10:27
  • Sorry, I really don't know to explain myself in a better way. I want to keep the aspect ratio of my QToolButton. By constraining the height by the width, I can keep it but I can't resize the windows correctly. I made a small demo : https://webmshare.com/play/KA6BV – Cuissedemouche Dec 03 '18 at 10:41
  • This video has nothing to do with my example or with the example that you posted in your question, if you modify I can not help you. please read [ask] and pass the [tour], you can not change the game rules every time, if you want help then provide a [mcve] – eyllanesc Dec 03 '18 at 11:17
  • I maybe simplified too much my script test, what I normally have is a panel with buttons and labels, and the QToolButton I have in my script test. Your script keep well the aspect ratio, but remove the horizontal center of the widget. it also overlapping with other widgets (that yes I remove in this example sorry). I'll just edit my original post to add a button. – Cuissedemouche Dec 03 '18 at 11:27
  • 1
    Do not simplify your problem too much if you do not know how to create an [mcve], if you are going to modify it every time you cause us to get bored in helping you, remember that our work is voluntary, so you will have to make an effort and take the time to provide a [mcve] . So when you do, you let me know. – eyllanesc Dec 03 '18 at 11:30
  • I edited it. I remove the fix button (that I first put to be understand but it was not relevant), remove one class because it was useless for this example, and add some widgets to the right panel. I kept the original problem I had in my script. And again thanks for your help. – Cuissedemouche Dec 03 '18 at 11:54
  • Then I will assume that if I solve the problem   current will no longer indicate another problem – eyllanesc Dec 03 '18 at 11:56
  • why `22` in `size = min(h, w)-22`? – eyllanesc Dec 03 '18 at 11:57
  • The "-22" was to remove the layout margin which are 11 by default. And yes it will solve the problem. – Cuissedemouche Dec 03 '18 at 12:03

1 Answers1

1

You are looking for QtGui.QStackedWidget. Adding the widgets to this on the right side of your splitter will change the code around self.first and self.second's construction to this:

    self.stack_right = QtGui.QStackedWidget()
    self.splitter.addWidget(self.stack_right)

    self.first = panel('1')
    self.second = panel('2')
    self.stack_right.addWidet(self.first)
    self.stack_right.addWidget(self.second)

Then your ToggleParent method:

def ToggleParent(self):
    if self.btn_toggleSplitter.isChecked() == True:
        self.stack_right.setCurrentWidget(self.second)
    else:
        self.stack_right.setCurrentWidget(self.first)

This will avoid the awkwardness of caching and manually resizing your widgets.

Addendum: The tool button scaling is really a separate question, but here's a tip:

Have a look at the heightForWidth layout setting for lyt_left. This will help you keep a 1:1 ratio for the QToolButton. You currently have a size policy of Preferred/Expanding, which doesn't make sense if you need a 1:1 aspect ratio. I highly recommend this over manually resizing the tool button while handling an event. Generally, calling setFixedSize more than once on a widget should be considered a last resort. Let the layouts do the work.

Addendum to addendum: doing a little poking (it's been awhile), you may need to inherit from QToolButton and reimplement the hasHeightForWidth() and heightForWidth() methods. There are a plethora of questions addressing the subject here. Just search for heightForWidth.

jonspaceharper
  • 4,207
  • 2
  • 22
  • 42
  • Ok thank you very much. I didn't know QStackedWidget. I'll give a look to heighForWidth as you suggested. – Cuissedemouche Dec 03 '18 at 12:40
  • Ok I watch it a bit and now as you said it's a total other problem. Have a 1:1 widget with other widgets which expand (like the QPlainTextEdit in my example). I'll search an answer for that. Thanks again. – Cuissedemouche Dec 03 '18 at 17:21