Передача wx.BoxSizer, если дочерний размер изменяет

Если размер детей в wx.BoxSizer Изменения в boxsizer не транслируются:

import wx

class MyButton(wx.Button):
    def __init__(self, parent):
        wx.Button.__init__(self, parent, -1, style=wx.SUNKEN_BORDER, label="ABC")
        self.Bind(wx.EVT_BUTTON, self.OnClick)

    def OnClick(self, event):
        self.SetSize((200, 200))
        self.SetSizeHints(200, 200)

class MyFrame(wx.Frame):
    def __init__(self, parent, ID, title):
       wx.Frame.__init__(self, parent, ID, title, size=(300, 250))

       self.button = MyButton(self)
       button2 = wx.Button(self, -1, style=wx.SUNKEN_BORDER, label="DEF")

       # self.button.Bind(wx.EVT_SIZE, self.OnButtonResize)

       box = wx.BoxSizer(wx.HORIZONTAL)
       box.Add(self.button, 1, wx.EXPAND)
       box.Add(button2, 1, wx.EXPAND)

       self.SetAutoLayout(True)
       self.SetSizer(box)
       self.Layout()

    def OnButtonResize(self, event):
        event.Skip()
        self.Layout()

app = wx.App()
frame = MyFrame(None, -1, "Sizer Test")
frame.Show()
app.MainLoop()

После нажатия левой кнопки его размер изменяется, но макет нарушается. После изменения размера ребенка

Если вручную изменить размер кнопки (строка комментария), то получится бесконечная рекурсия.

В моем реальном случае использования я не могу изменить MyButton а также MyButton это wx.Panel который изменяется на событии, которое я не могу вызвать.

2 ответа

Решение

Я нашел собственное решение. Если вы проверите изменения размера в обратном вызове события перед выполнением ретрансляции, вы не получите бесконечную рекурсию:

class MyFrame(wx.Frame):
    def __init__(self, parent, ID, title):
       wx.Frame.__init__(self, parent, ID, title, size=(300, 250))

       self.button = MyButton(self)
       button2 = wx.Button(self, -1, style=wx.SUNKEN_BORDER, label="DEF")

       self.button.Bind(wx.EVT_SIZE, self.OnButtonResize)

       box = wx.BoxSizer(wx.HORIZONTAL)
       box.Add(self.button, 1, wx.EXPAND)
       box.Add(button2, 1, wx.EXPAND)

       self.buttonSize = None
       self.SetSizer(box)
       self.Layout()

    def OnButtonResize(self, event):
        event.Skip()

        if self.buttonSize != event.Size:
            self.buttonSize = event.Size
            self.Layout()

Это не часть wx.Sizer дизайн для изменения размера, чтобы автоматически течь вверх по иерархии содержимого для повторного макета. Вместо этого вам нужно запустить реле самостоятельно. Это потому, что может произойти несколько изменений, и только вы знаете, когда это подходящее время для этого. Если бы это было автоматизировано, то было бы слишком легко попасть в ситуацию, когда одно изменение размера вызывает другое изменение размера, которое вызывает другое, которое вызывает изменение первого размера снова.

Таким образом, Sizer вместо этого предназначены для управления макетом сверху вниз (например, изменение размера кадра приводит к положению или изменению размера дочерних элементов кадра), и когда возникает ситуация, когда должно произойти изменение снизу вверх, тогда программист должен помочь в чем-то. В вашем примере вы можете просто добавить следующую строку в OnClick метод:

self.GetContainingSizer().Layout()

Для более сложных макетов может потребоваться что-то еще.

Другие вопросы по тегам