Dynamische Generierung von Eingabemasken

Fragen zu Tkinter.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: Du hast es noch nicht ganz erfasst: Deine Wörterbuchklasse ist ganz und gar überflüssig. Definition der Formularelemente und Inhalt sind zwei verschiedene Dinge und gehören nicht in einer Klasse gemischt. Die Definition kannst Du noch um mehrere Sprachen, Anzeigeoptionen und Validierung erweitern, trotzdem ist das kein Wörterbuch und erst recht keins, wofür eine eigene Klasse nötig wäre.
Wie würdest Du dann das machen?

Code: Alles auswählen

# -*- coding: utf-8 -*-

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

class ConfigAdvanced:


    KEYS = [
"tags",
"title",
"geometry",
'minsize',
'maxsize',
'resizable',
"from", # Spinbox (decimal default 0.0)
"to",   # Spinbox, Scale (decimal Spinbox default 0,0, Scale default 100.0)
"increment", # Spinbox, (decimal default 1.0)
"resolution", # Scale (decimal default 1.0)
"bigincrement", # Scale (decimal default 0.0)
"showvalue",
"tickinterval", # Scale (decimal default 0.0)
"digits", # Scale (Integer default 0)
"orient",
"label",
"text",
"underline",
"myclass",
"baseclass",
"call Code(self)",
"link",
"photoimage",
"activephotoimage",
"disabledphotoimage",
'bitmap',
'activebitmap',
'disabledbitmap',
"compound",
"type",
"selectmode",
"state",
"default",
"relief",
"sliderrelief",
"overrelief",
"buttondownrelief",
'style',
'start',
'extent',
'arrow',
'arrowshape',
'capstyle',
'joinstyle',
'smooth',
'splinesteps',
"width",
"height",
"outline",
"dash",
"dashoffset",
"outlinestipple",
"outlineoffset",
"fill",
"stipple",
"offset",
"activewidth",
"activeoutline",
"activeoutlineoffset",
"activedash",
"activeoutlinestipple",
"activefill",
"activestipple",
"disabledwidth",
"disabledoutline",
"disabledoutlineoffset",
"disableddash",
"disabledoutlinestipple",
"disabledfill",
"disabledstipple",
"length",
"sliderlength",
"wraplength",
"padx", # often (Label: Integer default 0, Button ? default 3m)
"pady", # often (Label: Integer default 0, Button ? default 1m)
"bd",
"anchor",
"justify",
"font",
"fg",
"bg",
"foreground",
"background",
"troughcolor",
"selectforeground",
"selectbackground",
"insertwidth",
"insertborderwidth",
"insertontime",
"selectborderwidth",
"activeforeground",
"activebackground",
"disabledforeground",
"disabledbackground",
"highlightcolor",
"highlightbackground",
"highlightthickness",
"sashrelief",
"sashwidth",
"sashpad",
"opaqueresize",
"sashcursor",
"showhandle",
"handlesize",
"handlepad",
"takefocus",
"cursor" ]


    def __init__(self,extern_dictionary):
        self.extern_dictionary = extern_dictionary

    def get_dictionary(self):
        dictionary = {}
        for key in self.extern_dictionary.config():
            dictionary[key] = self.extern_dictionary[key]
        return dictionary

    def config(self,**kwargs):
        if kwargs:
            self.extern_dictionary.config(**kwargs)
        return self.get_dictionary()

    def __getitem__(self,key):
        return self.config()[key]
 
    def __setitem__(self,key,value):
        try:
            self.config(**{key : value})
        except tk.TclError:
            pass

    def keys(self):

        keys = []
        dictionary = dict(self.get_dictionary())

        for key in KEYS:
            if key in dictionary:
                keys.append(key)
            dictionary.pop(key,None)

        for key in dictionary:
            keys.append(key)

        return keys


