Important: Please read the Qt Code of Conduct -

Replacing a widget with another one containing splitter

  • Hi,
    I’m looking into an odd issue on BoxLayout.replaceWidget in PyQt5.9
    It would be great if anybody would point me to a right direction.

    I have the following sandbox code and the goal is to split one of the exiting widget into two widgets (on one widget) without changing the other widget in the initial screen.
    The idea is to replace existing widget with another widget which contains both a new widget and the existing widget with a splitter.
    In split_widget(), it returns a splitter with new widget and the existing one.
    And then, main class App.split_wgt() performs the replacement by calling self.layoutV.replaceWidget(self.canvas, container_wgt).
    The problem is the replaced widget size is too big. I expect the replacement area is the same size as the original widget’s width&height, but containing additional widget. As a result, each new item should have 1/2 height of the original widget.
    Why I can’t control the replacement area??

    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    import sys
    class BaseClass(QFrame):
        def __init__(self, base=None, parent=None):
            super(BaseClass, self).__init__(parent)
            self.parent = parent
            self.base = base
            self.mouse_pos = QPoint()
        def mouseMoveEvent(self, event):
            self.mouse_pos = event.pos()
        def mousePressEvent(self, event):
            print('mouse pressed at ', event.pos().x(), ',', event.pos().y())
            if event.pos().y() > self.height() /2:
                print("Bottom insert")
                self.base.split_signal.emit(self, 'B')
                print("Top insert")
                self.base.split_signal.emit(self, 'T')
    class App(QWidget):
        split_signal = pyqtSignal(object, object)
        def __init__(self):
            self.setGeometry(50, 50, 500, 600)
            self.layoutV = QVBoxLayout()
            # Upper
            self.upper_widget = QFrame()
            self.pb = QPushButton('top', self.upper_widget)
            self.pb.resize(self.upper_widget.width(), self.upper_widget.height())
            # Lower
            self.canvas = QWidget()
        def place_base(self):
            container_wgt = BaseClass(base=self, parent=self.canvas)   # Container widget
            container_wgt.resize(self.canvas.width(), self.canvas.height())
        @pyqtSlot(object, object)
        def split_wgt(self, wgt, orientation):
            if orientation =='T':
                container_wgt = QWidget()
                self.new_wgt = BaseClass(base=self, parent=container_wgt)
                new_items_spltr = self.split_widget(wgt, self.new_wgt, 'V')
                self.new_layout = QVBoxLayout()
                self.new_splitter = QSplitter(Qt.Vertical)
                aaa = self.layoutV.replaceWidget(self.canvas, container_wgt)
        def destroy_layout(self, wgt):
            www = wgt.layout()
            QWidget().setLayout(wgt.layout())  # remove the wgt's layout
        def split_widget(self, current_wgt, new_wgt, spltr):
            splitter = QSplitter(Qt.Vertical) if spltr == 'V' else QSplitter(Qt.Horizontal)
            current_wgt.resize(current_wgt.width() /2, current_wgt.height() /2)
            new_wgt.resize(current_wgt.width() /2, current_wgt.height() /2)
            return splitter
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        ex = App()

    Many thanks in advance for your help.


  • Lifetime Qt Champion


    Wouldn't QSplitter::setSizes do what you want ?

  • Thanks for an update, SGaist.

    Yes, it's what I wanted! but not 100%. I still have an issue on positioning a splitter on my "main widget".
    To isolate widgets, I place each splitter on different widget(let's say container widget) on the main widget, which is something like a main window or canvas. That's safe on building complex layouts as every widget is isolated.
    Looks like the isolation doesn't work when I replace an existing widget with new one containing QSplitter...

    What I want to achieve is like this. Click on a widget splits the widget either vertically or horizontally based on the click position.

    The current problem is that the main widget shows a different behavior when I place a container widget with qsplitter. Non-splitter on the container widget can position appropriately on the main widget but qsplitter container widget can't.
    I guess there should be something I'm missing when I position a widget containing QSplitter, but have no idea what it is... :<

    Any ideas?


  • This post is deleted!

  • @ShinSat By the way, I'm also looking for a framework which helps me implement thisw whether it's paid one or not.
    Does anybody know some frameworks?


  • Lifetime Qt Champion

    What behaviour do you get with QSplitter ?

Log in to reply