Dynamische Generierung von Eingabemasken

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

Dieses Thema wurde an mich herangetragen und ist wohl des Behandelns wert.

Also, es gibt eine Funktion oder Methode. Diese erhält ein Objekt übergeben, aus dem eine Eingabemaske erstellt werden soll.

Das wäre der Ausgangspunkt:

Code: Alles auswählen

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

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


class Application(tk.Tk):

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

class Eingabemaske(tk.LabelFrame):

    def __init__(self,master,**kwargs):
        tk.LabelFrame.__init__(self,master,**kwargs)
        self.config(text='Eingabemaske')
        # widget definitions ===================================
        self.content = tk.Frame(self)
        self.content.pack(fill='x')

if __name__ == '__main__':
    Application().mainloop()
Doch wie geht das jetzt weiter?
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich sehe da nichts, das irgendwem irgendwie uebergeben wird - zumindest bezogen auf die Aufgabenstellung.

Da wirst du schon noch etwas mehr ausholen muessen.
stefanxfg
User
Beiträge: 85
Registriert: Sonntag 2. April 2017, 14:11

Dann nimm mal diese GUI. Es handelt sich um eine Tabelle. Diese soll eine Stadardtabellenform darstellen. Der Inhalt, bestehend aus Label und Entry, kann von der Anzahl der Zeilen variieren.
Der Sinn ist, die Standardform an verschiedenen Stellen der GUI einzfügen und dynamisch die Zeilen zu erzeugen. Ich denke da an Dictionaries für die Labels und davon abhängig die Zeilen zu erstellen.

Code: Alles auswählen

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

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

#import DynTkInter as tk # for GuiDesigner


# === general grid table definition =================
def grid_general_rows(container,rows,**kwargs):
    for row in range(rows):
        container.rowconfigure(row,**kwargs)

def grid_general_cols(container,columns,**kwargs):
    for column in range(columns):
        container.columnconfigure(column,**kwargs)

# Application definition ============================

class Application(tk.Tk):

    def __init__(self,**kwargs):
        tk.Tk.__init__(self,**kwargs)
        self.title('APP')
        self.geometry('1263x75+76+111')
        self.minsize(116, 1)
        self.maxsize(1444, 882)
        # individual grid definition ===========================
        self.rowconfigure(0,minsize=25, pad=0, weight=0)
        self.columnconfigure(0,minsize=75, pad=0, weight=1)
        # widget definitions ===================================
        self.MAINFRAME = MainFrame(self,name='#0_MAINFRAME')
        self.MAINFRAME.grid(row=0, sticky='nesw')