class Application(tk.Tk):

    def __init__(self,**kwargs):
        tk.Tk.__init__(self,**kwargs)
        # widget definitions ===================================
        self.Eingabemaske = Eingabemaske(self) # basisklasse.Eingabemaske
        self.Eingabemaske.pack(fill='x',expand =1)
        self.Eingabemaske.show_config(tk.Entry())
        

class Eingabemaske(tk.LabelFrame):

    def __init__(self,master,**kwargs):
        tk.LabelFrame.__init__(self,master,**kwargs)
        self.config(text='Eingabemaske')
        
        
        # code =================================================


    def show_config(self,widget):
        
        class Code_Eingabemaske:
            def __init__(self,container):
                self.container = container

            def create_Eingabemaske(self,input_object):
                self.input_object = input_object # for OK button

                keys = input_object.keys()
                maxlen = max(map(len, keys))

                self.content = tk.Frame(self.container)
                self.content.pack(fill = 'x' , expand = 1)

                def set_value(event,me,widget,key):
                    widget[key] = me.get()

                for key in keys:
                    frame = tk.Frame(self.content)
                    frame.pack(fill='x',expand = 1)
                    label = tk.Label(frame,text = key, width = maxlen+1,anchor = 'e')
                    label.pack(side = 'left')

                    width = 30
                    expand = 0
                    fill = 'x'
                    # ===========================================
                        
                    entry = tk.Entry(frame,width = width)

                    entry.delete(0,'end')
                    entry.insert(0,str(input_object[key]))
                    entry.pack(side = 'left',fill = fill,expand= expand,padx = 5,pady=1)

                    entry.bind('<Return>', lambda event, entry = entry, widget = ConfigAdvanced(entry), key = key: set_value(event,entry,widget,key))

        Code_Eingabemaske(self).create_Eingabemaske(widget)

if __name__ == '__main__':
    Application().mainloop()
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Natürlich sollte man noch eine Rückmeldung geben, dass es ausgeführt wurde und einen falschen Wert soll man nicht so stehen lassen

Es war außerdem noch ein Fehler drin: ich hatte nicht dieses Dictionary als Parameter übergeben sondern einen tk.Entry. Deshalb war die Liste auch nicht sortiert.

Die Methode key gibt es auch für widgets. Da ist es dann die alphabetische Reihenfolge.

Code: Alles auswählen

# -*- coding: utf-8 -*-

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

class ConfigAdvanced:


    KEYS = [
"tags",
"title",
"geometry",
'minsize',
'maxsize',
'resizable',
"from", # Spinbox (decimal default 0.0)
"to",   # Spinbox, Scale (decimal Spinbox default 0,0, Scale default 100.0)
"increment", # Spinbox, (decimal default 1.0)
"resolution", # Scale (decimal default 1.0)
"bigincrement", # Scale (decimal default 0.0)
"showvalue",
"tickinterval", # Scale (decimal default 0.0)
"digits", # Scale (Integer default 0)
"orient",
"label",
"text",
"underline",
"myclass",
"baseclass",
"call Code(self)",
"link",
"photoimage",
"activephotoimage",
"disabledphotoimage",
'bitmap',
'activebitmap',
'disabledbitmap',
"compound",
"type",
"selectmode",
"state",
"default",
"relief",
"sliderrelief",
"overrelief",
"buttondownrelief",
'style',
'start',
'extent',
'arrow',
'arrowshape',
'capstyle',
'joinstyle',
'smooth',
'splinesteps',
"width",
"height",
"outline",
"dash",
"dashoffset",
"outlinestipple",
"outlineoffset",
"fill",
"stipple",
"offset",
"activewidth",
"activeoutline",
"activeoutlineoffset",
"activedash",
"activeoutlinestipple",
"activefill",
"activestipple",
"disabledwidth",
"disabledoutline",
"disabledoutlineoffset",
"disableddash",
"disabledoutlinestipple",
"disabledfill",
"disabledstipple",
"length",
"sliderlength",
"wraplength",
"padx", # often (Label: Integer default 0, Button ? default 3m)
"pady", # often (Label: Integer default 0, Button ? default 1m)
"bd",
"anchor",
"justify",
"font",
"fg",
"bg",
"foreground",
"background",
"troughcolor",
"selectforeground",
"selectbackground",
"insertwidth",
"insertborderwidth",
"insertontime",
"selectborderwidth",
"activeforeground",
"activebackground",
"disabledforeground",
"disabledbackground",
"highlightcolor",
"highlightbackground",
"highlightthickness",
"sashrelief",
"sashwidth",
"sashpad",
"opaqueresize",
"sashcursor",
"showhandle",
"handlesize",
"handlepad",
"takefocus",
"cursor" ]


    def __init__(self,extern_dictionary):
        self.extern_dictionary = extern_dictionary

    def get_dictionary(self):
        dictionary = {}
        for key in self.extern_dictionary.config():
            dictionary[key] = self.extern_dictionary[key]
        return dictionary

    def config(self,**kwargs):
        if kwargs:
            self.extern_dictionary.config(**kwargs)
        return self.get_dictionary()

    def __getitem__(self,key):
        return self.config()[key]
 
    def __setitem__(self,key,value):
        try:
            self.config(**{key : value})
        except tk.TclError:
            pass

    def keys(self):

        keys = []
        dictionary = dict(self.get_dictionary())

        for key in self.KEYS:
            if key in dictionary:
                keys.append(key)
            dictionary.pop(key,None)

        for key in dictionary:
            keys.append(key)

        return keys


