[mini demo] use kiwisolver to locate and resize widget

first of all, I know we can use grid layout in wxPython.

But I try to mimic wNim’s Layout DSL with kiwisolver firstly. Then the ultimate goal is to coin Autolayout in wxPython which is more concise to describe GUI layout; which is a very hard project for me now, so it could be better if the community can make one.

In the simplified case, a button named b1 is placed on the frame. The horizontal gaps between button and frame are 10, the vertical gaps are 5. The position and size of widget should be recalculated when the user resize the frame.

this is a traditional way to do so

import wx

class Example(wx.Frame):
    def __init__(self, parent, title):
        super(Example, self).__init__(parent, title=title, size=(350, 300))

        self.InitUI()
        self.Bind(wx.EVT_SIZE, self.OnResize, self)
        self.Centre()

    def OnResize(self, evt):
        self.w, self.h = self.panel.GetSize()

        self.b1_w =  self.w - 10 * 2
        self.b1_h =  self.h - 5 * 2

        self.b1_x = 10
        self.b1_y = 5

        self.b1.SetPosition((self.b1_x, self.b1_y))
        self.b1.SetSize(self.b1_w, self.b1_h)

        self.Refresh() # or self.Update()

        self.panel.SetSize(self.GetClientSize() )

        evt.Skip()

    def InitUI(self):
        self.panel = wx.Panel(self)
        self.b1 = wx.Button(self.panel, wx.ID_ANY, "hello")

        self.panel.SetSize(self.GetClientSize() )

def main():
    app = wx.App()
    ex = Example(None, title='Absolute positioning')
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

and this one uses kiwisolver

from kiwisolver import Variable, Solver
import wx

class Example(wx.Frame):
    def __init__(self, parent, title):
        super(Example, self).__init__(parent, title=title, size=(350, 300))

        self.InitUI()
        self.Bind(wx.EVT_SIZE, self.OnResize, self)
        self.Centre()

    def OnResize(self, evt):
        self.w, self.h = self.panel.GetSize()

        self.b1_w = Variable('b1_w')
        self.b1_h = Variable('b1_h')
        self.b1_x = Variable('b1_x')
        self.b1_y = Variable('b1_y')

        constraints = [
            self.b1_w ==  self.w - 10 * 2,
            self.b1_h ==  self.h - 5 * 2,

            self.b1_x == 10,
            self.b1_y == 5,
        ]

        solver = Solver()

        for cn in constraints:
            solver.addConstraint(cn)

        solver.addEditVariable(self.b1_w, 'strong')
        solver.addEditVariable(self.b1_h, 'strong')
        solver.addEditVariable(self.b1_x, 'strong')
        solver.addEditVariable(self.b1_y, 'strong')

        solver.updateVariables()

        self.b1.SetPosition((self.b1_x.value(), self.b1_y.value()))
        self.b1.SetSize(self.b1_w.value(), self.b1_h.value())

        self.Update()

        self.panel.SetSize(self.GetClientSize() )

        evt.Skip()

    def InitUI(self):
        self.panel = wx.Panel(self)
        self.b1 = wx.Button(self.panel, wx.ID_ANY, "hello")

        self.panel.SetSize(self.GetClientSize() )

def main():
    app = wx.App()
    ex = Example(None, title='Absolute positioning')
    ex.Show()
    app.MainLoop()

if __name__ == '__main__':
    main()

You may want to take a look at wx.lib.anchors and wx.LayoutConstraits. It’s not really the same as wNim’s layout, but it seems to to follow a similar paradigm. Maybe you could implement your code on top of layout constraints? Note that the wx.LayoutConstraints classes in wxWidgets have been deprecated, but I doubt that it will ever be removed.

thanks. But my purpose is to create the GUI without typing so many codes by hand. In fact, I always hate to write a GUI applications.

Try wxGlade. Saves you from typing.

Yes, I has used wxGlade for my application before.