class MainFrame(tk.Frame):

    def __init__(self,master,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        self.myclass = 'MainFrame'
        # general grid definition ==============================
        grid_general_rows(self,2, minsize = 25, pad = 0, weight = 0)
        grid_general_cols(self,1, minsize = 0, pad = 0, weight = 1)
        # individual grid definition ===========================
        self.columnconfigure(0,minsize=75, pad=0, weight=1)
        # widget definitions ===================================
        self.TitleFrame = Titleframe(self,name='#1_TitleFrame')
        self.TitleFrame.grid(row=0, sticky='ew')
        self.ContentFrame = ContentFrame(self,name='#2_ContentFrame')
        self.ContentFrame.grid(row=1, sticky='ew')

class ContentFrame(tk.Frame):

    def __init__(self,master,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        self.myclass = 'ContentFrame'
        # general grid definition ==============================
        grid_general_cols(self,3, minsize = 0, pad = 0, weight = 1)
        # individual grid definition ===========================
        self.rowconfigure(0,minsize=25, pad=0, weight=0)
        self.columnconfigure(0,minsize=0, pad=0, weight=0)
        self.columnconfigure(1,minsize=0, pad=0, weight=0)
        self.columnconfigure(2,minsize=0, pad=100, weight=20)
        # widget definitions ===================================
        self.Bezeichnung = tk.Label(self,name='#3_Bezeichnung',anchor='w', justify='left', text='label', width=50)
        self.Bezeichnung.grid(row=0, sticky='nsw')
        self.entry = tk.Entry(self,name='#4_entry')
        self.entry.grid(column=2, row=0, sticky='nesw')

class Titleframe(tk.Frame):

    def __init__(self,master,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        self.myclass = 'Titleframe'
        # individual grid definition ===========================
        self.rowconfigure(0,minsize=25, pad=0, weight=0)
        self.columnconfigure(0,minsize=75, pad=0, weight=1)
        # widget definitions ===================================
        self.label = tk.Label(self,name='#5_label',anchor='w', fg='#0000FF', text='label', width=25)
        self.label.grid(row=0, sticky='nesw')

if __name__ == '__main__':
    #Application().mainloop('guidesigner/Guidesigner.py') # for GuiDesigner
    Application().mainloop()

Zuletzt geändert von Anonymous am Montag 26. Juni 2017, 19:41, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

__deets__ hat geschrieben:Ich sehe da nichts, das irgendwem irgendwie uebergeben wird - zumindest bezogen auf die Aufgabenstellung.

Da wirst du schon noch etwas mehr ausholen muessen.
Ja stimmt, da wurde noch nichts übergeben. Daher müssen wir die Klasse entwickeln, die übergeben wird. Und ich denke, die ist schon einmal für den Anfang nicht schlecht.

Wir können da ein eigenes Dictionary verwenden oder auch eines von außerhalb:

Code: Alles auswählen

# -*- coding: utf-8 -*-
class Input_Class:

    def __init__(self,get_dictionary=None):
        
        if get_dictionary:
            self.get_dictionary = get_dictionary
        else:
            self.dictionary = {
                'Name': '',
                'Vorname': '',
                'Straße': '',
                'Hausnummer':'',
                'PLZ':'',
                'Ort':'',
                }
            self.get_dictionary = self.get_own_dictionary

    def get_own_dictionary(self):
        return self.dictionary

    def keys(self):
        pass

Input_Object = Input_Class()
print(Input_Object.get_dictionary())
Und was nicht schlecht ist, genau dieselbe Klasse mit exakt dem gleichen Code läßt sich auch in diesem Zusammenhang einsetzen:

Code: Alles auswählen

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

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

class Input_Class:

    def __init__(self,get_dictionary=None):
        
        if get_dictionary:
            self.get_dictionary = get_dictionary
        else:
            self.dictionary = {
                'Name': '',
                'Vorname': '',
                'Straße': '',
                'Hausnummer':'',
                'PLZ':'',
                'Ort':'',
                }
            self.get_dictionary = self.get_own_dictionary

    def get_own_dictionary(self):
        return self.dictionary

    def keys(self):
        pass

class Application(tk.Tk):

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

        Input_Object = Input_Class(self.Eingabemaske.config_dictionary)
        print(Input_Object.get_dictionary())

class Eingabemaske(tk.LabelFrame):

    def __init__(self,master,**kwargs):
        tk.LabelFrame.__init__(self,master,**kwargs)
        self.config(text='Eingabemaske')
        # widget definitions ===================================
        self.content = tk.Frame(self)
        self.content.pack(fill='x')

    def config_dictionary(self):
        dictionary = self.config()
        dictionary2 = {}
        for element in dictionary:
            dictionary2[element] = str(self[element])
        return dictionary2

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

Denn es soll in diesem Fall für jede Art von Widgets gehen:

Code: Alles auswählen

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

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

class Input_Class:

    def __init__(self,get_dictionary=None):
        
        if get_dictionary:
            self.get_dictionary = get_dictionary
        else:
            self.dictionary = {
                'Name': '',
                'Vorname': '',
                'Straße': '',
                'Hausnummer':'',
                'PLZ':'',
                'Ort':'',
                }
            self.get_dictionary = self.get_own_dictionary

    def get_own_dictionary(self):
        return self.dictionary

    def keys(self):
        pass

class Widget_Config:
    def __init__(self,widget):
        self.widget = widget

    def config_dictionary(self):
        dictionary = self.widget.config()
        dictionary2 = {}
        for element in dictionary:
            dictionary2[element] = str(self.widget[element])
        return dictionary2

class Application(tk.Tk):

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

        Input_Object = Input_Class(Widget_Config(self.Eingabemaske).config_dictionary)
        print(Input_Object.get_dictionary())

class Eingabemaske(tk.LabelFrame):

    def __init__(self,master,**kwargs):
        tk.LabelFrame.__init__(self,master,**kwargs)
        self.config(text='Eingabemaske')
        # widget definitions ===================================
        self.content = tk.Frame(self)
        self.content.pack(fill='x')


if __name__ == '__main__':
    Application().mainloop()
Komisch ist dabei aber, dass ich hier keine Hausnummer sehe
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Ein Dictionary ist ungeordnet. SWichtig istm, dass unsewre Maske geordnet aufgebaut ist. Deshalb soll unsere Klasse eine sortierte key Liste liefern:

Code: Alles auswählen

# -*- coding: utf-8 -*-
class Input_Class:

    def __init__(self,get_dictionary=None):
        
        if get_dictionary:
            self.get_dictionary = get_dictionary
        else:
            self.dictionary = {
                'Name': '',
                'Vorname': '',
                'Straße': '',
                'Hausnummer':'',
                'PLZ':'',
                'Ort':'',
                }
            self.get_dictionary = self.get_own_dictionary

    def get_own_dictionary(self):
        return self.dictionary

    def keys(self):
        return [ 'Name',
                 'Vorname',
                 'Straße',
                 'Hausnummer',
                 'PLZ',
                 'Ort',
                 ]

    def __getitem__(self,key):
        return self.get_dictionary()[key]
                 

Input_Object = Input_Class()
keys = Input_Object.keys()
for key in keys:
    print(key,Input_Object[key])
stefanxfg
User
Beiträge: 85
Registriert: Sonntag 2. April 2017, 14:11

Hallo Alfons,

verstehe ich das richtig, dass du aus dem dictionary eine labelliste machen willst, die du dann zur gui erzeugst?
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Abhängig vom gewählten Layout und wenn es auf den Platz ankommt, sollten wir eventuell noch die nötige Breite für die Labels feststellen:

Code: Alles auswählen

maxlen = 0
for key in keys:
    maxlen = max(maxlen,len(key))

print(maxlen)
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wozu ein dict, wenn du eh eine Ordnung brauchst? Da reicht doch die Liste völlig. Und was soll diese extra Schleife mit "get_dictionary"?

So oder so halte ich diesen Ansatz für ziemlich sinnlos. So ein Vorgehen hat wert wenn man zB mit SQLAlchemy-Objekten arbeitet, weil man da schon viele Metadaten hat, die man nutzen kann. Letztlich aber sind auch im Web zB bei Django Admin oder rails scaffolding die Einsatzmöglichkeiten beschränkt. Aber das hat dich ja noch nie abgehalten :lol:
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

__deets__ hat geschrieben:Wozu ein dict, wenn du eh eine Ordnung brauchst? Da reicht doch die Liste völlig. Und was soll diese extra Schleife mit "get_dictionary"?
Wofür man das Dictionary braucht, ganz einfach, man will ja nicht nur die Inhalte darstellen, sondern auch abspeichern. Zu get_dictionary kommen wir später.

Zum Darstellen braucht man mal kein dictionary.

Das wäre mal die Eingabemaske. Für gewisse Felder kann man eine Sonderbehandlung machen, etwa dass die PLZ nur 5 Stellen hat, oder dass man sie abprüft, oder dass man für manche Felder besser eine Spinbox verwendet.

Code: Alles auswählen

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

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

class Input_Class:

    def __init__(self,get_dictionary=None):
        
        if get_dictionary:
            self.get_dictionary = get_dictionary
        else:
            self.dictionary = {
                'Name': '',
                'Vorname': '',
                'Straße': '',
                'Hausnummer':'',
                'PLZ':'',
                'Ort':'',
                }
            self.get_dictionary = self.get_own_dictionary

    def get_own_dictionary(self):
        return self.dictionary

    def keys(self):
        return [ 'Name',
                 'Vorname',
                 'Straße',
                 'Hausnummer',
                 'PLZ',
                 'Ort',
                 ]

    def __getitem__(self,key):
        return self.get_dictionary()[key]


class Application(tk.Tk):

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

        self.Eingabemaske.create_Eingabemaske(Input_Class())
        

class Eingabemaske(tk.LabelFrame):

    def __init__(self,master,**kwargs):
        tk.LabelFrame.__init__(self,master,**kwargs)
        self.config(text='Eingabemaske')
        # widget definitions ===================================
        self.content = tk.Frame(self)
        self.content.pack(fill='x')

    def create_Eingabemaske(self,input_object):
        keys = input_object.keys()

        maxlen = 0
        for key in keys:
            maxlen = max(maxlen,len(key))

        self.content.destroy()
        self.content = tk.Frame(self)
        self.content.pack(fill='x')
        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')

            # Sonderbehandlung für spezielle Eingabefelder
            if key == 'PLZ':
                width = 5
                expand = 0
                fill = None
            elif key == 'Hausnummer':
                width = 6
                expand = 0
                fill = None
            else:
                width = 30
                expand = 1
                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)

if __name__ == '__main__':
    Application().mainloop()
Das ist ein einfaches Pack Layout. Man kann aber jedes beliebige Layout nehmen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Da gibt es zwei Möglichkeiten:

a) jeden Eintrag mit Enter bestätigen und damit speichern
b) Die Maske ausfüllen und am Ende einen Button zum Übernehmen drücken