class Application(tk.Tk):

    def __init__(self,**kwargs):
        tk.Tk.__init__(self,**kwargs)
        # widget definitions ===================================
        self.Eingabemaske = Eingabemaske(self) # basisklasse.Eingabemaske
        self.Eingabemaske.pack(fill='x',expand =1)
        self.Eingabemaske.show_config(ConfigAdvanced(tk.Entry()))
        

class Eingabemaske(tk.LabelFrame):

    def __init__(self,master,**kwargs):
        tk.LabelFrame.__init__(self,master,**kwargs)
        self.config(text='Eingabemaske')
        
        
        # code =================================================


    def show_config(self,widget):
        
        class Code_Eingabemaske:
            def __init__(self,container):
                self.container = container

            def create_Eingabemaske(self,input_object):
                self.input_object = input_object # for OK button

                keys = input_object.keys()
                maxlen = max(map(len, keys))

                self.content = tk.Frame(self.container)
                self.content.pack(fill = 'x' , expand = 1)


                def get_value(me,widget,key,bg):
                    me['bg'] = bg
                    me.delete(0,'end')
                    me.insert(0,widget[key])

                def set_value(event,me,widget,key):
                    widget[key] = me.get()
                    my_bg = me['bg']
                    me['bg'] = 'gray'
                    me.after(300,lambda me=me,widget=widget,key=key,bg = my_bg:get_value(me,widget,key,bg))

                for key in keys:
                    frame = tk.Frame(self.content)
                    frame.pack(fill='x',expand = 1)
                    label = tk.Label(frame,text = key, width = maxlen+1,anchor = 'e')
                    label.pack(side = 'left')

                    width = 30
                    expand = 0
                    fill = 'x'
                    # ===========================================
                        
                    entry = tk.Entry(frame,width = width)

                    entry.delete(0,'end')
                    entry.insert(0,str(input_object[key]))
                    entry.pack(side = 'left',fill = fill,expand= expand,padx = 5,pady=1)

                    entry.bind('<Return>', lambda event, entry = entry, widget = ConfigAdvanced(entry), key = key: set_value(event,entry,widget,key))



        Code_Eingabemaske(self).create_Eingabemaske(widget)


