Zugriff von Panel-Class auf Methoden der Application-Class

Plattformunabhängige GUIs mit wxWidgets.
Antworten
tobias.vdk
User
Beiträge: 19
Registriert: Mittwoch 23. November 2005, 16:51

Hallo!

Ich habe ein Programm mit zwei Panel-Klassen, die ich in das Hauptpgrogramm mitteils import einbinde. Wenn ich jetzt aber über einen Button eine Methode der Application-Klasse das Hauptprogramms aufrufen will, müsste ich diese wiederum durch import einfügen. Dann kommt aber immer der Fehler:

Code: Alles auswählen

Traceback (most recent call last):
  File "createxml.py", line 2, in ?
    import configPanel
  File "/home/l142051/work/ldap/autoyast/script/python_gui/neu2/configPanel.py", line 2, in ?
    from createxml import Application
  File "/home/l142051/work/ldap/autoyast/script/python_gui/neu2/createxml.py", line 124, in ?
    frame = application()
  File "/home/l142051/work/ldap/autoyast/script/python_gui/neu2/createxml.py", line 19, in __init__
    self.pConfig = configPanel.Panel(self, self.ldapconfig, self.autoyastconfig, self.configFile)
AttributeError: 'module' object has no attribute 'Panel'
Application-Klasse (Auszug):

Code: Alles auswählen

import wx
import configPanel
import serverPanel
ID_CONFIG=100
ID_SERVER=102
ID_EXIT=110
ID_ABOUT=301

class application(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "createXML", size = (600,500))
        self.sizer = wx.BoxSizer()
        self.CreateToolBar()
        self.CreateStatusBar()
        self.createMenubar()
        self.configFile = "/home/l142051/work/ldap/autoyast/script/python_gui/config"
        self.ldapconfig = self.configLdap()
        self.autoyastconfig = self.configAutoyast()
        self.pConfig = configPanel.Panel(self, self.ldapconfig, self.autoyastconfig, self.configFile)
        self.pServer = serverPanel.Panel(self)
        self.sizer.Add(self.pConfig,1,wx.EXPAND)
        self.sizer.Add(self.pServer,1,wx.EXPAND)
        self.sizer.Show(self.pConfig, False)
        self.sizer.Show(self.pServer,False)
        self.SetSizerAndFit(self.sizer)
        self.sizer.Layout()
        self.Show(True)
configPanel-Klasse (Auszug):

Code: Alles auswählen

import wx
import createxml

