Sizer 没有按计划行事......
Sizer not behaving as planned…
我正在构建一个包含多个不同面板的 GUI,我不想将它们放在同一个 sizer 中:虽然它们显示相关内容,但它们应该是分开的。我有几个面板,每个面板都有自己的 sizer 添加到顶级 sizer。到目前为止,一切都很好。但是,我无法弄清楚如何让 sizer 实际调整面板的大小。
我有兴趣了解一下我没有遗漏的,不是简单的debug。
现在,行为似乎可以根据版本和 OS 而改变,所以这是我的:
- 分OS 7.
- Python 3.6.
- wxPython 4.0.0b1.
- 为了增加复杂性,此代码最终也必须在 Windows 10 上运行。
这是我目前得到的:
这就是我希望发生的事情:
虽然左右没有边框,尽管加了一个。我怀疑 sizer 代码搞砸了,因此忽略了边界。
源码,如是:
import wx.lib.agw.floatspin as FS
import wx
class GUICalibration(wx.Frame):
"""A calibration GUI for raiju…"""
def __init__(self, parent, id, title):
super(GUICalibration, self).__init__(parent, id, title)
panel = wx.Panel(self)
panel.SetBackgroundColour('#5968c3')
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self._ui(panel), 1, wx.EXPAND | wx.ALL, 3)
sizer.SetSizeHints(panel)
panel.SetSizer(sizer)
self.Centre()
self.Show(True)
def _ui(self, parent):
panel = wx.Panel(parent)
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(self._ui_prefix(panel), flag=wx.EXPAND)
vbox.Add(self._ui_input(panel), wx.EXPAND)
vbox.AddStretchSpacer()
vbox.Add(self._ui_suffix(panel), flag=wx.EXPAND)
vbox.SetSizeHints(parent)
panel.SetSizer(vbox)
return panel
def _ui_prefix(self, parent):
panel = wx.Panel(parent)
panel.SetBackgroundColour('steelblue')
hbox = wx.BoxSizer(wx.HORIZONTAL)
_label = wx.StaticText(panel, label='')
_label.SetLabelMarkup("<b><i><big>Calibration</big></i></b>")
hbox.Add(_label, flag=wx.ALIGN_CENTER | wx.ALL)
panel.SetSizer(hbox)
return panel
def _ui_input(self, parent):
box = wx.StaticBox(parent, -1, "Calibration input")
fgs = wx.FlexGridSizer(3, 3, 11, 11)
flags = wx.EXPAND | wx.ALL
_spin_count = wx.SpinCtrl(
box, wx.ID_ANY, '0', min=0, max=1000, size=(128, -1))
_spin_value = FS.FloatSpin(
box,
wx.ID_ANY,
size=(128, -1),
value=0.0,
min_val=-40.0,
max_val=100.0, # FIXME
increment=0.1)
_spin_value.SetFormat("%f")
_spin_value.SetDigits(1)
_add = wx.Button(box, wx.ID_ANY, "Add calibration data")
fgs.Add(wx.StaticText(box, label='Count'), 0, flags)
fgs.Add(wx.StaticText(box, label='Value'), 0, flags)
fgs.AddStretchSpacer()
fgs.Add(_spin_count, 0, flags)
fgs.Add(_spin_value, 0, flags)
fgs.Add(_add, 0, flags)
fgs.SetSizeHints(box)
box.SetSizer(fgs)
return box
def _ui_suffix(self, parent):
panel = wx.Panel(parent)
panel.SetBackgroundColour('steelblue')
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(
wx.BoxSizer(wx.VERTICAL), flag=wx.RESERVE_SPACE_EVEN_IF_HIDDEN)
_quit = wx.Button(panel, wx.ID_ANY, "Quit")
_quit.SetBackgroundColour('#5968c3')
self.Bind(wx.EVT_BUTTON, self.OnQuit, _quit)
hbox.AddStretchSpacer()
hbox.Add(_quit, flag=wx.ALIGN_CENTER | wx.SHAPED | wx.ALL, border=3)
hbox.AddStretchSpacer()
panel.SetSizer(hbox)
return panel
def OnQuit(self, e):
self.Close()
if __name__ == '__main__':
"""This is useful for testing the frame…"""
app = wx.App()
GUICalibration(None, -1, title='Calibration')
app.MainLoop()
一个可行的解决方案如下:
class GUICalibration(wx.Frame):
def __init__(self, parent, id, title):
self._logger = logging.getLogger(self.__class__.__name__)
super(GUICalibration, self).__init__(parent, id, title)
self._ui(self)
self.Fit()
self.SetAutoLayout(True)
self.Centre()
self.Show()
def _ui(self, parent):
panel = wx.Panel(self)
sizer = wx.FlexGridSizer(1, 5, 5)
sizer.Add(self._ui_frame(panel), 1, wx.EXPAND | wx.ALL, 3)
sizer.Add(self._ui_frame(panel), 1, wx.EXPAND | wx.ALL, 3)
sizer.Add(self._ui_frame(panel), 1, wx.EXPAND | wx.ALL, 3)
panel.SetSizerAndFit(sizer)
return panel
def _ui_frame(self, parent):
sizer = wx.StaticBoxSizer(wx.VERTICAL, parent, 'test',)
sizer.Add(wx.Button(parent, -1, 'A very ' + 20 * 'long ' + 'text'), 0, 0, 0)
sizer.Add(wx.Button(parent, -1, 'Small button'), 0, wx.EXPAND | wx.ALL, 20)
return sizer
前缀和后缀代码已被省略以使代码更短,但包含在屏幕截图中。
此解决方案的问题有两个:首先,重新调整 window 不会 调整任何 sizer 的大小:它们保持在尽可能低的水平大小合适。其次,我丢失了顶层面板的背景色。为什么?这两个我都不知道。
我正在构建一个包含多个不同面板的 GUI,我不想将它们放在同一个 sizer 中:虽然它们显示相关内容,但它们应该是分开的。我有几个面板,每个面板都有自己的 sizer 添加到顶级 sizer。到目前为止,一切都很好。但是,我无法弄清楚如何让 sizer 实际调整面板的大小。
我有兴趣了解一下我没有遗漏的,不是简单的debug。
现在,行为似乎可以根据版本和 OS 而改变,所以这是我的:
- 分OS 7.
- Python 3.6.
- wxPython 4.0.0b1.
- 为了增加复杂性,此代码最终也必须在 Windows 10 上运行。
这是我目前得到的:
这就是我希望发生的事情:
虽然左右没有边框,尽管加了一个。我怀疑 sizer 代码搞砸了,因此忽略了边界。
源码,如是:
import wx.lib.agw.floatspin as FS
import wx
class GUICalibration(wx.Frame):
"""A calibration GUI for raiju…"""
def __init__(self, parent, id, title):
super(GUICalibration, self).__init__(parent, id, title)
panel = wx.Panel(self)
panel.SetBackgroundColour('#5968c3')
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self._ui(panel), 1, wx.EXPAND | wx.ALL, 3)
sizer.SetSizeHints(panel)
panel.SetSizer(sizer)
self.Centre()
self.Show(True)
def _ui(self, parent):
panel = wx.Panel(parent)
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(self._ui_prefix(panel), flag=wx.EXPAND)
vbox.Add(self._ui_input(panel), wx.EXPAND)
vbox.AddStretchSpacer()
vbox.Add(self._ui_suffix(panel), flag=wx.EXPAND)
vbox.SetSizeHints(parent)
panel.SetSizer(vbox)
return panel
def _ui_prefix(self, parent):
panel = wx.Panel(parent)
panel.SetBackgroundColour('steelblue')
hbox = wx.BoxSizer(wx.HORIZONTAL)
_label = wx.StaticText(panel, label='')
_label.SetLabelMarkup("<b><i><big>Calibration</big></i></b>")
hbox.Add(_label, flag=wx.ALIGN_CENTER | wx.ALL)
panel.SetSizer(hbox)
return panel
def _ui_input(self, parent):
box = wx.StaticBox(parent, -1, "Calibration input")
fgs = wx.FlexGridSizer(3, 3, 11, 11)
flags = wx.EXPAND | wx.ALL
_spin_count = wx.SpinCtrl(
box, wx.ID_ANY, '0', min=0, max=1000, size=(128, -1))
_spin_value = FS.FloatSpin(
box,
wx.ID_ANY,
size=(128, -1),
value=0.0,
min_val=-40.0,
max_val=100.0, # FIXME
increment=0.1)
_spin_value.SetFormat("%f")
_spin_value.SetDigits(1)
_add = wx.Button(box, wx.ID_ANY, "Add calibration data")
fgs.Add(wx.StaticText(box, label='Count'), 0, flags)
fgs.Add(wx.StaticText(box, label='Value'), 0, flags)
fgs.AddStretchSpacer()
fgs.Add(_spin_count, 0, flags)
fgs.Add(_spin_value, 0, flags)
fgs.Add(_add, 0, flags)
fgs.SetSizeHints(box)
box.SetSizer(fgs)
return box
def _ui_suffix(self, parent):
panel = wx.Panel(parent)
panel.SetBackgroundColour('steelblue')
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(
wx.BoxSizer(wx.VERTICAL), flag=wx.RESERVE_SPACE_EVEN_IF_HIDDEN)
_quit = wx.Button(panel, wx.ID_ANY, "Quit")
_quit.SetBackgroundColour('#5968c3')
self.Bind(wx.EVT_BUTTON, self.OnQuit, _quit)
hbox.AddStretchSpacer()
hbox.Add(_quit, flag=wx.ALIGN_CENTER | wx.SHAPED | wx.ALL, border=3)
hbox.AddStretchSpacer()
panel.SetSizer(hbox)
return panel
def OnQuit(self, e):
self.Close()
if __name__ == '__main__':
"""This is useful for testing the frame…"""
app = wx.App()
GUICalibration(None, -1, title='Calibration')
app.MainLoop()
一个可行的解决方案如下:
class GUICalibration(wx.Frame):
def __init__(self, parent, id, title):
self._logger = logging.getLogger(self.__class__.__name__)
super(GUICalibration, self).__init__(parent, id, title)
self._ui(self)
self.Fit()
self.SetAutoLayout(True)
self.Centre()
self.Show()
def _ui(self, parent):
panel = wx.Panel(self)
sizer = wx.FlexGridSizer(1, 5, 5)
sizer.Add(self._ui_frame(panel), 1, wx.EXPAND | wx.ALL, 3)
sizer.Add(self._ui_frame(panel), 1, wx.EXPAND | wx.ALL, 3)
sizer.Add(self._ui_frame(panel), 1, wx.EXPAND | wx.ALL, 3)
panel.SetSizerAndFit(sizer)
return panel
def _ui_frame(self, parent):
sizer = wx.StaticBoxSizer(wx.VERTICAL, parent, 'test',)
sizer.Add(wx.Button(parent, -1, 'A very ' + 20 * 'long ' + 'text'), 0, 0, 0)
sizer.Add(wx.Button(parent, -1, 'Small button'), 0, wx.EXPAND | wx.ALL, 20)
return sizer
前缀和后缀代码已被省略以使代码更短,但包含在屏幕截图中。
此解决方案的问题有两个:首先,重新调整 window 不会 调整任何 sizer 的大小:它们保持在尽可能低的水平大小合适。其次,我丢失了顶层面板的背景色。为什么?这两个我都不知道。