if __name__ == '__main__':
    Application().mainloop()
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer:
Jetzt hat diese Klasse zwei Aufgaben, die nichts miteinander zu tun haben: 1. das festlegen der Schlüssel, die nicht als Konstante in einer Klasse, sondern als Konfigurationsparameter übergeben werden sollte und 2. das Speichern der Eingaben, was auch durch ein einfaches Wörterbuch möglich wäre. Die Klasse wird also ersetzt durch Wörterbuch und Liste
Das bringt ja wohl nichts, denn das Wörterbuch behandelt keine Falscheingaben. Und wie soll ein Programmteil, der ein Wörterbuch und eine Liste erhält, dann wissen, wie die Eingaben zu speichern sind?

Also der für die Darstellung der Eingabe verantwortliche Programmteil erhält genau ein Objekt und das behandelt auch das Abspeichern und fehlende Eingaben bzw. Falscheingaben.

Dieser Programmteil muss einen Save Button darstellen und wenn der Benutzer den Button drückt, braucht nur die Save Methode des betreffenden Objektes aufgerufen werden, nachdem man vorher die Werte an es übergeben hat.

Was save machen soll, muss und soll dem für das dynamische Gui Layout verantwortlichen Programmteil nicht bekannt sein. Daher kann dieser beliebige derartige Objekte behandeln.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: wie soll ein Wörterbuch auch Falscheingaben behandeln? Das Wörterbuch ist doch nur dazu da, die Formdaten zu speichern. Mehr nicht!
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: Du hast es noch nicht ganz erfasst: Deine Wörterbuchklasse ist ganz und gar überflüssig. Definition der Formularelemente und Inhalt sind zwei verschiedene Dinge und gehören nicht in einer Klasse gemischt. Die Definition kannst Du noch um mehrere Sprachen, Anzeigeoptionen und Validierung erweitern, trotzdem ist das kein Wörterbuch und erst recht keins, wofür eine eigene Klasse nötig wäre.
Wo sind da Formularelemente in Inhalt vermischt? Formularelemente sind etwa Label und Entry. Davon steht nichts im Wörterbuch. Im Wörterbuch steht die Bezeichnung als key und der dazugehörige Wert.

Die Gui Layout Klasse muss aus dem Wörterbuch und der sortierten Liste das Layout mit Anzeige der Werte erstellen und außerdem dafür sorgen, dass die Eingaben mit der Wörterbuchklasse in der geforderten Art und Weise verknüpft werden. Also Einzeleingaben, die bei Enter gleich in die Wörterbuchklasse übernommen werden oder auch der Button der am Ende alles übernimmt. Die Wörterbuchklasse ist nötig, weil sie auch Falscheingaben behandelt, was ein Wörterbuch nicht kann. Außerdem müssen bei der Variante mit Eingabe erst und Sichern über den Button, die Werte auch abgespeichert werden.

Stellst Du Dir vor, dass die Gui Layoutklasse ein Dictionary, eine Liste, eine Save Methode , eine Abcheckmethode für Einzeleingaben, eine Abcheckmethode für das Saven eine Abcheck mit Save Verknüpfmethode, eine Abcheck mit Wörterbucheintrag Verknüpfmethode als Parameter oder als Message übermittelt bekommt?

Das wäre nur eine völlig unnötige Verkomplizierung. Das übergebene Wörterbuch Objekt soll das gefälligst selber erledigen. Schließlich sollen Layout und Code für abchecken und speichern unabhängig voneinander sein.

Und hier geht es um dynamische Generierung von Eingabemasken und nicht um etwas, was die Gui Layout Maske von sich aus tun kann. Wie soll sie wissen, wie die Daten zu speichern sind, wenn die Save Routine nicht im Wörterbuch steht?
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: wie soll ein Wörterbuch auch Falscheingaben behandeln? Das Wörterbuch ist doch nur dazu da, die Formdaten zu speichern. Mehr nicht!
Nein es geht hier genau um die Ergänzung eines Wörterbuches. Das sind:

- sortierte Liste
- Falscheingaben
- fehlende Eingaben
- speichern
- abbrechen
- nebst normalem Wörterbuchzugriff

