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?
- wx.aui β wxPython Phoenix 4.2.1 documentation
- wx.aui.AuiManager β wxPython Phoenix 4.2.1 documentation
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