3

我已经编写了我的第一个 wxpython 应用程序,它运行良好,但我遇到了正确调整主窗口大小的困难。该面板包含一个wx.BoxSizer,而后者又包含一个wx.FlexGridSizer,而后者又包含 6 个wx.TextCtrls。

我读过的教程似乎侧重于手动设置大小。我真正想做的是让TextCtrls 计算出它们应该是什么大小以包含来自给定字体的 3 个字符(比如“WWW”),然后应该自动确定 FlexGridSizer 的大小和主窗户。我不需要担心调整布局的大小(所以也许 Sizer 不是必需的?),我只想自动确定大小,而不是通过我将魔术常量放入程序中。

import wx
from names_as_vs import name_sum, name_mult

NAME_SIZE = 35

class MyForm(wx.Frame):
    def __init__(self, parent,title):
        wx.Frame.__init__(self,parent,title=title,size=(405,200))

        self.default_init_UI()
        self.init_UI()
        self.Show()

    def default_init_UI(self):
        """Do all the standard UI stuff"""
        file_menu = wx.Menu()
        menuAbout = file_menu.Append(wx.ID_ABOUT,"About\tCtrl-A")
        menuExit = file_menu.Append(wx.ID_EXIT,"Quit\tCtrl-Q")

        menu_bar = wx.MenuBar()
        menu_bar.Append(file_menu,"File")
        self.SetMenuBar(menu_bar)

        self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
        self.Bind(wx.EVT_MENU, self.OnExit, menuExit)

    def init_UI(self):
        """Particular UI setup for this program"""

        hbox = wx.BoxSizer(wx.HORIZONTAL)
        panel = wx.Panel(self)
        fgs = wx.FlexGridSizer(2,5,9,9)

        fixed_elts_args = {"size":(30,70)}
        plus = wx.StaticText(panel, label="+", **fixed_elts_args)
        times = wx.StaticText(panel, label=".",**fixed_elts_args)

        equals1 = wx.Button(panel, label="=", **fixed_elts_args)
        equals2 = wx.Button(panel, label="=", **fixed_elts_args)
        equals1.Bind(wx.EVT_BUTTON, self.compute_sum)
        equals2.Bind(wx.EVT_BUTTON, self.compute_mult)

        font = wx.Font(48,wx.ROMAN,wx.NORMAL,wx.NORMAL)
        text_ctrl_args = {"size":(95,70)}
        self.summand1 = wx.TextCtrl(panel, **text_ctrl_args)
        self.summand2 = wx.TextCtrl(panel, **text_ctrl_args)
        self.scalar = wx.TextCtrl(panel, **text_ctrl_args)
        self.multiplicand = wx.TextCtrl(panel, **text_ctrl_args)
        self.sum_result = wx.TextCtrl(panel, style = wx.TE_READONLY, **text_ctrl_args)
        self.mult_result = wx.TextCtrl(panel, style = wx.TE_READONLY,     **text_ctrl_args)

        for ctrl in (plus,times,equals1,equals2,self.summand1,self.summand2,
                     self.scalar,self.multiplicand,self.sum_result,self.mult_result):
            ctrl.SetFont(font)

        fgs.AddMany([ 
            self.summand1,plus,self.summand2,equals1,self.sum_result,
            self.scalar,times,self.multiplicand,equals2,self.mult_result
            ])

        hbox.Add(fgs, proportion=1, flag= wx.ALL, border=15)
        panel.SetSizer(hbox)

    def OnAbout(self,e):
        dlg = wx.MessageDialog(self, "A GUI implementation of 815 as a vector space",     "About 815 as a vector space", wx.OK)
        dlg.ShowModal() # Shows it
        dlg.Destroy() # finally destroy it when finished.

    def OnExit(self,e):
        self.Close(True)  # Close the frame.

    def compute_sum(self,e):
        """Computes the sum of the names in summand1 and summand2 and displays the result in self.sum_result"""
        n1 = self.summand1.GetValue()
        n2 = self.summand2.GetValue()
        self.sum_result.SetValue(name_sum(n1,n2))

    def compute_mult(self,e):
        """
        Computes the scalar multiple of the name in multiplicand by the scalar in scalar and displays the result in self.mult_result
        """
        n = self.multiplicand.GetValue()
        lamb = self.scalar.GetValue()
        self.mult_result.SetValue(name_mult(lamb,n))
4

1 回答 1

5

您需要执行两个步骤来解决您的问题。

第一步是计算字符串的宽度(以“WWW”为例)。请查看有关使用 wxpython 以像素为单位计算字符串宽度的 SO question。一旦你有了宽度和高度,你就可以设置你的wx.TextCtrl尺寸。

第二步是设置wx.Frame大小。我想说的是,在 wxpython 术语中,任何可以出现在屏幕上的对象都称为窗口,而大多数用户将其称为窗口(即 MS Windows 中具有最小化/最大化/关闭按钮的东西)称为框架。我知道,这可能会让人感到困惑。

因此,您想使用内容的大小自动设置框架的大小。简单的!您想使用该Fit()方法(文档)。您也可以使用该SetSizerAndFit()方法(文档),但这只是一种同时调用两者的便捷SetSizer()方法Fit()。该Fit()方法查看对象内容的大小并相应地调整该对象的大小。不幸的是,在您的特定代码中并不是那么简单。

在您的代码中,您有一个MyForm(一个wx.Frame实例),其中包含一个wx.Panel然后包含您的尺寸器和您wx.TextCtrl的 s。不幸的是,这会导致MyForm根据内容计算 's 大小的问题,因此调用Fit()只会将其设置为默认大小。原因是wx.Frames 根据它们的 sizer(由 分配SetSizer())计算它们的大小,而 currentMyForm没有 sizer,所以它不能根据你的内容计算大小wx.Panel。幸运的是,这个问题有两种解决方案,而且都很简单。

1.删panel​​除并将所有内容设置为MyForm直接然后调用的子项SetSizerAndFit()

这看起来像这样:

def init_UI(self):

    [...]

    #note that the parent is now "self" and not "panel"
    self.multiplicand = wx.TextCtrl(self, **text_ctrl_args)
    self.sum_result = wx.TextCtrl(self, style = wx.TE_READONLY, **text_ctrl_args)
    self.mult_result = wx.TextCtrl(self, style = wx.TE_READONLY,     **text_ctrl_args)

    [...]

    self.SetSizerAndFit(hbox)


2. 放置在panel另一个尺寸器内并调用SetSizerAndFit()MyForm

看起来像这样:

def init_UI(self):

    [...]

    panel.SetSizer(hbox)

    sizer = wx.BoxSizer(wx.Horizontal)
    sizer.Add(panel)
    self.SetSizerAndFit(sizer) 


最后,我想快速解释一下为什么教程倾向于使用那些“神奇的数字”。UI 设计很困难,有时您需要像素完美的东西。如果您正在开发一个应用程序以在具有不同设置和屏幕分辨率甚至不同操作系统的不同计算机上使用,那么确保所有内容都一致地显示需要明确设置字体和大小等内容,而不是依赖系统默认值。随着您的进步并开始制作更复杂的 wxpython 应用程序,您会遇到有时无法正确计算对象大小的问题,并且使用我告诉您使用的方法仍然会使您的窗口太大/太小。请记住这一点,然后继续前进。

于 2012-07-28T04:24:19.890 回答