Wenn es sich nur um den Wörterbuchzugriff handeln würde, bräuchte man diese Klasse nicht.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Abbrechen ist auch wichtig. Hatte ich glatt vergessen. Denn wenn die Erfassung beendet ist, entweder durch Speichern oder Abbrechen, muss eine Gui instanz benachrichtigt werden, die dann entscheidet, wie es weiter geht.

Muss eventuell benachrichtigt werden, das kommt darauf an, ob ein bestimmter Ablauf stattfinden soll. Wenn man etwa in der Stammdatenpflege war, soll es dann wieder dahin zurückgehen, ohne dass man das wieder extra über das Menü auswählen muss.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Wie sieht so eine Klasse für Eingabe und abspeichern in der Realität aus?

Wenn wir darauf verzichten, Falscheingaben abzuprüfen, ob etwa die Postleitzahl 5 stellig ist und aus Ziffern besteht, können wir eine ganz allgemeine Klasse formulieren.

Außerdem arbeitet der Anwender mit dem Eventbroker, mit dem Nachrichten gesandt werden. Da wird dann allöes sehr einfach.

Die Klasse sieht vom header her so aus:

Code: Alles auswählen

class DynLayoutAndTreat:

    def __init__(self,cancel_id,save_id,database_id,database_kwargs):
Das sind drei Message IDs und ein Parameter.

Die ersten beiden davon sind dafür da, damit eine Instanz in der GUI entscheiden kann, wie es weiter gehen soll.

- cancel_id wird gesendet, wenn der Anwender die Erfassung abbricht
- save_id wird gesendet, wenn der Anwender die Daten speichert

Die dritte ID ist database_id. Sie wird an das Datenbank Modul gesendet, das daraufhin die Daten speichert.
Außerdem werden auch Parameter dazu an das Datenbank Modul gesendet. Diese sind in database_kwargs.

Zum Speichern sendet man folgendes:

Code: Alles auswählen

publish(database_id,**database_kwargs)
database_kwargs enthält die Parameter, welche die Datenbank braucht, nämlich wohin speichern, Neuerfassung, oder Änderung, aber das muss uns nicht interessieren.

Wichtig für uns ist erstens: database_kwargs enthält auch die keys als 'keys'
Zweitens ist wichtig: es könnte eine Neuerfassung oder eine Änderung von Daten sein.
database_kwargs enthält bereits vorhandene Daten für eine Änderung in 'record'.
Oder es ist eine Neuerfassung, dann enthält database_kwargs diese Daten nicht.

Komplett sieht dann die Klasse so aus:

Code: Alles auswählen

class DynLayoutAndTreat:

    def __init__(self,cancel_id,save_id,database_id,database_kwargs):

        self.cancel_id = cancel_id
        self.save_id = save_id

        self.database_id = database_id
        self.database_kwargs = database_kwargs
        self.list_of_keys = self.database_kwargs['keys']

        if not 'record' in self.database_kwargs or not self.database_kwargs['record']:
            self.database_kwargs['record'] = { key: '' for key in self.list_of_keys }            
        self.dictionary = self.database_kwargs['record']

    def cancel(self):
        publish(self.cancel_id)

    def save(self):

        for key in self.keys():
            if not len(self.dictionary[key].strip()):
                return False,key + ' fehlt'
        
        publish(self.database_id,**self.database_kwargs)
        publish(self.save_id)
        return True,''
 
    def __getitem__(self,key):
        return self.dictionary[key]

    def __setitem__(self,key,value):
        self.dictionary[key] = value

    def keys(self):
        return list(self.list_of_keys)
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Das komplette Beispiel sieht so aus:

Das ist die Applikation:

Code: Alles auswählen

# -*- coding: utf-8 -*-

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

import testcode
import baseclasses

class Application(tk.Tk):

    def __init__(self,**kwargs):
        tk.Tk.__init__(self,**kwargs)
        # widget definitions ===================================
        self.Eingabemaske = baseclasses.Eingabemaske(self)
        self.Eingabemaske.pack(fill='x')

        testcode.app_init(self)

