如何以受控的纵横比居中面板
How to center panel with controlled aspect ratio
在 wxPython 中,我无法将我创建的具有固定纵横比的子面板居中。
为了控制纵横比,子面板需要捕获Size事件,然后做一个显式的SetSize。所以,我已经做到了,而且效果很好。不幸的是,当我将此子面板嵌入另一个面板(使用 sizer)时,wx.ALIGN_CENTER_HORIZONTAL 标志不起作用。
显然,sizer 告诉我的子面板它有适合的整个宽度。当我的 window 不使用整个宽度时,sizer 不会调整。这是显示问题的代码的简化版本:
import wx
ROWS = 6
COLS = 25
class TestPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
label = wx.StaticText(self, -1, 'Label')
grid = TestGrid(self)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(label, 0, flag=wx.ALIGN_CENTER_HORIZONTAL)
sizer.Add(grid, 1, flag=wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND)
self.SetSizer(sizer)
class TestGrid(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
self.SetBackgroundColour(wx.BLUE)
self.Bind(wx.EVT_SIZE, self.OnSize)
def OnSize(self, event):
w, h = self.GetSizeTuple()
delta = min(w // COLS, h // ROWS)
self.SetSize((COLS*delta, ROWS*delta))
self.Refresh()
if __name__ == '__main__':
app = wx.App()
frame = wx.Frame(None, -1, "Test", size=(600, 200))
panel = TestPanel(frame)
frame.Show(True)
app.MainLoop()
这是屏幕截图:
您不能,或者至少不应该,从其自己的 wxEVT_SIZE
处理程序调整 window 的大小。我不确定你到底想达到什么目的,但如果目标是将所有内容封装在 TestGrid
class 中,那么你应该让它具有任何大小并创建一个嵌套的 window 在其中,您将在 OnSize
.
中调整到适当的大小
正如 VZ 在他的回答中解释的那样,您的 wxEVT_SIZE
处理程序不是一个好主意。去掉它。使用 sizer 时,您必须在 sizer 基础结构中工作才能实现您想要的。
您希望 TestGrid
在其父级中尽可能多地填充 space,同时保持一定的纵横比;这正是 wx.SHAPED
的用途(结合您已经拥有的大于 0 的 proportion
)。因此,您应该像这样将 grid
添加到 sizer:
sizer.Add(grid, 1, flag=wx.ALIGN_CENTER_HORIZONTAL|wx.SHAPED)
您唯一需要做的另一件事就是告诉 sizer 您想要的纵横比是多少。最简单的方法是为 TestGrid
设置一个初始大小(在它被添加到 sizer 之前);例如,设置其 wxPanel
基数的大小:
wx.Panel.__init__(self, parent, -1, size=(COLS*7, ROWS*7))
仅此而已。
(我只是在猜测 Python 语法,所以忽略任何明显的错误:-))
在 wxPython 中,我无法将我创建的具有固定纵横比的子面板居中。
为了控制纵横比,子面板需要捕获Size事件,然后做一个显式的SetSize。所以,我已经做到了,而且效果很好。不幸的是,当我将此子面板嵌入另一个面板(使用 sizer)时,wx.ALIGN_CENTER_HORIZONTAL 标志不起作用。
显然,sizer 告诉我的子面板它有适合的整个宽度。当我的 window 不使用整个宽度时,sizer 不会调整。这是显示问题的代码的简化版本:
import wx
ROWS = 6
COLS = 25
class TestPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
label = wx.StaticText(self, -1, 'Label')
grid = TestGrid(self)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(label, 0, flag=wx.ALIGN_CENTER_HORIZONTAL)
sizer.Add(grid, 1, flag=wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND)
self.SetSizer(sizer)
class TestGrid(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
self.SetBackgroundColour(wx.BLUE)
self.Bind(wx.EVT_SIZE, self.OnSize)
def OnSize(self, event):
w, h = self.GetSizeTuple()
delta = min(w // COLS, h // ROWS)
self.SetSize((COLS*delta, ROWS*delta))
self.Refresh()
if __name__ == '__main__':
app = wx.App()
frame = wx.Frame(None, -1, "Test", size=(600, 200))
panel = TestPanel(frame)
frame.Show(True)
app.MainLoop()
这是屏幕截图:
您不能,或者至少不应该,从其自己的 wxEVT_SIZE
处理程序调整 window 的大小。我不确定你到底想达到什么目的,但如果目标是将所有内容封装在 TestGrid
class 中,那么你应该让它具有任何大小并创建一个嵌套的 window 在其中,您将在 OnSize
.
正如 VZ 在他的回答中解释的那样,您的 wxEVT_SIZE
处理程序不是一个好主意。去掉它。使用 sizer 时,您必须在 sizer 基础结构中工作才能实现您想要的。
您希望 TestGrid
在其父级中尽可能多地填充 space,同时保持一定的纵横比;这正是 wx.SHAPED
的用途(结合您已经拥有的大于 0 的 proportion
)。因此,您应该像这样将 grid
添加到 sizer:
sizer.Add(grid, 1, flag=wx.ALIGN_CENTER_HORIZONTAL|wx.SHAPED)
您唯一需要做的另一件事就是告诉 sizer 您想要的纵横比是多少。最简单的方法是为 TestGrid
设置一个初始大小(在它被添加到 sizer 之前);例如,设置其 wxPanel
基数的大小:
wx.Panel.__init__(self, parent, -1, size=(COLS*7, ROWS*7))
仅此而已。
(我只是在猜测 Python 语法,所以忽略任何明显的错误:-))