Das ist die Methode b):

Code: Alles auswählen

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

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

class Input_Class:

    def __init__(self,get_dictionary=None,set_dictionary = None):
        
        if get_dictionary:
            self.get_dictionary = get_dictionary
        else:
            self.dictionary = {
                'Name': '',
                'Vorname': '',
                'Straße': '',
                'Hausnummer':'',
                'PLZ':'',
                'Ort':'',
                }
            self.get_dictionary = self.get_own_dictionary

        if set_dictionary:
            self.set_dictionary = set_dictionary
        else:
            self.set_dictionary = self.set_own_dictionary

    def get_own_dictionary(self):
        return self.dictionary

    def set_own_dictionary(self,**kwargs):
        for key in kwargs:
            self.dictionary[key] = kwargs[key]

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

    def __getitem__(self,key):
        return self.config()[key]

    def __setitem__(self,key,value):
        self.config(**{key : value})

    def keys(self):
        return [ 'Name',
                 'Vorname',
                 'Straße',
                 'Hausnummer',
                 'PLZ',
                 'Ort',
                 ]


class Application(tk.Tk):

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

        self.Eingabemaske.create_Eingabemaske(Input_Class())
        

class Eingabemaske(tk.LabelFrame):

    def __init__(self,master,**kwargs):
        tk.LabelFrame.__init__(self,master,**kwargs)
        self.config(text='Eingabemaske')
        # widget definitions ===================================
        self.content = tk.Frame(self)
        self.content.pack(fill='x')

    def create_Eingabemaske(self,input_object):
        keys = input_object.keys()

        maxlen = 0
        for key in keys:
            maxlen = max(maxlen,len(key))

        self.content.destroy()
        self.content = tk.Frame(self)
        self.content.pack(fill='x')

        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')

            # Sonderbehandlung für spezielle Eingabefelder
            if key == 'PLZ':
                width = 5
                expand = 0
                fill = None
            elif key == 'Hausnummer':
                width = 6
                expand = 0
                fill = None
            else:
                width = 30
                expand = 1
                fill = 'x'
            # ===========================================
               
                
            entry = tk.Entry(frame,width = width)

            entry.key = key # das ist zum Speichern
            entrylist.append(entry) # und das auch

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

        def save_input():
            for entry in entrylist:
                input_object[entry.key] = str(entry.get())

            # Zum Anschauen =============================
            print(input_object.config())

        okbutton = tk.Button(self.content,text = 'OK')
        okbutton.pack(anchor = 'e')
        okbutton['command'] = save_input