if __name__ == '__main__':
    Application().mainloop()
In baseclasses ist die dynamische Eingabemaske.

baseclasses.py:

Code: Alles auswählen

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

import testcode

class Eingabemaske(tk.LabelFrame):

    def __init__(self,master,**kwargs):
        tk.LabelFrame.__init__(self,master,**kwargs)
        self.config(text='Eingabemaske')
       
        self.status_label = tk.Label(self)
        self.status_label.grid(column=0,row=1)

        self.okbutton = tk.Button(self,text = 'OK')
        self.okbutton.grid(column=0,row=1, sticky = 'e')

        self.cancelbutton = tk.Button(self,text = 'Cancel')
        self.cancelbutton.grid(column=0,row=1, sticky = 'w')

        # code =================================================

        testcode.Code_Eingabemaske(self)
Diesse hat einen Label zum Anzeigen, warum es mit dem Speichern nicht geklappt hat und einen Button zum Abbrechen und zum Speichern.

Und das ist dann der Code für alles:

testcode.py:

Code: Alles auswählen

testcode.py:
# -*- coding: utf-8 -*-

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk


from eventbroker import subscribe,publish


class DynLayoutAndTreat:

    def __init__(self,cancel_id,save_id,database_id,database_kwargs):

        self.cancel_id = cancel_id
        self.save_id = save_id

        self.database_id = database_id
        self.database_kwargs = database_kwargs
        self.list_of_keys = self.database_kwargs['keys']

        if not 'record' in self.database_kwargs or not self.database_kwargs['record']:
            self.database_kwargs['record'] = { key: '' for key in self.list_of_keys }            
        self.dictionary = self.database_kwargs['record']

    def cancel(self):
        publish(self.cancel_id)

    def save(self):

        for key in self.keys():
            if not len(self.dictionary[key].strip()):
                return False,key + ' fehlt'
        
        publish(self.database_id,**self.database_kwargs)
        publish(self.save_id)
        return True,''
 
    def __getitem__(self,key):
        return self.dictionary[key]

    def __setitem__(self,key,value):
        self.dictionary[key] = value

    def keys(self):
        return list(self.list_of_keys)

def app_init(self):
    keys = [ 'Name','Vorname','Straße','Hausnummer','PLZ','Ort',]
    publish("DYN_EINGABEMASKE",DynLayoutAndTreat("DYN_EINGABEMASKE_CANCEL","DYN_EINGABEMASKE_SAVE","DATABASE_ACESS",{ 'keys' : keys }))


class Code_Eingabemaske:
    def __init__(self,container):
        self.container = container
        self.container.okbutton['command'] = self.save_input
        self.container.cancelbutton['command'] = self.cancel
        self.container.grid_remove()

        subscribe("DYN_EINGABEMASKE",self.create_Eingabemaske)


    def cancel(self):
        self.input_object.cancel()
        self.container.grid_remove()
        self.content.destroy()
        

    def save_input(self):
        for entry in self.entrylist:
            self.input_object[entry.key] = str(entry.get())
        result,status = self.input_object.save()
        self.container.status_label.config(text = status,fg='blue',font = 'TkDefaultFont 10 bold')

        if result:
            self.container.grid_remove()
            self.content.destroy()


    def create_Eingabemaske(self,input_object):

        self.input_object = input_object # for OK button

        keys = input_object.keys()
        maxlen = max(map(len, keys))

        self.content = tk.Frame(self.container)
        self.content.grid(row = 0, column = 0)

        self.entrylist = [] # Liste mit den Eingabefeldern zum Speichern

        for key in keys:
            frame = tk.Frame(self.content)
            frame.pack(fill='x')
            label = tk.Label(frame,text = key, width = maxlen+1,anchor = 'e')
            label.pack(side = 'left')

            entry = tk.Entry(frame)
            entry.key = key # das ist zum Speichern
            self.entrylist.append(entry) # und das auch

            entry.delete(0,'end')
            entry.insert(0,str(input_object[key]))
            entry.pack(side = 'left',fill = 'x',expand = 1,padx = 5,pady=1)
            self.container.grid()
