如何在Python中的另一个类中创建类的实例

时间:2023-01-13 09:07:40

I am trying to learn Python and WxPython. I have been a SAS programmer for years. This OOP stuff is slowly coming together but I am still fuzzy on a lot of the concepts. Below is a section of code. I am trying to use a button click to create an instance of another class. Specifically-I have my main panel in one class and I wanted to instance a secondary panel when a user clicked on one of the menu items on the main panel. I made all of this work when the secondary panel was just a function. I can't seem to get ti to work as a class.

我正在尝试学习Python和WxPython。我多年来一直是SAS程序员。这个OOP的东西正在慢慢融合在一起,但我对很多概念仍然很模糊。下面是一段代码。我试图使用按钮单击来创建另一个类的实例。具体来说 - 我将主面板放在一个类中,当用户单击主面板上的某个菜单项时,我想要实例化一个辅助面板。当辅助面板只是一个功能时,我完成了所有这些工作。我似乎无法在课堂上工作。

Here is the code

这是代码

import wx

class mainPanel(wx.Frame):
    def __init__(self, parent, id, title):
    wx.Frame.__init__(self, parent, id, 'directEDGAR Supplemental Tools', size=(450, 450))
    wx.Panel(self,-1)
    wx.StaticText(self,-1, "This is where I will describe\n the purpose of these tools",(100,10))


    menubar = wx.MenuBar()
    parser = wx.Menu()
    one =wx.MenuItem(parser,1,'&Extract Tables  with One Heading or Label')
    two =wx.MenuItem(parser,1,'&Extract Tables  with Two Headings or Labels')
    three =wx.MenuItem(parser,1,'&Extract Tables  with Three Headings or Labels')
    four =wx.MenuItem(parser,1,'&Extract Tables  with Four Headings or Labels')
    quit = wx.MenuItem(parser, 2, '&Quit\tCtrl+Q')
    parser.AppendItem(one)
    parser.AppendItem(two)
    parser.AppendItem(three)
    parser.AppendItem(four)
    parser.AppendItem(quit)
    menubar.Append(parser, '&Table Parsers')

    textRip = wx.Menu()
    section =wx.MenuItem(parser,1,'&Extract Text With Section Headings')
    textRip.AppendItem(section)
    menubar.Append(textRip, '&Text Rippers')

    dataHandling = wx.Menu()
    deHydrate =wx.MenuItem(dataHandling,1,'&Extract Data from Tables')
    dataHandling.AppendItem(deHydrate)
    menubar.Append(dataHandling, '&Data Extraction')        


    self.Bind(wx.EVT_MENU, self.OnQuit, id=2)

this is where I think I am being clever by using a button click to create an instance

of subPanel.

    self.Bind(wx.EVT_MENU, self.subPanel(None, -1, 'TEST'),id=1)

    self.SetMenuBar(menubar)

    self.Centre()
    self.Show(True)

   def OnQuit(self, event):
    self.Close()

class subPanel(wx.Frame):
    def __init__(self, parent, id, title):
    wx.Frame.__init__(self, parent, id, 'directEDGAR Supplemental Tools', size=(450, 450))
    wx.Panel(self,-1)
    wx.StaticText(self,-1, "This is where I will describe\n the purpose of these tools",(100,10))


    getDirectory = wx.Button(panel, -1, "Get Directory Path", pos=(20,350))
    getDirectory.SetDefault()

    getTerm1 = wx.Button(panel, -1, "Get Search Term", pos=(20,400))
    getTerm1.SetDefault()

    #getDirectory.Bind(wx.EVT_BUTTON, getDirectory.OnClick, getDirectory.button)


    self.Centre()
    self.Show(True)




app = wx.App()
mainPanel(None, -1, '')
app.MainLoop()

3 个解决方案

#1


0  

You need an event handler in your bind expression

您需要在绑定表达式中使用事件处理程序

self.bind(wx.EVT_MENU, subPanel(None, -1, 'TEST'),id=1)

needs to be changed to:

需要改为:

self.bind(wx.EVT_MENU, <event handler>, <id of menu item>)

where your event handler responds to the event and instantiates the subpanel:

您的事件处理程序响应事件并实例化子面板:

def OnMenuItem(self, evt): #don't forget the evt
    sp = SubPanel(self, wx.ID_ANY, 'TEST')
    #I assume you will add it to a sizer
    #if you aren't... you should
    test_sizer.Add(sp, 1, wx.EXPAND)
    #force the frame to refresh the sizers:
    self.Layout()

Alternatively, you can instantiate the subpanel in your frame's __init__ and call a subpanel.Hide() after instantiation, and then your menuitem event handler and call a show on the panel subpanel.Show()

或者,您可以在框架的__init__中实例化子面板,并在实例化后调用subpanel.Hide(),然后调用menuitem事件处理程序并在面板subpanel.Show()上调用show。

Edit: Here is some code that will do what I think that you are asking:

编辑:这里有一些代码可以执行我认为您要问的内容:

#!usr/bin/env python

import wx

class TestFrame(wx.Frame):
    def __init__(self, parent, *args, **kwargs):
        wx.Frame.__init__(self, parent, *args, **kwargs)
        framesizer = wx.BoxSizer(wx.VERTICAL)
        mainpanel = MainPanel(self, wx.ID_ANY)
        self.subpanel = SubPanel(self, wx.ID_ANY)
        self.subpanel.Hide()
        framesizer.Add(mainpanel, 1, wx.EXPAND)
        framesizer.Add(self.subpanel, 1, wx.EXPAND)
        self.SetSizerAndFit(framesizer)

class MainPanel(wx.Panel):
    def __init__(self, parent, *args, **kwargs):
        wx.Panel.__init__(self, parent, *args, **kwargs)
        panelsizer = wx.BoxSizer(wx.VERTICAL)
        but = wx.Button(self, wx.ID_ANY, "Add")
        self.Bind(wx.EVT_BUTTON, self.OnAdd, but)
        self.panel_shown = False
        panelsizer.Add(but, 0)
        self.SetSizer(panelsizer)

    def OnAdd(self, evt):
        if not self.panel_shown:
            self.GetParent().subpanel.Show()
            self.GetParent().Fit()
            self.GetParent().Layout()
            self.panel_shown = True
        else:
            self.GetParent().subpanel.Hide()
            self.GetParent().Fit()
            self.GetParent().Layout()
            self.panel_shown = False

class SubPanel(wx.Panel):
    def __init__(self, parent, *args, **kwargs):
        wx.Panel.__init__(self, parent, *args, **kwargs)
        spsizer = wx.BoxSizer(wx.VERTICAL)
        text = wx.StaticText(self, wx.ID_ANY, label='I am a subpanel')
        spsizer.Add(text, 1, wx.EXPAND)
        self.SetSizer(spsizer)

if __name__ == '__main__':
    app = wx.App()
    frame = TestFrame(None, wx.ID_ANY, "Test Frame")
    frame.Show()
    app.MainLoop()

#2


1  

I don't know wxWidgets, but based on what I know of Python, I'm guessing that you need to change:

我不知道wxWidgets,但基于我对Python的了解,我猜你需要改变:

self.Bind(wx.EVT_MENU, self.subPanel(None, -1, 'TEST'),id=1)

to:

self.Bind(wx.EVT_MENU, subPanel(None, -1, 'TEST'),id=1)

"subPanel" is a globally defined class, not a member of "self" (which is a mainPanel).

“subPanel”是一个全局定义的类,不是“self”的成员(它是一个mainPanel)。

Edit: Ah, "Bind" seems to bind an action to a function, so you need to give it a function that creates the other class. Try the following. It still doesn't work, but at least it now crashes during the subPanel creation.

编辑:啊,“Bind”似乎将一个动作绑定到一个函数,所以你需要给它一个创建另一个类的函数。请尝试以下方法。它仍然不起作用,但至少它现在在subPanel创建过程中崩溃。

self.Bind(wx.EVT_MENU, lambda(x): subPanel(None, -1, 'TEST'),id=1)

#3


1  

You should handle the button click event, and create the panel in your button handler (like you already do with your OnQuit method).

您应该处理按钮单击事件,并在按钮处理程序中创建面板(就像您已经使用OnQuit方法一样)。

I think the following code basically does what you're after -- creates a new Frame when the button is clicked/menu item is selected.

我认为以下代码基本上就是你所追求的 - 当单击按钮/选择菜单项时创建一个新的框架。

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, title="My Frame", num=1):

        self.num = num
        wx.Frame.__init__(self, parent, -1, title)
        panel = wx.Panel(self)

        button = wx.Button(panel, -1, "New Panel")
        button.SetPosition((15, 15))
        self.Bind(wx.EVT_BUTTON, self.OnNewPanel, button)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

        # Now create a menu
        menubar = wx.MenuBar()
        self.SetMenuBar(menubar)

        # Panel menu
        panel_menu = wx.Menu()

        # The menu item
        menu_newpanel = wx.MenuItem(panel_menu,
                                    wx.NewId(),
                                    "&New Panel",
                                    "Creates a new panel",
                                    wx.ITEM_NORMAL)
        panel_menu.AppendItem(menu_newpanel)

        menubar.Append(panel_menu, "&Panels")
        # Bind the menu event
        self.Bind(wx.EVT_MENU, self.OnNewPanel, menu_newpanel)

    def OnNewPanel(self, event):
        panel = MyFrame(self, "Panel %s" % self.num, self.num+1)
        panel.Show()

    def OnCloseWindow(self, event):
        self.Destroy()

def main():
    application = wx.PySimpleApp()
    frame = MyFrame(None)
    frame.Show()
    application.MainLoop()

if __name__ == "__main__":
    main()

Edit: Added code to do this from a menu.

编辑:添加了从菜单中执行此操作的代码。

#1


0  

You need an event handler in your bind expression

您需要在绑定表达式中使用事件处理程序

self.bind(wx.EVT_MENU, subPanel(None, -1, 'TEST'),id=1)

needs to be changed to:

需要改为:

self.bind(wx.EVT_MENU, <event handler>, <id of menu item>)

where your event handler responds to the event and instantiates the subpanel:

您的事件处理程序响应事件并实例化子面板:

def OnMenuItem(self, evt): #don't forget the evt
    sp = SubPanel(self, wx.ID_ANY, 'TEST')
    #I assume you will add it to a sizer
    #if you aren't... you should
    test_sizer.Add(sp, 1, wx.EXPAND)
    #force the frame to refresh the sizers:
    self.Layout()

Alternatively, you can instantiate the subpanel in your frame's __init__ and call a subpanel.Hide() after instantiation, and then your menuitem event handler and call a show on the panel subpanel.Show()

或者,您可以在框架的__init__中实例化子面板,并在实例化后调用subpanel.Hide(),然后调用menuitem事件处理程序并在面板subpanel.Show()上调用show。

Edit: Here is some code that will do what I think that you are asking:

编辑:这里有一些代码可以执行我认为您要问的内容:

#!usr/bin/env python

import wx

class TestFrame(wx.Frame):
    def __init__(self, parent, *args, **kwargs):
        wx.Frame.__init__(self, parent, *args, **kwargs)
        framesizer = wx.BoxSizer(wx.VERTICAL)
        mainpanel = MainPanel(self, wx.ID_ANY)
        self.subpanel = SubPanel(self, wx.ID_ANY)
        self.subpanel.Hide()
        framesizer.Add(mainpanel, 1, wx.EXPAND)
        framesizer.Add(self.subpanel, 1, wx.EXPAND)
        self.SetSizerAndFit(framesizer)