class Panel(wx.Panel):
    def __init__(self, parent, ldapconfig, autoyastconfig, configFile):
        wx.Panel.__init__(self, parent, -1, style = wx.TAB_TRAVERSAL | wx.CLIP_CHILDREN | wx.FULL_REPAINT_ON_RESIZE)
        self.sConfig = wx.GridBagSizer(5,5)
        self.SetSizerAndFit(self.sConfig)
        
        width = 400

        self.ldapText = wx.StaticText(self, -1, "LDAP configuration")

        self.host = wx.StaticText(self, -1, "LDAP Server IP:")
        self.hostconf = wx.TextCtrl(self, -1, ldapconfig["host"], size=(width, -1))
        self.hostconf.SetInsertionPoint(0)

        self.port = wx.StaticText(self, -1, "openLDAP port:")
        self.portconf = wx.TextCtrl(self, -1, ldapconfig["port"], size=(width, -1))
        self.portconf.SetInsertionPoint(0)

        self.version = wx.StaticText(self, -1, "openLDAP version:")
        self.versionconf = wx.TextCtrl(self, -1, ldapconfig["version"], size=(width, -1))
        self.versionconf.SetInsertionPoint(0)

        self.autoyastText = wx.StaticText(self, -1, "AutoYaST configuration")

        self.base = wx.StaticText(self, -1, "ayBaseconfig:")
        self.baseconf = wx.TextCtrl(self, -1, autoyastconfig["baseconfig"], size=(width, -1))
        self.baseconf.SetInsertionPoint(0)

        self.server = wx.StaticText(self, -1, "ayServer:")
        self.serverconf = wx.TextCtrl(self, -1, autoyastconfig["server"], size=(width, -1))
        self.serverconf.SetInsertionPoint(0)

        self.hw = wx.StaticText(self, -1, "ayHardwarepool:")
        self.hwconf = wx.TextCtrl(self, -1, autoyastconfig["hardwarepool"], size=(width, -1))
        self.hwconf.SetInsertionPoint(0)

        self.report = wx.StaticText(self, -1, "ayReport:")
        self.reportconf = wx.TextCtrl(self, -1, autoyastconfig["report"], size=(width, -1))
        self.reportconf.SetInsertionPoint(0)

        self.security = wx.StaticText(self, -1, "aySecurity:")
        self.securityconf = wx.TextCtrl(self, -1, autoyastconfig["security"], size=(width, -1))
        self.securityconf.SetInsertionPoint(0)

        self.software = wx.StaticText(self, -1, "aySoftware:")
        self.softwareconf = wx.TextCtrl(self, -1, autoyastconfig["software"], size=(width, -1))
        self.softwareconf.SetInsertionPoint(0)

        self.x11 = wx.StaticText(self, -1, "ayX11Conf:")
        self.x11conf = wx.TextCtrl(self, -1, autoyastconfig["x11conf"], size=(width, -1))
        self.x11conf.SetInsertionPoint(0)

        #self.safeButton = wx.Button(self.pConfig, wx.ID_SAVE, "")
        self.safeButton = wx.Button(self, -1, "Save")
        self.Bind(wx.EVT_BUTTON, saveConfig, self.safeButton)

        self.undoButton = wx.Button(self, -1, "Undo")
        self.Bind(wx.EVT_BUTTON, undoConfig, self.undoButton)
        

        i = 1
        j = 1

        self.sConfig.Add(self.ldapText, (i,j))
        i = i + 1
        self.sConfig.Add(self.host, (i,j))
        self.sConfig.Add(self.hostconf, (i,j+1))
        i = i + 1
        self.sConfig.Add(self.port, (i,j))
        self.sConfig.Add(self.portconf, (i,j+1))
        i = i + 1
        self.sConfig.Add(self.version, (i,j))
        self.sConfig.Add(self.versionconf, (i,j+1))
        i = i + 2
        self.sConfig.Add(self.autoyastText, (i,j))
        i = i + 1
        self.sConfig.Add(self.base, (i,j))
        self.sConfig.Add(self.baseconf, (i,j+1))
        i = i + 1
        self.sConfig.Add(self.hw, (i,j))
        self.sConfig.Add(self.hwconf, (i,j+1))
        i = i + 1
        self.sConfig.Add(self.software, (i,j))
        self.sConfig.Add(self.softwareconf, (i,j+1))
        i = i + 1
        self.sConfig.Add(self.server, (i,j))
        self.sConfig.Add(self.serverconf, (i,j+1))
        i = i + 1
        self.sConfig.Add(self.report, (i,j))
        self.sConfig.Add(self.reportconf, (i,j+1))
        i = i + 1        
        self.sConfig.Add(self.security, (i,j))
        self.sConfig.Add(self.securityconf, (i,j+1))
        i = i + 1        
        self.sConfig.Add(self.x11, (i,j))
        self.sConfig.Add(self.x11conf, (i,j+1))
        i = i + 1
        self.sConfig.Add(self.undoButton, (i,j))
        self.sConfig.Add(self.safeButton, (i,j+1))

        self.Show(False)
Kann mir jemand einen Hinweise geben?

Tobias
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Hallo,

kannst du nicht einfach diese Funktion in das file mit der Panel klasse
selbst geben?

(Vom main file wird ja sowiese panel1.py und panel2.py importiert).

Oder:
wenn z.B. die Application Klasse das parent vom Panel ist.

in etwa:

Code: Alles auswählen