if __name__ == '__main__':
    Application().mainloop()
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Alfons Mittelmeyer hat geschrieben:Abhängig vom gewählten Layout und wenn es auf den Platz ankommt, sollten wir eventuell noch die nötige Breite für die Labels feststellen:

Code: Alles auswählen

maxlen = 0
for key in keys:
    maxlen = max(maxlen,len(key))

print(maxlen)
Das geht auch kürzer:

Code: Alles auswählen

max(map(len, keys))
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Die Klasse wurde reduziert und erweitert, auf das, was man in diesem Falle braucht. Außerdem wurde noch eine Fehlerbehandlung eingebaut:

Code: Alles auswählen

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

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

import re

class Input_Class:

    def __init__(self, save_dictionary=None, dictionary = None):

        self.dictionary = dictionary if dictionary else { key : '' for key in self.keys() }
        self.save_dictionary = save_dictionary

    def save(self):

        for key in self.keys():
            if not len(self.dictionary[key].strip()):
                return False,key + ' fehlt'

        plz = self.dictionary['PLZ']
        if not re.match('(?:[0-9]{5})',plz):
            return False,'PLZ stimmt nicht'

        if self.save_dictionary:
            self.save_dictionary(**self.dictionary)
        else:
            print(self.dictionary)
            print('\nsave function missing')
        return True,''

    def keys(self):
        return [ 'Name',
                 'Vorname',
                 'Straße',
                 'Hausnummer',
                 'PLZ',
                 'Ort',
                 ]

    def __getitem__(self,key):
        return self.dictionary[key]

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


