I wonder if you can adapt the borderlayout class to the wxpython phoenix library?

from PyQt5.QtCore import QRect, QSize, Qt
from PyQt5.QtWidgets import (QApplication, QFrame, QLabel, QLayout,
                             QTextBrowser, QWidget, QWidgetItem)


class ItemWrapper(object):
    def __init__(self, i, p):
        self.item = i
        self.position = p
class BorderLayout(QLayout):
    West, North, South, East, Center = range(5)
    MinimumSize, SizeHint = range(2)

    def __init__(self, parent=None, margin=None, spacing=-1):
        super(BorderLayout, self).__init__(parent)

        if margin is not None:
            self.setContentsMargins(margin, margin, margin, margin)

        self.setSpacing(spacing)
        self.list = []

    def __del__(self):
        l = self.takeAt(0)
        while l is not None:
            l = self.takeAt(0)

    def addItem(self, item):
        self.add(item, self.West)

    def addWidget(self, widget, position):
        self.add(QWidgetItem(widget), position)

    def expandingDirections(self):
        return Qt.Horizontal | Qt.Vertical

    def hasHeightForWidth(self):
        return False

    def count(self):
        return len(self.list)

    def itemAt(self, index):
        if index < len(self.list):
            return self.list[index].item

        return None

    def minimumSize(self):
        return self.calculateSize(self.MinimumSize)

    def setGeometry(self, rect):
        center = None
        eastWidth = 0
        westWidth = 0
        northHeight = 0
        southHeight = 0
        centerHeight = 0

        super(BorderLayout, self).setGeometry(rect)

        for wrapper in self.list:
            item = wrapper.item
            position = wrapper.position

            if position == self.North:
                item.setGeometry(QRect(rect.x(), northHeight,
                                       rect.width(), item.sizeHint().height()))

                northHeight += item.geometry().height() + self.spacing()

            elif position == self.South:
                item.setGeometry(QRect(item.geometry().x(),
                                       item.geometry().y(), rect.width(),
                                       item.sizeHint().height()))

                southHeight += item.geometry().height() + self.spacing()

                item.setGeometry(QRect(rect.x(),
                                       rect.y() + rect.height() - southHeight + self.spacing(),
                                       item.geometry().width(), item.geometry().height()))

            elif position == self.Center:
                center = wrapper

        centerHeight = rect.height() - northHeight - southHeight

        for wrapper in self.list:
            item = wrapper.item
            position = wrapper.position

            if position == self.West:
                item.setGeometry(QRect(rect.x() + westWidth,
                                       northHeight, item.sizeHint().width(), centerHeight))

                westWidth += item.geometry().width() + self.spacing()

            elif position == self.East:
                item.setGeometry(QRect(item.geometry().x(),
                                       item.geometry().y(), item.sizeHint().width(),
                                       centerHeight))

                eastWidth += item.geometry().width() + self.spacing()

                item.setGeometry(QRect(rect.x() + rect.width() - eastWidth + self.spacing(),
                                       northHeight, item.geometry().width(),
                                       item.geometry().height()))

        if center:
            center.item.setGeometry(QRect(westWidth, northHeight,
                                          rect.width() - eastWidth - westWidth, centerHeight))

    def sizeHint(self):
        return self.calculateSize(self.SizeHint)

    def takeAt(self, index):
        if index >= 0 and index < len(self.list):
            layoutStruct = self.list.pop(index)
            return layoutStruct.item

        return None

    def add(self, item, position):
        self.list.append(ItemWrapper(item, position))

    def calculateSize(self, sizeType):
        totalSize = QSize()

        for wrapper in self.list:
            position = wrapper.position
            itemSize = QSize()

            if sizeType == self.MinimumSize:
                itemSize = wrapper.item.minimumSize()
            else: # sizeType == self.SizeHint
                itemSize = wrapper.item.sizeHint()

            if position in (self.North, self.South, self.Center):
                totalSize.setHeight(totalSize.height() + itemSize.height())

            if position in (self.West, self.East, self.Center):
                totalSize.setWidth(totalSize.width() + itemSize.width())

        return totalSize

Can you not do this (and a whole lot more) with the wx.aui modules?

Or with the pure python version:

Edit: here is the example from the wxPython Demo, modified to run stand-alone:
aui_demo_example_2.py (43.8 KB)

1 Like

Thank you, but isn’t it okay? directly wx.With you

What is the point of the BorderLayout class?
Placing widgets around a central widgets is easy and does not require a new sizer type.

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 1.1.0a2 on Sun May 12 16:01:07 2024
#

import wx




class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetSize((854, 483))
        self.SetTitle("frame")

        self.panel_1 = wx.Panel(self, wx.ID_ANY)

        sizer_1 = wx.BoxSizer(wx.VERTICAL)

        self.button_1 = wx.Button(self.panel_1, wx.ID_ANY, "North")
        sizer_1.Add(self.button_1, 0, wx.EXPAND, 0)

        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)

        self.button_3 = wx.Button(self.panel_1, wx.ID_ANY, "West")
        sizer_2.Add(self.button_3, 0, wx.EXPAND, 0)

        self.text_ctrl_1 = wx.TextCtrl(self.panel_1, wx.ID_ANY, "Central Widget")
        sizer_2.Add(self.text_ctrl_1, 1, wx.EXPAND, 0)

        self.button_4 = wx.Button(self.panel_1, wx.ID_ANY, "East 2")
        sizer_2.Add(self.button_4, 0, wx.EXPAND, 0)

        self.button_5 = wx.Button(self.panel_1, wx.ID_ANY, "East 1")
        sizer_2.Add(self.button_5, 0, wx.EXPAND, 0)

        self.button_2 = wx.Button(self.panel_1, wx.ID_ANY, "South")
        sizer_1.Add(self.button_2, 0, wx.EXPAND, 0)

        self.panel_1.SetSizer(sizer_1)

        self.Layout()


class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True

if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

2 Likes

You are right and thank you, but the borderlayout class is better than creating it manually one by one :slight_smile: