如何覆盖面板的最小尺寸?

1 投票
3 回答
682 浏览
提问于 2025-04-17 13:54

我正在尝试实现一个面板的子类,这个面板会在内容超出其垂直范围时自动插入垂直滚动条。我希望这个面板在所有方面都和普通面板完全一样,唯一的不同是:面板的最小高度应该是一个固定值(比如200),而不是它的布局器的最小高度。当面板的高度低于它的布局器的高度时,就应该出现一个垂直滚动条。换句话说,当面板的高度高于布局器的最小高度时,它的功能应该和普通面板完全一样。

我遇到的问题是,像 DoGetBestSizeGetMinSize 这样的函数在面板上重写后没有任何效果,因为这些函数根本没有被调用(我通过插入断点检查过)。我猜测面板的父级直接与面板的布局器进行通信,而这个布局器在这种情况下是从面板外部设置的普通盒子布局器。

class ScrolledPanel(wx.Panel):
    """A panel that will automatically add scrollbars when needed."""

    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1)

        self.SetBackgroundColour('#FF0000')

    # This function is never called.
    def DoGetBestSize(self):
        """Override the minimum size of the panel."""

        default = self.GetSizer().GetMinSize()
        default.SetHeight(250)

        return default

我想知道是否有可能实现我想要的效果?如果可以的话,我该如何绕过上面描述的问题呢?

这是我尝试使用滚动面板的代码


更新

我想我可以尝试重写 SetSizer 函数,先把那个布局器“抓住”,然后咨询它关于大小的信息,但实际上不在面板上设置布局器。这样的话,像 DoGetBestSize 这样的自定义大小函数就会被调用。然而,这个方法失败了。即使没有设置布局器,这些函数仍然没有被调用。我尝试了 PanelPyPanel。这是我当前的滚动面板:

class ScrolledPanel(wx.PyPanel):
    """A panel that will automatically add scrollbars when needed."""

    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1)

        self.SetBackgroundColour('#FF0000')

    # This function is called.
    def SetSizer(self, sizer):
        import pdb; pdb.set_trace()
        self._pet_sizer = sizer

    # The below functions are never called.
    def DoGetBestSize(self):
        """Override the minimum size of the panel."""
        import pdb; pdb.set_trace()
        default = self.GetSizer().GetMinSize()
        default.SetHeight(250)

        return default

    def DoGetClientSize(self):
        import pdb; pdb.set_trace()

    def DoGetSize(self):
        import pdb; pdb.set_trace()

    def DoGetVirtualSize(self):
        import pdb; pdb.set_trace()

3 个回答

0

你为什么要重新发明轮子呢?wxPython已经提供了一个叫做ScrolledPanel的组件:wx.lib.scrolledpanel

你只需要使用这个就可以了。wxPython的演示中有一个例子。

编辑:这里有一个示例脚本,里面有一个放在布局中的ScrolledPanel。

import wx
import  wx.lib.scrolledpanel as scrolled

########################################################################
class MyScrolledPanel(scrolled.ScrolledPanel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        scrolled.ScrolledPanel.__init__(self, parent)


########################################################################
class MainPanel(wx.Panel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)

        text = "one two buckle my shoe three four shut the door five six pick up sticks seven eight lay them straight nine ten big fat hen"

        mainSizer = wx.BoxSizer(wx.VERTICAL)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sPanel = MyScrolledPanel(self)

        words = text.split()
        for word in words:
            hSizer = wx.BoxSizer(wx.HORIZONTAL)
            label = wx.StaticText(sPanel, -1, word+":")
            tc = wx.TextCtrl(sPanel, -1, word, size=(50,-1))

            hSizer.Add(label, flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=10)
            hSizer.Add(tc, flag=wx.LEFT, border=10)
            sizer.Add(hSizer)

        sPanel.SetSizer(sizer)
        sPanel.SetAutoLayout(1)
        sPanel.SetupScrolling()

        mainSizer.Add(sPanel, 1, wx.EXPAND)
        self.SetSizer(mainSizer)


########################################################################
class MainFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None)
        panel = MainPanel(self)

if __name__ == "__main__":
    app = wx.App(False)
    frame = MainFrame()
    frame.Show()
    app.MainLoop()
0

你不需要做什么特别的事情。如果你在任何一个 wxWindow 上调用 SetVirtualSize(),包括 wxPanel,它会自动根据需要显示滚动条,而且布局管理器会使用这个虚拟大小来安排窗口里的内容。

2

在wxPython中,想要重写方法需要使用一些特定的基类,这些基类是为了让Python中的重写方法能够反映C++中的虚拟方法调用。简单来说,如果你想在一个面板中捕捉这些方法的调用,你就得让你的类继承自wx.PyPanel,而不是wx.Panel。想了解更多,可以查看这个链接:http://wiki.wxpython.org/OverridingMethods

撰写回答