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

Python 在创建wx.App之前,如何初始化wx.Font对象?,python,wxpython,wxwidgets,Python,Wxpython,Wxwidgets,我的应用程序有一个名为gui\u constants的模块,其中包含我的应用程序使用的所有字体和颜色的定义。例如,gui\u 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\u constants
的模块,其中包含我的应用程序使用的所有字体和颜色的定义。例如,
gui\u 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)
我遇到的问题是,在创建
wx.App
之前,正在导入我的
gui\u常量
模块,这导致异常:

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!
回溯(最近一次呼叫最后一次):
文件“/main.py”,第3行,在
从新图形用户界面应用程序导入新图形用户界面应用程序
文件“../application/new\u gui\u app.py”,第3行,在
从视图导入主窗口
文件“../application/views/\uuuuu init\uuuuu.py”,第1行,在
从横幅进口横幅
文件“../application/views/banner.py”,第3行,在
导入gui_常量
文件“../application/gui_constants.py”,第63行,在
heading_font=wx.font(12,wx.SWISS,wx.NORMAL,wx.BOLD,face='LucidaGrande')
文件“/usr/local/lib/python2.7/site packages/wx-2.9.5-osx_cococa/wx/_gdi.py”,第2156行,在__
_gdi_u.Font_swiginit(self,_gdi_u.new_Font(*args,**kwargs))
wx._core.PyNoAppError:必须首先创建wx.App对象!

有人能提出一种方法,将这些“常量”声明分解成单个模块,同时防止它们在创建
wx.App
之前被初始化吗?

您有两个选择。一种非常简单的方法是将常量更改为元组,而不是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)
heading_font = "wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, face='LucidaGrande')"
########################################################################
class MyPanel(wx.Panel):
    """"""

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

        print type(eval(gui_constants.heading_font))
您可以尝试使用Python的eval。如果这样做,您会希望将常量存储为字符串,如下所示:

#----------------------------------------------------------------------
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)
heading_font = "wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, face='LucidaGrande')"
########################################################################
class MyPanel(wx.Panel):
    """"""

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

        print type(eval(gui_constants.heading_font))
然后在wxPython代码中,您将执行以下操作:

#----------------------------------------------------------------------
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)
heading_font = "wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, face='LucidaGrande')"
########################################################################
class MyPanel(wx.Panel):
    """"""

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

        print type(eval(gui_constants.heading_font))

请注意,eval有一个小危险,即如果允许用户修改gui_常量文件,他们可能会插入恶意代码。如果他们不能修改它,那么根本就没有什么危险。

我最终使用的方法是在我的
gui\u常量
模块中添加
initialize
方法:

def initialize():
    global heading_font
    heading_font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, face='LucidaGrande')
这种方法要求用户在使用
gui\u constants
中定义的任何常量之前,但在创建
App
之后,调用此方法。(在
应用程序
准备就绪之前调用
初始化
会导致Pynapperror,如我的问题所述,调用太晚会在有人试图访问一种尚未定义的字体时产生AttributeError。)不过,时间安排并不像我想象的那么棘手;在我的
App
子类的
OnInit
方法的开头,我调用了
initialize
,这似乎很好

还有三个其他选项(由Mike Driscoll和VZ提出):

  • 将字体信息存储在一个元组中,并在每次需要字体时将该元组传递给
    create\u font
    函数。
    我觉得这太重了;constants模块的所有用户都需要了解字体创建功能,这应该是一个私有的实现细节。它还增加了少量的语法开销

  • 使用
    eval
    eval的危险是众所周知的,我个人的政策是除非没有其他办法,否则不要使用它

  • 将字体存储为
    FontInfo
    对象,并在以后将其转换为
    Font
    对象。
    这可以通过在每次使用该字体时将
    FontInfo
    传递给某个构造器来实现,如选项(1)中所示,或者通过集体构造
    Font
    对象,正如我在最终解决方案中所做的那样。使用前一种方法与我在第(1)项中提到的反对意见相同。使用后一种方法基本上就是我正在做的,但是有一个额外的间接层


  • 元组解决方案是最好的,我只想补充一点,在3.0中你有
    wxFontInfo
    ,这是一个简单的元组类,也可以在GUI初始化之前创建,并且可以直接从中创建
    wxFont
    。是的,我也这么认为,但我想给出几个选项。