class MainPanel(wx.Panel):
    def __init__(self, parent, *args, **kwargs):
        wx.Panel.__init__(self, parent, *args, **kwargs)
        panelsizer = wx.BoxSizer(wx.VERTICAL)
        but = wx.Button(self, wx.ID_ANY, "Add")
        self.Bind(wx.EVT_BUTTON, self.OnAdd, but)
        self.panel_shown = False
        panelsizer.Add(but, 0)
        self.SetSizer(panelsizer)

    def OnAdd(self, evt):
        if not self.panel_shown:
            self.GetParent().subpanel.Show()
            self.GetParent().Fit()
            self.GetParent().Layout()
            self.panel_shown = True
        else:
            self.GetParent().subpanel.Hide()
            self.GetParent().Fit()
            self.GetParent().Layout()
            self.panel_shown = False

class SubPanel(wx.Panel):
    def __init__(self, parent, *args, **kwargs):
        wx.Panel.__init__(self, parent, *args, **kwargs)
        spsizer = wx.BoxSizer(wx.VERTICAL)
        text = wx.StaticText(self, wx.ID_ANY, label='I am a subpanel')
        spsizer.Add(text, 1, wx.EXPAND)
        self.SetSizer(spsizer)

if __name__ == '__main__':
    app = wx.App()
    frame = TestFrame(None, wx.ID_ANY, "Test Frame")
    frame.Show()
    app.MainLoop()

#2


1  

I don't know wxWidgets, but based on what I know of Python, I'm guessing that you need to change:

我不知道wxWidgets,但基于我对Python的了解,我猜你需要改变:

self.Bind(wx.EVT_MENU, self.subPanel(None, -1, 'TEST'),id=1)

to:

self.Bind(wx.EVT_MENU, subPanel(None, -1, 'TEST'),id=1)

"subPanel" is a globally defined class, not a member of "self" (which is a mainPanel).

“subPanel”是一个全局定义的类,不是“self”的成员(它是一个mainPanel)。

Edit: Ah, "Bind" seems to bind an action to a function, so you need to give it a function that creates the other class. Try the following. It still doesn't work, but at least it now crashes during the subPanel creation.

编辑:啊,“Bind”似乎将一个动作绑定到一个函数,所以你需要给它一个创建另一个类的函数。请尝试以下方法。它仍然不起作用,但至少它现在在subPanel创建过程中崩溃。

self.Bind(wx.EVT_MENU, lambda(x): subPanel(None, -1, 'TEST'),id=1)

#3


1  

You should handle the button click event, and create the panel in your button handler (like you already do with your OnQuit method).

您应该处理按钮单击事件,并在按钮处理程序中创建面板(就像您已经使用OnQuit方法一样)。

I think the following code basically does what you're after -- creates a new Frame when the button is clicked/menu item is selected.

我认为以下代码基本上就是你所追求的 - 当单击按钮/选择菜单项时创建一个新的框架。

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, title="My Frame", num=1):

        self.num = num
        wx.Frame.__init__(self, parent, -1, title)
        panel = wx.Panel(self)

        button = wx.Button(panel, -1, "New Panel")
        button.SetPosition((15, 15))
        self.Bind(wx.EVT_BUTTON, self.OnNewPanel, button)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

        # Now create a menu
        menubar = wx.MenuBar()
        self.SetMenuBar(menubar)

        # Panel menu
        panel_menu = wx.Menu()

        # The menu item
        menu_newpanel = wx.MenuItem(panel_menu,
                                    wx.NewId(),
                                    "&New Panel",
                                    "Creates a new panel",
                                    wx.ITEM_NORMAL)
        panel_menu.AppendItem(menu_newpanel)

        menubar.Append(panel_menu, "&Panels")
        # Bind the menu event
        self.Bind(wx.EVT_MENU, self.OnNewPanel, menu_newpanel)

    def OnNewPanel(self, event):
        panel = MyFrame(self, "Panel %s" % self.num, self.num+1)
        panel.Show()

    def OnCloseWindow(self, event):
        self.Destroy()

def main():
    application = wx.PySimpleApp()
    frame = MyFrame(None)
    frame.Show()
    application.MainLoop()

if __name__ == "__main__":
    main()

Edit: Added code to do this from a menu.

编辑:添加了从菜单中执行此操作的代码。