def OnButton(self, event):
     self.GetParent.MyAppFunction()
Edit (Leonidas): Code in Python-Tags gesetzt.
tobias.vdk
User
Beiträge: 19
Registriert: Mittwoch 23. November 2005, 16:51

Wenn ich nun das "eigentliche" Programm (in der Datei application.py als Klasse,oder so) vom Rest (Frame und Panels) trennen möchte, wie kann dann ein Child dieser Klasse erzeugen, um vom einem Panel aus mittels self.GetParent().GetChild().Function() auf eine Funktionen dieser application zugreifen zu können.
Klingt bestimmt kompliziert. Vielleicht kann mir ja trotzdem jemand helfen.

Tobias
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

tobias.vdk hat geschrieben:Wenn ich nun das "eigentliche" Programm (in der Datei application.py als Klasse,oder so) vom Rest (Frame und Panels) trennen möchte, wie kann dann ein Child dieser Klasse erzeugen, um vom einem Panel aus mittels self.GetParent().GetChild().Function() auf eine Funktionen dieser application zugreifen zu können.
Klingt bestimmt kompliziert. Vielleicht kann mir ja trotzdem jemand helfen.

Tobias
Ich weiss nicht ob ich dich richtig verstehe.

Aber warum gibst du nicht einfach die instanz deine applikation beim
erstellen des Frame oder Panelobjektes mit an?
Dann kannst du zugreifen darauf:

pseudo (in application):

Code: Alles auswählen



def MyAppFunction(...)

self.MyPanel = Panel1(self)
...


in sagen wir panel.py:

Code: Alles auswählen

class Panel1 (wx.Panel)
  def __init__(self, app, ...
     ...
     self.app = app

dann:
  def OnButton...
     self.app.AppFunction(....
da braucht man im Panel.py das App.py oder wie wir es nennen wollen,
nicht einzubinden (Ist ja nicht C++, wo alles vorher definiert werden muss).

Die Frage hat eigentlich eh nicht so viel mit wxPython zu tun,
sodass man diese eigentlich zu den allgemeinen Fragen verschieben könnte.
Zuletzt geändert von Francesco am Donnerstag 22. Dezember 2005, 16:23, insgesamt 1-mal geändert.
tobias.vdk
User
Beiträge: 19
Registriert: Mittwoch 23. November 2005, 16:51

Ich dachte an folgendes:

application.py:

Code: Alles auswählen

import os
import wx
import ldap
import mainFrame

class application(wx.App):
    def OnInit(self):
        self.frame = mainFrame.Frame(self)
        self.SetTopWindow(self.frame)
        self.frame.Show(True)
    
     def function1()
        ...
application(0).MainLoop()
mainFrame.py:

Code: Alles auswählen

import wx

import panelConfig
import panelServer
ID_CONFIG=101
ID_SERVER=102
ID_EXIT=110
ID_ABOUT=301

class Frame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, "createXML", size = (600,500))
        self.sizer = wx.BoxSizer()
        self.CreateToolBar()
        self.CreateStatusBar()
        self.createMenubar()
        self.pConfig = panelConfig.Panel(self)
        self.pServer = panelServer.Panel(self)
        self.sizer.Add(self.pConfig, 1, wx.EXPAND)
        self.sizer.Add(self.pServer, 1, wx.EXPAND)
        self.sizer.Show(self.pConfig, False)
        self.sizer.Show(self.pServer, False)
        self.SetSizer(self.sizer)
        self.sizer.Layout()
2x panel:

Code: Alles auswählen

import wx

class Panel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1, style = wx.TAB_TRAVERSAL | wx.CLIP_CHILDREN | wx.FULL_REPAINT_ON_RESIZE)
doch folgende Fehlermeldung tritt auf:

Code: Alles auswählen