In app_init wird der Eingabemaske zugesandt, was sie darstellen soll und mit welchen Messages sie dann Speichern kann, bzw das Speichern oder Abbrechen mitteilen kann:

Code: Alles auswählen

def app_init(self):
    keys = [ 'Name','Vorname','Straße','Hausnummer','PLZ','Ort',]
    publish("DYN_EINGABEMASKE",DynLayoutAndTreat("DYN_EINGABEMASKE_CANCEL","DYN_EINGABEMASKE_SAVE","DATABASE_ACESS",{ 'keys' : keys }))
Und dann braucht es dazu den Eventbroker

eventbroker.py:

Code: Alles auswählen

import sys
def output(param):
    sys.stdout.write(param+'\n')

class EventBroker():
    def __init__(self):
        self._dictionary_ = {}
 
    def clear(self):
        self._dictionary_.clear()

    def subscribe(self,message_id,callback_or_alias,warning = True):

        is_string = True

        try: # python2
            is_string = isinstance(callback_or_alias,basestring)
        except NameError: #python 3
            is_string = isinstance(callback_or_alias,str)
            
        if is_string:
            if message_id not in self._dictionary_:
                self._dictionary_[message_id] = set()
            self._dictionary_[message_id].add(callback_or_alias)
            
        else:
            if message_id in self._dictionary_:

                callback = self._dictionary_[message_id]
                if isinstance(callback ,set):
                    output("EventBroker: message '{}' is a broadcast message. It's not allowed to overwrite it by a callback.".format(message_id))
                else:                
                    if not callback_or_alias:
                        del self._dictionary_[message_id]
                    else:
                        if warning:
                            output('EventBroker: callback already defined for message id: {}\nThe callback before will be overwritten'.format(message_id))
                        self._dictionary_[message_id] = callback_or_alias
            elif callback_or_alias:
                    self._dictionary_[message_id] = callback_or_alias
 

    def publish(self,message_id,*args,**kwargs):

        if message_id not in self._dictionary_:
            output('EventBroker: no callback defined for message: {},*{},**{}'.format(message_id,args,kwargs))
            return

        if 'ALL' in self._dictionary_:
            callback = self._dictionary_['ALL']
            if isinstance(callback ,set):
                for element in callback:
                    if element in self._dictionary_:
                        callback = self._dictionary_[element]
                        if isinstance(callback,set):
                            output("EventBroker: for message id '{}' is alias '{}' allowed, but no furter aliases for this alias".format(message_id,element))
                        else:
                            callback(message_id,*args,**kwargs)

        callback = self._dictionary_[message_id]
        if not isinstance(callback ,set):
            return callback(*args,**kwargs)
        for element in callback:
            if element in self._dictionary_:
                callback = self._dictionary_[element]
                if isinstance(callback,set):
                    output("EventBroker: for message id '{}' is alias '{}' allowed, but no furter aliases for this alias".format(message_id,element))
                else:
                    callback(*args,**kwargs)

eventbroker = EventBroker()
publish = eventbroker.publish
subscribe = eventbroker.subscribe
def subscribe_nowarning(message_id,callback_or_alias):
    eventbroker.subscribe(message_id,callback_or_alias,False)
stefanxfg
User
Beiträge: 85
Registriert: Sonntag 2. April 2017, 14:11

Also sind damit alle Felder erst einmal erzeugt. Aber wie sieht es denn damit aus, dass man später mit configure bestimmte Einstellungen z.B. für Entries ändern möchte.
Man braucht doch dann die Adressierung der Entries. Beim Erzeugen könnte man sich dass in eine Liste speichern. Die müsste dann zurückgegeben werden und in der zugehörigen Liste im Code übergeben werden.
Aber wie bewerkstelligt man das?
Antworten