如何在创建wx.App之前初始化wx.Font对象?

时间:2014-04-28 14:55:13

标签: python wxpython wxwidgets

我的应用程序有一个名为gui_constants的模块,其中包含我的应用程序使用的所有字体和颜色的定义。例如,gui_constants.py可能包含类似

的行
heading_font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, face='LucidaGrande')

和另一个文件可能会说

heading_label = wx.StaticText(self, label='Lorem Ipsum')
heading_label.SetFont(gui_constants.heading_font)

我遇到的问题是我的gui_constants模块是在创建wx.App之前导入的,这会导致异常:

Traceback (most recent call last):
  File "./main.py", line 3, in <module>
    from new_gui_app import NewGuiApp
  File ".../application/new_gui_app.py", line 3, in <module>
    from views import MainWindow
  File ".../application/views/__init__.py", line 1, in <module>
    from banner import Banner
  File ".../application/views/banner.py", line 3, in <module>
    import gui_constants
  File ".../application/gui_constants.py", line 63, in <module>
    heading_font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, face='LucidaGrande')
  File "/usr/local/lib/python2.7/site-packages/wx-2.9.5-osx_cocoa/wx/_gdi.py", line 2156, in __init__
    _gdi_.Font_swiginit(self,_gdi_.new_Font(*args, **kwargs))
wx._core.PyNoAppError: The wx.App object must be created first!

任何人都可以建议一种方法来将这些“常量”声明保留在一个模块中,同时也阻止它们在wx.App创建之前被初始化吗?

2 个答案:

答案 0 :(得分:1)

你有几个选择。一个非常简单的方法是将常量更改为元组而不是wx.Font对象:

heading_font = (12, wx.SWISS, wx.NORMAL, wx.BOLD, 'LucidaGrande')

然后当您导入它时,您可以执行以下操作:

#----------------------------------------------------------------------
def create_font(data):
    """"""
    size, family, style, weight, face = data
    font = wx.Font(size, family, style, weight, face=face)
    return font


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

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

        print type(gui_constants.heading_font)
        print create_font(gui_constants.heading_font)

您可以尝试的替代方法是使用Python的 eval 。如果你这样做,你会希望将常量存储为字符串,如下所示:

heading_font = "wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, face='LucidaGrande')"

然后在你的wxPython代码中,你可以这样做:

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

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

        print type(eval(gui_constants.heading_font))

请注意,eval的危险性很小,如果允许用户修改gui_constants文件,则可能会插入恶意代码。如果他们无法对其进行修改,那么根本没有任何危险。

答案 1 :(得分:0)

我最终使用的方法是在我的initialize模块中添加gui_constants方法:

def initialize():
    global heading_font
    heading_font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, face='LucidaGrande')

此方法要求用户在使用gui_constants中定义的任何常量之前调用此方法,但在创建App之后。 (在initialize准备好之前调用App会导致PyNoAppError,如我的问题所示,当有人试图访问其中一个尚未定义的字体时,调用它太晚会产生AttributeError。)然而,时机并不像我想象的那样棘手;我在initialize子类的App方法的开头调用OnInit,这似乎工作正常。

提到了另外三个选项(Mike Driscoll和VZ):

  1. 将字体信息存储在元组中,并在每次需要字体时将此元组传递给create_font函数。根据我的喜好,这太重了;常量模块的所有用户都需要知道字体创建功能,该功能应该是私有实现细节。它还在整个地方添加了少量语法开销。

  2. 使用eval eval的危险性众所周知,我的个人政策是不使用它,除非别无其他。

  3. 将字体存储为FontInfo个对象,稍后将其转换为Font个对象。这可以通过将FontInfo传递给某个构造函数来完成每次我们想要使用该字体,如选项(1),或通过构建Font对象,就像我在最终解决方案中所做的那样。使用前一种方法与我在项目(1)中提到的具有相同的反对意见。使用后一种方法基本上就是我正在做的,但是有一个额外的间接层。