Traceback (most recent call last):
  File "createxml2.py", line 863, in ?
    application(0).MainLoop()
  File "/usr/lib/python2.3/site-packages/wx-2.6-gtk2-unicode/wx/_core.py", line 6151, in __init__
    self._BootstrapApp()
  File "/usr/lib/python2.3/site-packages/wx-2.6-gtk2-unicode/wx/_core.py", line 5803, in _BootstrapApp
    return _core_.PyApp__BootstrapApp(*args, **kwargs)
  File "createxml2.py", line 8, in OnInit
    self.frame = mainFrame.Frame(self)
  File "/home/l142051/work/ldap/autoyast/script/python_gui/neu/mainFrame.py", line 12, in __init__
    wx.Frame.__init__(self, parent, -1, "createXML", size = (600,500))
  File "/usr/lib/python2.3/site-packages/wx-2.6-gtk2-unicode/wx/_windows.py", line 476, in __init__
    newobj = _windows_.new_Frame(*args, **kwargs)
TypeError: argument number 1: a 'wxWindow *' is expected, 'PySwigObject(_p_wxPyApp)' is received
das liegt an dem "(self)" in "self.frame = mainFrame.Frame(self)", aber wie soll ich sonst mittels GetParent() von den Panels auf zb, function1 der application zugreifen?

Tobias
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Das kann nicht gehen:

Du musst beim Frame ein TopWindow angeben.
Wenn keines da ist, dann übergibst du None.

also stattt
self.frame = mainFrame.Frame(self)

self.frame = mainFrame.Frame(None)

also funktion1 ist im wx.App class.

In Panel kannst du aufrufen:
app = wx.GetApp()
app.function1()

das ist einfacher als die app instance zu übergeben.

dann würde es so aussehen:

Code: Alles auswählen

self.frame = mainFrame.Frame(None, self) 

class Frame(wx.Frame):
    def __init__(self, parent, app):
        wx.Frame.__init__(self, parent, -1, "createXML", size = (600,500))
        ...
        self.pConfig = panelConfig.Panel(self, app)

        self.sizer = wx.BoxSizer() 

class Panel(wx.Panel):
    def __init__(self, parent, app):
        wx.Panel.__init__(...
        self.app = app
    def onbtn (...
       self.app.function1()
tobias.vdk
User
Beiträge: 19
Registriert: Mittwoch 23. November 2005, 16:51

Das funktioniert leider nicht. Wenn ich im mainFrame:

Code: Alles auswählen

class Frame(wx.Frame):

    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, "createXML", size = (600,500))
        ...
        self.app = wx.GetApp()

    def createFilemenu(self):

        """Create the File menu."""

        self.filemenu = wx.Menu()
        self.filemenu.Append(ID_CONFIG,"&Preferences"," Show/change preferences...")

        wx.EVT_MENU(self, ID_CONFIG, self.app.configure())
kommt die Fehlermeldung:

Code: Alles auswählen

AttributeError: 'Frame' object has no attribute 'app'
Woran liegt das? Auch das Übergeben der app Instanz (dein 2. Beispiel) liefert den gleichen Fehler.
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Code: Alles auswählen

class Frame(wx.Frame):

    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, "createXML", size = (600,500))
        ...
        self.app = wx.GetApp()

    def createFilemenu(self):

        """Create the File menu."""

        self.filemenu = wx.Menu()
        self.filemenu.Append(ID_CONFIG,"&Preferences"," Show/change preferences...")

        wx.EVT_MENU(self, ID_CONFIG, self.app.configure())
Ehm, rufst du im init self.app eh vor dem createFilemenu auf?

Code: Alles auswählen


    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, "createXML", size = (600,500))
        #vorher ...
        self.app = wx.GetApp()
        #erst jetzt...
        self.createFilemenu()
sonst kann ich mir nicht vorstellen, dass es nicht funktionieren sollte.
das mit wx.GetApp() funktioniert ja, oder?
tobias.vdk
User
Beiträge: 19
Registriert: Mittwoch 23. November 2005, 16:51

Genau das hab' ich natürlich nicht gemacht.... jetzt funktioniert's.

Vielen Dank!

Tobias
Antworten