class Application(tk.Tk):

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

        self.Eingabemaske.create_Eingabemaske(Input_Class())
        

class Eingabemaske(tk.LabelFrame):

    def __init__(self,master,**kwargs):
        tk.LabelFrame.__init__(self,master,**kwargs)
        self.config(text='Eingabemaske')
        # widget definitions ===================================
        self.content = tk.Frame(self)
        self.content.pack(fill='x')

    def create_Eingabemaske(self,input_object):
        keys = input_object.keys()

        maxlen = max(map(len, keys))

        self.content.destroy()
        self.content = tk.Frame(self)
        self.content.pack(fill='x')

        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')

            # Sonderbehandlung für spezielle Eingabefelder
            if key == 'PLZ':
                width = 5
                expand = 0
                fill = None
            elif key == 'Hausnummer':
                width = 6
                expand = 0
                fill = None
            else:
                width = 30
                expand = 1
                fill = 'x'
            # ===========================================
               
                
            entry = tk.Entry(frame,width = width)

            entry.key = key # das ist zum Speichern
            entrylist.append(entry) # und das auch

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

        status_label = tk.Label(self.content)
        status_label.pack(side = 'left')

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


        okbutton = tk.Button(self.content,text = 'OK')
        okbutton.pack(side = 'right', anchor = 'e')
        okbutton['command'] = save_input

if __name__ == '__main__':
    Application().mainloop()
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: die Klasse Input_Class ist aus vielerlei Gründen schlecht. Zuerst der Name. Dass es eine Klasse ist, sieht man an der Schreibweise; es handelt sich nicht nur um Input sondern auch um Output. Die Felder sind fest verdrahtet und dazu noch mehrfach im Code. Wenn ich eine andere get_dictionary oder set_dictionary-Methode haben will, schreibe ich eine eigene Klasse und übergebe keine Funktionen an eine generische Klasse. Damit sieht die Input_Class so aus:

Code: Alles auswählen

class Address(object):
    KEYS = [
        'Name',
        'Vorname',
        'Straße',
        'Hausnummer',
        'PLZ',
        'Ort',
    ]

    def __init__(self):
        self.dictionary = dict.fromkeys(self.KEYS, "")
 
    def get_dictionary(self):
        return self.dictionary
 
    def set_dictionary(self,**kwargs):
        self.dictionary.update(kwargs)
 
    def config(self,**kwargs):
        self.dictionary.update(**kwargs)
        return self.dictionary
 
    def __getitem__(self, key):
        return self.dictionary[key]
 
    def __setitem__(self, key, value):
        self.dictionary[key] = value
 
    def keys(self):
        return list(self.KEYS)
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

Code: Alles auswählen

def create_Eingabemaske(self, keys): [...]

def save_input():
    output = {}
    for key, entry in zip(keys, entrylist):
        output[key] = entry.get()
    print(output)
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3: wenn man allerdings davon ausgeht, dass man die wichtigsten Dictionary Einträge kennt, aber nicht alle, dann ist keys zu ergänzen:

Code: Alles auswählen

    def keys(self):

        keys = list(self.KEYS)
        dictionary = dict(self.get_dictionary())

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

        return keys
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Wir sollten auch noch davon ausgehen, dass manche Dictionaries nicht alle keys haben:

Code: Alles auswählen

    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)
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Wovon wir noch ausgehen sollten. Das Dictionary könnte auch mehrsprachig sein. Wenn wir auf eine Dictionary Kopie mit key zugreifen, könnten wir eine Liste mit Einträgen in allerlei Sprachen bekommen. Eindeutig wird es nur, wenn wir auf das Original Dictionary zugreifen, weil das dann den Eintrag in der aktuellen Sprache liefert:

Code: Alles auswählen

    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
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Und so sieht es doch schon gut aus:

Code: Alles auswählen

class DictionaryAdvanced:

    KEYS = [
        'Name',
        'Vorname',
        'Straße',
        'Hausnummer',
        'PLZ',
        'Ort',
    ]    

    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):
        self.config(**{key : value})

    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
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Naja, das auch noch:

Code: Alles auswählen

   def __setitem__(self,key,value):
        try:
            self.config(**{key : value})
        except: ValueError
            pass
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@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.
Antworten