Datenübergabe mit Listbox und grid

Fragen zu Tkinter.
Nobuddy
User
Beiträge: 1015
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,
habe mir ein Fenster für das anlegen von Neukunden erstellt.
Es besteht aus einer Listbox und einer grid-Texteingabe.
Leider weiß ich nicht, wie ich von der Listbox die Auswahl an die grid-Texteingabe übergeben kann. Dies betrifft nur ein Übergabefeld.
Die Datenübernahme nach dem Ausfüllen der grid-Textfelder, stellt mich auch vor ein Problem.

Ich hoffe, daß Ihr mir da auf die Sprünge helfen könnt?

Code: Alles auswählen

class KundeNeu(Tk):
    def __init__(self):
        Tk.__init__(self)
        # Fenster
        self.title('officeplanet')

        # Farbe Button-Frames
        bcolor = 'orange'
        # Farbe Buttons
        bbcolor = 'grey'
        fbcolor = 'black'
        # Farbe Texteingabe, Textfenster
        btxt = 'black'
        ftxt = 'white'
        # Text Schrift
        font = 'NimbusSansL'
        # Textgröße Buttons, Texteingabe
        fontsize = 14
        # Textgröße 
        output_fontsize = 12

        ## Listbox ##
        text = 'Anlage Neukunde'
        items = ['Privatkunde', 'Kleinbetrieb, bis 1000 € Jahresumsatz',
            'Mittelständischer Betrieb, bis 10.000 € Jahresumsatz',
            'Großbetrieb, bis 25.000 € Jahresumsatz',
            'Konzern, ab 25.000 € Jahresumsatz',
            'Komunaler Träger']
        self.selection = []
        self.items = items
        activated = (0,0) # Vor-Aktivierte Punkte
        self.text = text
        self.listboxTXT = Label(self, text=self.text, background=bcolor,
            font=(font, fontsize))
        self.listboxTXT.pack(anchor='n', ipadx=5, ipady=10, fill=BOTH)
        self.listboxLabel = Label(self, text=self.text,
            background=bcolor, font=(font, fontsize))
        self.listboxLabel.pack(anchor='s', ipadx=5, ipady=10, fill=BOTH)
        self.listbox = Listbox(self.listboxLabel, selectmode=SINGLE, 
            height=5, width=45, font=(font, output_fontsize))
        self.listbox.pack(anchor='s')
        # Einträge einfügen
        for txt in self.items:
            self.listbox.insert(END, txt)
        # Vor-Aktivierte Punkte selektieren
        for index in activated:
            self.listbox.selection_set(index)

        ## Eingabefelder ##
        self.txtLabel = Label(self, background=bcolor)
        self.txtLabel.pack(anchor='s', expand='YES', fill=BOTH)
        field = ['Kundenkreis', 'Namen', 'Zusatz', 'Straße, Nr.', 'PLZ', 
                'Ort', 'Ansprechpartner', 'Telefon', 'Handy', 'Fax', 
                'Mail','Internetseite']
        r = 0
        for name in field:
            self.KundeNeuLab01 = Label(self.txtLabel, text=name,
                width=15, background=bcolor, font=(font, fontsize)
                ).grid(row=r, column=0, padx=30,pady=10)
            self.KundeNeuLab01 = Entry(self.txtLabel, relief=SUNKEN,
                width=65, font=(font, fontsize)).grid(row=r, column=1, 
                padx=5, pady=10)
            if name == 'Kundenkreis':
                selection = self.display_selection
                print('')
            r = r + 1

        ## Buttons unten ##
        label_down = Label(self, width=200, background=bcolor)
        label_down.pack(anchor='s', ipady=10, fill=BOTH)
        button = {
                '01-Übernehmen' : self.display_selection,
                '02-Abbrechen' : self.destroy,
        }
        for b in sorted(button):
            Button(label_down, width=10, text=b.split('-')[1], 
                background=bbcolor, font=(font, fontsize), 
                foreground=fbcolor, command=button[b]).pack(side='left', 
                padx=210, pady=30)

    def display_selection(self):
        selection = []
        for i in self.listbox.curselection():
            index = int(i) # i ist ein String
            selection.append(self.items[index])
        print("Aktuelle Selektion ist:", selection)
        return selection


class Controller(object):
    def __init__(self):
        self.view = KundeNeu()
        self.view.mainloop()

if __name__ == '__main__':
    Controller()
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Nobuddy

Hier etwas betreffs Listboxselektion mit callback:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import Tkinter as tk

LISTBOX_FONT = ('Arial', 12, 'bold')
LISTBOX_HEIGHT = 5
LISTBOX_WIDTH = 45
LISTBOX_ITEMS = [
    'Privatkunde', 
    'Kleinbetrieb, bis 1000 € Jahresumsatz',
    'Mittelständischer Betrieb, bis 10.000 € Jahresumsatz',
    'Großbetrieb, bis 25.000 € Jahresumsatz',
    'Konzern, ab 25.000 € Jahresumsatz',
    'Komunaler Träger'
    ]
    
class ListboxSelect(tk.Listbox):

  def __init__(self, app_win, items, list_callback):

    self.items = items
    self.list_callback = list_callback
    
    self.frame = tk.Frame(app_win)
    self.frame.pack(side='left', padx=5, pady=5)
    
    tk.Listbox.__init__(self, self.frame, selectmode='single', bd=0,
        highlightthickness=0, fg='steelblue')
    self.pack(fill='both', expand=True)

    self.insert(0, *items)

    self.bind('<<ListboxSelect>>', self.check)
       
  def check(self, event):

    index = map(int, self.curselection())

    if self.list_callback:
        self.list_callback(self.items[index[0]])

if __name__ == '__main__':

    def list_callback(item):
        print item
        
    app_win = tk.Tk()
    app_win.title("Kundenkreis-Listbox")
    
    listbox_select = ListboxSelect(app_win, LISTBOX_ITEMS, list_callback)
    listbox_select.config(height=LISTBOX_HEIGHT, width=LISTBOX_WIDTH,
        font=LISTBOX_FONT)

    app_win.mainloop()
Gruß wuf :wink:
Take it easy Mates!
Nobuddy
User
Beiträge: 1015
Registriert: Montag 30. Januar 2012, 16:38

Hallo wuf, Danke für Deine Unterstützung,

Bei Deinem Code kommt beim Auswählen in der Listbox, folgende Meldung:

self.list_callback(self.items[index[0]])
TypeError: 'map' object is not subscriptable

PS: Habe es gelöst.
'index = map(int, self.curselection())' bringt den Fehler und mit dem 'index = list(map(int, self.curselection()))' funktioniert es.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

OK Nobuddy

Du hast recht. Hab das Snippet nur mit Python2.6 getestet. Mit Python3.1 wirft es bei mir die gleiche Fehlermeldung. Habe es korrigiert. Nun sollte es mit beiden Python-Versionen funktionieren.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
except:
    # Tkinter for Python 3.xx
    import tkinter as tk


LISTBOX_FONT = ('Arial', 12, 'bold')
LISTBOX_HEIGHT = 5
LISTBOX_WIDTH = 45
LISTBOX_ITEMS = [
    'Privatkunde', 
    'Kleinbetrieb, bis 1000 € Jahresumsatz',
    'Mittelständischer Betrieb, bis 10.000 € Jahresumsatz',
    'Großbetrieb, bis 25.000 € Jahresumsatz',
    'Konzern, ab 25.000 € Jahresumsatz',
    'Komunaler Träger'
    ]
    
class ListboxSelect(tk.Listbox):

  def __init__(self, app_win, items, list_callback):

    self.items = items
    self.list_callback = list_callback
    
    self.frame = tk.Frame(app_win)
    self.frame.pack(side='left', padx=5, pady=5)
    
    tk.Listbox.__init__(self, self.frame, selectmode='single', bd=0,
        highlightthickness=0, fg='steelblue')
    self.pack(fill='both', expand=True)

    self.insert(0, *items)

    self.bind('<<ListboxSelect>>', self.check)
       
  def check(self, event):

    index = int(self.curselection()[0])
    
    if self.list_callback:
        self.list_callback(self.items[index])

if __name__ == '__main__':

    def list_callback(item):
        print(item)
        
    app_win = tk.Tk()
    app_win.title("Kundenkreis-Listbox")
    
    listbox_select = ListboxSelect(app_win, LISTBOX_ITEMS, list_callback)
    listbox_select.config(height=LISTBOX_HEIGHT, width=LISTBOX_WIDTH,
        font=LISTBOX_FONT)

    app_win.mainloop()
Nobuddy hat geschrieben:PS: Habe es gelöst.
'index = map(int, self.curselection())' bringt den Fehler und mit dem 'index = list(map(int, self.curselection()))' funktioniert es.
Danke noch für den Tipp. Werde ihn noch näher anschauen.

P.S. Wie speicherst du deine kundenbezogenen Eingaben ab? In einem Dictionary? Oder verwendest du ein bestimmtes Datenbankformat?

Gruß wuf :wink:
Take it easy Mates!
Nobuddy
User
Beiträge: 1015
Registriert: Montag 30. Januar 2012, 16:38

Hallo wuf,
habe mit der Fehlermeldung gegoogelt und kam so auf die Lösung. :wink:

Bin am Überlegen, wie ich mit Deinem schönen Code weitermache.
In das Gesamtfenster für Neukundenanlage integrieren oder doch seperat?
Habe da noch einiges zu lernen. :wink:

Ich bin da noch komplett am Anfang. Bis jetzt arbeite ich mit MS Access2003 auf einer VM mit Windows2000.
Möchte langfristig eine Firmware mit Python erstellen.
Die Daten speichere ich in txt-Dateien, TAB-getrennt ab.
Jetzt noch eine Datenbank zu programmieren, würde mich etwas zeitlich überfordern und aus meiner bisherigen Access-Erfahrung, neige ich zu txt-Dateien.

Grüße Nobuddy
Nobuddy
User
Beiträge: 1015
Registriert: Montag 30. Januar 2012, 16:38

Hallo wuf,

habe den Code ein bischen umgestaltet.

Code: Alles auswählen

from tkinter import Tk
from tkinter import Frame
from tkinter import Listbox


TITEL = "Kundenkreis-Listbox"
LISTBOX_ITEMS = [
    'Privatkunde # 0',
    'Kleinbetrieb, bis 1000 € Jahresumsatz # 1',
    'Mittelständischer Betrieb, bis 10.000 € Jahresumsatz # 2',
    'Großbetrieb, bis 25.000 € Jahresumsatz # 3',
    'Konzern, ab 25.000 € Jahresumsatz # 4',
    'Komunaler Träger # 5'
    ]
LISTBOX_HEIGHT = len(LISTBOX_ITEMS)
LISTBOX_WIDTH = (max([len(i) for i in LISTBOX_ITEMS]) - 5)
LISTBOX_FONT = ('Arial', 12, 'bold')
LISTBOX_FONTCOLOR = 'steelblue'
LISTBOX_SELECTMODE = 'single'


class ListboxSelect(Tk):

    def __init__(self):
        Tk.__init__(self)
        self.title(TITEL)
        self.items = LISTBOX_ITEMS
        self.list_callback = list_callback
   
        self.frame = Frame(self)
        self.frame.pack(side='left', padx=5, pady=5)
   
        self.listbox_select = Listbox(self.frame, height=LISTBOX_HEIGHT, 
            width=LISTBOX_WIDTH, font=LISTBOX_FONT, 
            selectmode=LISTBOX_SELECTMODE, bd=0, highlightthickness=0,
            fg=LISTBOX_FONTCOLOR)
        self.listbox_select.pack(fill='both', expand=True)

        self.listbox_select.insert(0, *self.items)

        self.listbox_select.bind('<<ListboxSelect>>', self.check)
       
    def check(self, event):
        index = list(map(int, self.listbox_select.curselection()))
        if self.list_callback:
            self.list_callback(self.items[index[0]])


class Controller(object):

    def __init__(self):
        self.view = ListboxSelect()
        self.view.mainloop()

if __name__ == '__main__':
    def list_callback(item):
        select = item
        print(select)
        return select
    Controller()
Wenn ich jetzt noch die Parameter von einem anderen Modul aus übergeben könnte und das Ergebnis von list_callback weiterleiten könnte, könnte man dieses Modul multifunktional einsetzen.

Hast Du mir da evtl. Tipps dazu?

Grüße Nobuddy
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

OK Nobuddy

Habe dir etwas zum experimentieren zusammengestellt. Das Projekt besteht aus folgenden Dateien die im gleichen Verzeichnis abgelegt sein sollten.

Moduldatei:
my_listbox_module.py

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import tkinter as tk

class MyListbox(tk.Listbox):

    def __init__(self, parent, items, callback, **options):
        
        self.parent = parent
        self.items = items
        self.callback = callback
   
        tk.Listbox.__init__(self, parent, **options)
        self.insert(0, *self.items)
        self.bind('<<ListboxSelect>>', self.check)
       
    def check(self, event):
        index = list(map(int, self.curselection()))
        if self.callback:
            self.callback(self.items[index[0]])

#---- MODUL-TEST---------------------------------------------------------------#
if __name__ == '__main__':
    
    def callback(item):
        print(item)
        
    app_win = tk.Tk()
    
    TEST_ITEMS = [
        'Item-1',
        'Item-2',
        'Item-3',
        'Item-4'
        ]
        
    my_listbox = MyListbox(app_win, TEST_ITEMS, callback)
    my_listbox.pack()
     
    app_win.mainloop()
Anwendungs-Konfigurationsdatei:
my_app_config.py

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

APP_TITEL = "Kundenkreis-Listbox"

LISTBOX_FONT = ('Arial', 12, 'bold')
LISTBOX_FONTCOLOR = 'steelblue'

CUSTOM_TYPES = [
    'Privatkunde # 0',
    'Kleinbetrieb, bis 1000 € Jahresumsatz # 1',
    'Mittelständischer Betrieb, bis 10.000 € Jahresumsatz # 2',
    'Großbetrieb, bis 25.000 € Jahresumsatz # 3',
    'Konzern, ab 25.000 € Jahresumsatz # 4',
    'Komunaler Träger # 5'
    ]

CUSTOM_LISTBOX_OPTS = dict(width=(max([len(i) for i in CUSTOM_TYPES]) - 5),
    height=len(CUSTOM_TYPES), font=LISTBOX_FONT, fg=LISTBOX_FONTCOLOR,
    selectmode='single', bd=1, highlightthickness=0, relief='raised')

SUPPLIERS = [
    'Lieferant-1',
    'Lieferant-2',
    'Lieferant-3',
    'Lieferant-4',
    'Lieferant-5',
    'Lieferant-6'
    ]

SUPPLIER_LISTBOX_OPTS = dict(width=(max([len(i) for i in SUPPLIERS]) - 5),
    height=len(SUPPLIERS), font=LISTBOX_FONT, fg=LISTBOX_FONTCOLOR,
    selectmode='single', bd=1, highlightthickness=0, relief='raised')
Anwendungsdatei:
my_app.py

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import tkinter as tk
from my_listbox_module import*
from my_app_config import*

def custom_type_callback(custom_type):
    print(custom_type)

def supplier_callback(supplier):
    print(supplier)
    
def main():
    
    app_win = tk.Tk()
    app_win.title(APP_TITEL)
    
    custom_type_box = MyListbox(app_win, CUSTOM_TYPES, custom_type_callback,
        **CUSTOM_LISTBOX_OPTS)
    custom_type_box.pack(fill='both', expand=True, padx=5, pady=5)

    supplier_box = MyListbox(app_win, SUPPLIERS, supplier_callback,
        **SUPPLIER_LISTBOX_OPTS)
    supplier_box.pack(fill='both', expand=True, padx=5, pady=5)
     
    app_win.mainloop()
    
main()
Das Ganze kann natürlich noch weiter verbessert und optimiert werden.

Gruß wuf :wink:
Take it easy Mates!
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

@Nobuddy:
Du solltest dir mal das Model, View, Controller Pattern (MVC) ansehen.

Hier auch noch ein Beispiel:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x

import tkinter as tk

CONFIG = {'title' : "Kundenkreis-Listbox",
          'font': ('Arial', 12, 'bold'),
          'font_color': 'steelblue',
          'select_mode': 'single'}

ITEMS = ['Privatkunde', 'Kleinbetrieb, bis 1000 € Jahresumsatz',
         'Mittelständischer Betrieb, bis 10.000 € Jahresumsatz',
         'Großbetrieb, bis 25.000 € Jahresumsatz',
         'Konzern, ab 25.000 € Jahresumsatz',
         'Komunaler Träger']

class ListGui(object):

    def __init__(self, controller, items, conf):
        self.root = tk.Tk()
        self.root.title(conf['title'])

        self.controller = controller
        self.items = ['{0} # {1}'.format(item, i) for i, item in enumerate(items)]

        self.frame = tk.Frame(self.root)
        self.frame.pack(side='left', padx=5, pady=5)
        box_length = len(self.items)
        box_width = max(len(item) for item in self.items)# - 5
        self.listbox = tk.Listbox(self.frame, height=box_length, width=box_width,
                                  font=conf['font'],
                                  selectmode=conf['select_mode'],
                                  bd=0, highlightthickness=0,
                                  fg=conf['font_color'])
        self.listbox.pack(fill='both', expand=True)
        self.listbox.insert(0, *self.items)
        self.listbox.bind('<<ListboxSelect>>', self.check)


    def check(self, event):
        indices = list(map(int, self.listbox.curselection()))
        self.controller.process(self.items[indices[0]])


    def run(self):
        self.root.mainloop()


class Controller(object):

    def __init__(self):
        self.model = Model(ITEMS)
        self.view = ListGui(self, self.model.items, CONFIG)


    def process(self, string):
        print(string)


    def run(self):
        self.view.run()


class Model(object):

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


def main():
    Controller().run()

if __name__ == '__main__':
    main()
:wink:
yipyip
Nobuddy
User
Beiträge: 1015
Registriert: Montag 30. Januar 2012, 16:38

Hallo wuf, Danke für Deinen Post, werde ihn gleich testen. :wink:

War auch nicht ganz untätig und habe eine Teillösung, die aber bestimmt nicht so effizient wie Deine ist. :wink:
Hier der Teilcode, von dem Modul von dem ich die Listbox ansteuere:

Code: Alles auswählen

# listbox_conf.txt
listbox_conf_path = os.path.join(os.path.dirname(__file__),
                                    'tmp', 'listbox_conf.txt')
# listbox_list.txt
listbox_list_path = os.path.join(os.path.dirname(__file__),
                                    'tmp', 'listbox_list.txt')

TITEL = "Kundenkreis-Listbox"
LISTBOX_ITEMS = [
    'Privatkunde # 0',
    'Kleinbetrieb, bis 1000 € Jahresumsatz # 1',
    'Mittelständischer Betrieb, bis 10.000 € Jahresumsatz # 2',
    'Großbetrieb, bis 25.000 € Jahresumsatz # 3',
    'Konzern, ab 25.000 € Jahresumsatz # 4',
    'Komunaler Träger # 5'
    ]
LISTBOX_HEIGHT = len(LISTBOX_ITEMS)
LISTBOX_WIDTH = (max([len(i) for i in LISTBOX_ITEMS]) - 5)
LISTBOX_FONT = "Arial, 12, bold"
LISTBOX_FONTCOLOR = 'steelblue'
LISTBOX_SELECTMODE = 'single'

def write_csv(filename, datenpool):
    with codecs.open(filename, "w") as zielfile:
        writer = csv.writer(zielfile, delimiter="\t", quotechar="^")
        writer.writerows(datenpool)

def write_txt(filename, datenpool):
    with codecs.open(filename, "w") as zielfile:
        zielfile.write(datenpool)

def writeappend_txt(filename, datenpool):
    with codecs.open(filename, "a") as zielfile:
        zielfile.write(datenpool)

ITEMS = list()
for row in LISTBOX_ITEMS:
    ITEMS.append([row])
write_csv(listbox_list_path, ITEMS)
write_txt(listbox_conf_path, '{}\n'.format(TITEL))
writeappend_txt(listbox_conf_path, '{}\n'.format(LISTBOX_HEIGHT))
writeappend_txt(listbox_conf_path, '{}\n'.format(LISTBOX_WIDTH))
writeappend_txt(listbox_conf_path, '{}\n'.format(LISTBOX_FONT))
writeappend_txt(listbox_conf_path, '{}\n'.format(LISTBOX_FONTCOLOR))
writeappend_txt(listbox_conf_path, '{}\n'.format(LISTBOX_SELECTMODE))
Und das Modul der Listbox, sieht so aus:

Code: Alles auswählen

# listbox_conf.txt
listbox_conf_path = os.path.join(os.path.dirname(__file__),
                                    'tmp', 'listbox_conf.txt')
# listbox_select.txt
listbox_select_path = os.path.join(os.path.dirname(__file__),
                                    'tmp', 'listbox_select.txt')
# listbox_list.txt
listbox_list_path = os.path.join(os.path.dirname(__file__),
                                    'tmp', 'listbox_list.txt')


with codecs.open(listbox_conf_path, 'r') as infile:
    reader = csv.reader(infile, delimiter="\t", quotechar="^")
    for index, row in enumerate(reader):
        if index == 0:
            TITEL = row[0]
        if index == 1:
            LISTBOX_HEIGHT = row[0]
        if index == 2:
            LISTBOX_WIDTH = row[0]
        if index == 3:
            font = row[0].split(',')[0].replace('[', '')
            font2 = row[0].split(',')[1]
            font3 = row[0].split(',')[2].replace(']', '')
            LISTBOX_FONT = (font, int(font2), font3)
        if index == 4:
            LISTBOX_FONTCOLOR = row[0]
        if index == 5:
            LISTBOX_SELECTMODE = row[0]

LISTBOX_ITEMS = list()
with codecs.open(listbox_list_path, 'r') as infile:
    reader = csv.reader(infile, delimiter="\t", quotechar="^")
    for row in reader:
        LISTBOX_ITEMS.append(''.join(row))


def write_txt(filename, datenpool):
    with codecs.open(filename, "w") as zielfile:
        zielfile.write(datenpool)


class ListboxSelect(Tk):

    def __init__(self):
        Tk.__init__(self)
        self.title(TITEL)
        self.items = LISTBOX_ITEMS
        self.list_callback = list_callback
   
        self.frame = Frame(self)
        self.frame.pack(side='left', padx=5, pady=5)
   
        self.listbox_select = Listbox(self.frame, height=LISTBOX_HEIGHT, 
            width=LISTBOX_WIDTH, font=LISTBOX_FONT, 
            selectmode=LISTBOX_SELECTMODE, bd=0, highlightthickness=0,
            fg=LISTBOX_FONTCOLOR)
        self.listbox_select.pack(fill='both', expand=True)

        self.listbox_select.insert(0, *self.items)

        self.listbox_select.bind('<<ListboxSelect>>', self.check)
       
    def check(self, event):
        index = list(map(int, self.listbox_select.curselection()))
        if self.list_callback:
            self.list_callback(self.items[index[0]])


class Controller(object):

    def __init__(self):
        self.view = ListboxSelect()
        self.view.mainloop()

if __name__ == '__main__':
    def list_callback(item):
        write_txt(listbox_select_path, item)
        exit()
    Controller()
Hallo yipyip, Danke auch für Deinen Input, werde ich mir auch anschauen und testen. :wink:
Nobuddy
User
Beiträge: 1015
Registriert: Montag 30. Januar 2012, 16:38

Hallo wuf, Hallo yipyip,

beide Ausführungen sind interessant, auch wenn sie verschiedene Ansätze haben.

wuf das mit den Lieferanten, benötige ich bei der Listbox nicht, aber ich denke mal daß es ein Beispiel dafür ist, mehrere Kriterien durch mehrere Listboxen auswählen zu können. Interessant ist auch die Aufteilung in verschiedene Module.

yipyip, Dein Vorschlag ist auch sehr interessant.
Mein Problem ist die englische Sprache, leider ... :oops: und versuche daher deutschsprachige Seiten zu lesen.
Das Model, View, Controller Pattern (MVC) ist jedenfalls eine sehr interessante Sache, vielleicht hast Du mir dazu etwas deutschsprachiges?

Die CONFIG und die ITEMS, würde ich aus dem Modul selbst herausnehmen und es mit diesen Infos von einem anderen Modul ansteuern, dann wäre das Modul Listbox mehrfach verwendbar.

Grüße Nobuddy
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

@Nobuddy:
Es laesst sich aber auch ohne Schwierigkeiten etwas Deutschsprachiges zum Thema MVC erguugeln, z.B. bei Wikipedia. Auf Dauer solltest du dich aber schon mit dem Englischen vertraut machen. (Diskussionen darueber gabs hier ja genuegend.) Sooo schwer ist das gar nicht. Das diffundiert mit der Zeit hinein. :wink:

Als Einstieg ins Englische:
http://www.reddit.com/r/python
http://www.reddit.com/r/learnpython/
Fuer Vokabeln:
http://dict.leo.org/

Das MVC Pattern ist ein globes Architektur Pattern und besteht aus 3 Einheiten:
View: Alles, was mit Ein- und Ausgabe zu tun hat
Model: Alles, was mit deinen Daten zu tun hat.
Controller: Der Vermittler zwischen beiden.

D.h. alles was Tkinter betrifft, kommt in den View. Die Kundendaten etc. werden im Model behandelt. Tritt ein Event im View auf, wird dieser vom Controller entgegengenommen. Dieser kann dann z.B. Methoden des Models mit den entgegengenommenen Daten aufrufen und Daten des Models wieder dem View zur Verfuegung stellen.

:wink:
yipyip
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Nobuddy hat geschrieben:wuf das mit den Lieferanten, benötige ich bei der Listbox nicht, aber ich denke mal daß es ein Beispiel dafür ist, mehrere Kriterien durch mehrere Listboxen auswählen zu können
Stimmt! Es zeigt wie das MyListbox-Modul für die Erstellung mehrere MyListbox-Instanzen verwendet wird.

Als Übersetzer ist dieser Link auch noch gu (Der Google-Übersetzert:
http://translate.google.com/#de/en/Modul

Da kannst du einzelne Wörter oder ganze Texte übersetzen lassen. Für deren Aussprache ist es möglich sie auch akustisch hörbar zu machen.

Gruß wuf :wink:
Take it easy Mates!
Nobuddy
User
Beiträge: 1015
Registriert: Montag 30. Januar 2012, 16:38

Hallo wuf,
das mit der Erstellung mehrere MyListbox-Instanzen, werde ich mir merken, Danke!
'translate.goggle' verwende ich schon, ist wirklich eins der Besten Übersetzer. :wink:

Hallo yipyip,
MVC ist wirklich ein hervorragendes Konzept, was ich mir zu eigen machen möchte.
Ich habe dazu auch diesen Link http://www.shiftedwork.de/blog/2011/12/ ... s-von-mvc/ gefunden.

MVC werde ich bei meinem Hauptfenster, versuchen umzusetzen.
Dort habe ich auf der rechten Seite meine Haupt-Buttons, die auf der linken Seite individuell Buttons regenerieren, bezogen auf das jeweilige Haupt-Button, das gerade aktiviert wurde.
Dies habe ich momentan etwas unorthodox umgesetzt, was zwar gut funktioniert, denke aber mit MVC lässt sich das bestimmt effektiver gestalten.

Was mich interessiert, ist Eure Meinung über die Umsetzung bei den conf- und listbox-Daten.
Ich erzeuge diese Daten aus dem jeweiligen Fenster, das dann wie hier in diesem Beispiel, das Modul Listbox ansteuert.
Diese Daten erstelle in einem speziellen Ordner als txt-Datei, die dann von dem Modul Listbox dort abgerufen wird.
Mein Gedanke dazu ist, daß ich so das Modul Listbox individuell nutzen kann. Einmal weil ja die Daten unterschiedlich sein können und das Layout entsprechend auch unterschiedlich sein kann, was z.B. die Schrift, die Schriftgröße und Schriftfarbe angeht.

Noch etwas anderes, Ihr verwendet ja immer 'from tkinter import *'.
Das mit dem Sternchen sollte man ja normalerweise unterlassen und dafür die importierten Module dafür aufführen, was je nachdem auch etwas ausarten kann.
Ich habe dies dann bisher immer nach diesem Beispiel, versucht umzusetzen:

Code: Alles auswählen

class KundeNeu(Tk):
    def __init__(self):
        Tk.__init__(self)
Hier entfällt dann 'tk.modul' und ist einfach 'modul', was aber mit

Code: Alles auswählen

class KundeNeu(object):
    def __init__(self):
        Tk.__init__(self)
natürlich nicht funktioniert.
Gibt es dafür eine Lösung, oder ist die Umsetzung mit 'from tkinter import *' und 'tk.modul' von Euch der einzige Weg?

Grüße Nobuddy


Nachtrag:
Habe gerade gesehen, daß keine Sternchen verwendet werden > 'import tkinter as tk'
Also ist der letzte Absatz hinfällig. :wink:
Nobuddy
User
Beiträge: 1015
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,
habe jetzt yipyipś Code als Grundlage verwendet und beinhaltet jetzt nicht nur eine Listbox, sonder auch weitere Eingabefelder.
Die Eingabefelder habe ich mit dem dazu gehörigen Text-Label über eine for-Schleife erstellt. Hier stehe ich auch vor dem Problem, wie ich die Texteingaben auslesen kann?
Was ich noch nicht hin bekommen habe, ist daß nach der Auswahl in der Listbox, ein bestimmter Label mit der Ausgabe aktualisiert wird.
Vielleicht habt Ihr mir dazu Tipps?

Poste mal den Code:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x

import tkinter as tk

CONFIG = {'width' : 100,
        'title' : "Anlage Neukunden",
        'font': ('NimbusSansL', 14, 'bold'),
        'font_color': 'black',
        'back_ground' : 'orange',
        'select_mode': 'single'}

ITEMS = ['Namen', 'Zusatz', 'Straße, Nr.', 'PLZ', 
        'Ort', 'USt-Ident-Nr.', 'Ansprechpartner', 'Telefon', 'Handy',
        'Fax', 'Mail','Internetseite']

LISTBOX_ITEMS = {'0' : 'Privatkunde',
        '1' : 'Kleinbetrieb, bis 1000 € Jahresumsatz',
        '2' : 'Mittelständischer Betrieb, bis 10.000 € Jahresumsatz',
        '3' : 'Großbetrieb, bis 25.000 € Jahresumsatz',
        '4' : 'Konzern, ab 25.000 € Jahresumsatz',
        '5' : 'Komunaler Träger'}

class ListGui(object):

    def __init__(self, controller, items, items2, conf):
        self.root = tk.Tk()
        self.root.title(conf['title'])

        self.controller = controller
        self.items = ['{0}\t{1}'.format(item, items[item])
                                            for item in sorted(items)]
        self.items2 = items2

        self.frame = tk.Frame(self.root)
        self.frame.pack(side='left', padx=5, pady=5, fill='both',
                                                        expand=True)

        box_length = len(self.items)
        box_width = max(len(item) for item in self.items) - 5
        left_width = max(len(item) for item in self.items2)

        self.label_name = tk.Label(self.frame, height=2,
            width=conf['width'], text='Auswahl Kundenkreis',
            bg=conf['back_ground'], font=conf['font'], bd=0,
            highlightthickness=0, fg=conf['font_color'])
        self.label_name.pack(fill='both', expand=False)

        self.label_left = tk.Label(self.frame, bg=conf['back_ground'], 
            width=left_width, bd=0, highlightthickness=0)
        self.label_left.pack(side='left', ipady=10, fill='both',
            expand=False)

        self.label_left2 = tk.Label(self.label_left, bg=conf['back_ground'],
            height=(box_length + 14), width=left_width, bd=0,
            highlightthickness=0)
        self.label_left2.pack(fill='both', expand=False)

        self.listbox = tk.Listbox(self.frame, height=box_length,
            width=box_width, font=conf['font'],
            selectmode=conf['select_mode'], bd=0, highlightthickness=0,
            fg=conf['font_color'])
        self.listbox.pack(padx=30, pady=30,
            fill='both', expand=False)
        self.listbox.insert(0, *self.items)
        self.listbox.bind('<<ListboxSelect>>', self.check)

        self.label_select = tk.Label(self.frame, bg='grey',
            height=5, width=left_width, bd=0, highlightthickness=0)
        self.label_select.pack(fill='both', expand=False)

        self.label_right = tk.Text(self.frame, 
            width=conf['width'], bd=0, highlightthickness=0)
        self.label_right.pack(pady=8, fill='both', expand=True)

        self.items2 = ['{0}'.format(item) for item in items2]
        for item in self.items2:
            self.label = tk.Label(self.label_left, text=item,
                width=(round(left_width * 1.5)), bg=conf['back_ground'],
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0)
            self.label.pack(pady=10, fill='both', expand=False)

            self.label2e = tk.Label(self.label_right,
                width=(round(left_width * 1.5)),
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0)
            self.label2e.pack(pady=10, fill='both', expand=False)

            self.label = tk.Entry(self.label2e,
                width=(round(left_width * 1.5)), bg='grey',
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0)
            self.label.pack(fill='both', expand=False)


    def check(self, event):
        indices = list(map(int, self.listbox.curselection()))
        self.controller.process(self.items[indices[0]])


    def run(self):
        self.root.mainloop()


class Controller(object):

    def __init__(self):
        self.model = Model(LISTBOX_ITEMS)
        self.model2 = Model(ITEMS)
        self.view = ListGui(self, self.model.items, self.model2.items,
                    CONFIG)


    def process(self, string):
        print(string)


    def run(self):
        self.view.run()


class Model(object):

    def __init__(self, items):
        self.items = items
        self.items2 = items


def main():
    Controller().run()

if __name__ == '__main__':
    main()
Grüße Nobuddy
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Nobuddy

Jetzt kommst du langsam an das eingemachte. Für die in deinem Skript verwendeten Namen würde ich unbeding bessere Bezeichnungen verwenden, da du sonst innert Kürze den Überblick verlieren könntest. Also mir ginge es so :-) In Bezug des Skriptaufbaus würde ich noch einmal gründlich über die Bücher gehen. Dies wird sich mit deiner gesammelten Erfahrung sicher noch verbessern und verfeinern. Vor allem nichts überstürzen. Um Zugriff auf die Inhalte der Eingabefelder zu haben musst du ihre Objektreferenzen kennen. Noch besser ist, wenn du hierfür die Tkinter's Steuervariabel tk.StringVar verwendest. Betreffs MVC kann dir unser yipyip oder weitere Forumkollegen sicher noch weitere Tipps geben.

Änderung-1 (In der ListGui):

Code: Alles auswählen

self.frame = tk.Frame(self.root)
self.frame.pack(side='top', padx=5, ipady=5, fill='both', expand=True)
Änderung-2 (In der ListGui):

Code: Alles auswählen

self.entries_var = list()
self.items2 = ['{0}'.format(item) for item in items2]
for item in self.items2:
    self.label = tk.Label(self.label_left, text=item,
        width=(round(left_width * 1.5)), bg=conf['back_ground'],
        font=conf['font'], fg=conf['font_color'], bd=0,
        highlightthickness=0)
    self.label.pack(pady=10, fill='both', expand=False)

    self.label2e = tk.Label(self.label_right,
        width=(round(left_width * 1.5)),
        font=conf['font'], fg=conf['font_color'], bd=0,
        highlightthickness=0)
    self.label2e.pack(pady=10, fill='both', expand=False)

    entry_var = tk.StringVar()
    self.entries_var.append(entry_var)
    self.label = tk.Entry(self.label2e,
        width=(round(left_width * 1.5)), bg='grey',
        font=conf['font'], fg=conf['font_color'], bd=0,
        highlightthickness=0, textvariable=entry_var)
    self.label.pack(fill='both', expand=False)
    entry_var.set('?')
Änderung-3 (In der ListGui):

Code: Alles auswählen

self.button_frame = tk.Frame(self.root, bg=conf['back_ground'])
self.button_frame.pack(fill='x', ipady=5)

tk.Button(self.button_frame, text="Abbrechen",
    font=conf['font'], fg=conf['font_color'], highlightthickness=0,
    command=self.root.destroy,).pack(side='right', padx=4)

tk.Button(self.button_frame, text="Übernehmen",
    font=conf['font'], fg=conf['font_color'], highlightthickness=0,
    command=self.controller.collect_entries).pack(side='right', padx=4)
Änderung-4 (Im Controller):

Code: Alles auswählen

def process(self, listbox_item):
    print(listbox_item)
    self.view.entries_var[0].set(listbox_item)

def collect_entries(self):
    entry_data = dict()
    for index, entry_var in enumerate(self.view.entries_var):
        print("{} : {}".format(self.model2.items[index],
        entry_var.get()))
        entry_data[self.model2.items[index]] = entry_var.get()
    print()
    print(entry_data)
Noch viel Spass mit Python and Tkinter.

Gruß wuf :wink:
Take it easy Mates!
Nobuddy
User
Beiträge: 1015
Registriert: Montag 30. Januar 2012, 16:38

Hallo wuf,
ja langsam gehtś wirklich anś Eingemachte. :wink:

Danke für Deine Unterstützung, habe den Code damit ergänzt und habe auch bei der Namensgebung mehr Unterscheidung eingebracht. Auch bei den Listen habe ich ITEMS in NAME_ITEMS umbenannt.
Weiter habe ich auch noch ein Entry-Feld mehr (Kundenkreis) in NAME_ITEMS aufgenommen, was ich nach der Auswahl in der Listbox damit aktualisieren möchte. Habe da schon ein paar Ansätze versucht, aber bisher ohne Erfolg.
Gerade bin ich aber doch auf dem richtigen Weg, melde mich dazu später nochmals. :wink:

Ein Gedanke ist mir auch noch gekommen, wenn z.B. die Liste von NAME_ITEMS mehr items hat, als in das Fenster gehen.
Dann würde ja der Rest abgeschnitten nicht erreichbar sein. Da wäre dann eine Scrollbar von Nutzen. Aber erst eins nach dem anderen.

Grüße Nobuddy
Nobuddy
User
Beiträge: 1015
Registriert: Montag 30. Januar 2012, 16:38

Vielleicht ein kleiner Schritt wieder nach vorne?

Ich habe eine Lösung gefunden, das dafür definierte Entry-Feld nach Auswahl in der Listbox zu aktualisieren.
Wäre schön, wenn Ihr mir sagen könntet, ob das so in Ordnung ist oder ob es auch noch einfacher geht.

Die for-Schleife habe ich mit einem Index versehen und eine if-Anwendung eingebaut.
Dazu habe ich noch bei der Funktion check(self, event), die Anweisung zum Aktualisieren gegeben.
Hier der Code dazu:

Code: Alles auswählen

        self.entries_var = list()
        self.items2 = ['{0}'.format(item) for item in items2]
        for index, item in enumerate(self.items2):
            self.name = tk.Label(self.label_left, text=item,
                width=(round(left_width * 1.5)), bg=conf['back_ground'],
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0)
            self.name.pack(pady=10, fill='both', expand=False)

            self.place_entry = tk.Label(self.label_right,
                width=(round(left_width * 1.5)),
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0)
            self.place_entry.pack(pady=10, fill='both', expand=False)

            entry_var = tk.StringVar()
            self.entries_var.append(entry_var)
            if index == 0:
                self.entry0 = tk.Entry(self.place_entry,
                    width=(round(left_width * 1.5)), bg='grey',
                    font=conf['font'], fg=conf['font_color'], bd=0,
                    highlightthickness=0)
                self.entry0.pack(fill='both', expand=False)
            else:
                self.entry = tk.Entry(self.place_entry,
                    width=(round(left_width * 1.5)), bg='grey',
                    font=conf['font'], fg=conf['font_color'], bd=0,
                    highlightthickness=0)
                self.entry.pack(fill='both', expand=False)

            entry_var.set('?')

        self.button_frame = tk.Frame(self.root, bg=conf['back_ground'])
        self.button_frame.pack(fill='x', ipady=5)

        tk.Button(self.button_frame, text="Abbrechen",
            font=conf['font'], fg=conf['font_color'],
            highlightthickness=0, command=self.root.destroy,).pack(
            side='right', padx=4)

        tk.Button(self.button_frame, text="Übernehmen",
            font=conf['font'], fg=conf['font_color'],
            highlightthickness=0,
            command=self.controller.collect_entries).pack(
            side='right', padx=4)

    def check(self, event):
        indices = list(map(int, self.listbox.curselection()))
        self.controller.process(self.items[indices[0]])
        self.entry0.delete(0, tk.END)
        self.entry0.insert(0, self.items[indices[0]])
Grüße Nobuddy
Nobuddy
User
Beiträge: 1015
Registriert: Montag 30. Januar 2012, 16:38

Geht ja noch einfacher, die if-Schleife war völlig unnötig.

Code: Alles auswählen

        self.entries_var = list()
        self.items2 = ['{0}'.format(item) for item in items2]
        for index, item in enumerate(self.items2):
            self.name = tk.Label(self.label_left, text=item,
                width=(round(left_width * 1.5)), bg=conf['back_ground'],
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0)
            self.name.pack(pady=10, fill='both', expand=False)

            self.place_entry = tk.Label(self.label_right,
                width=(round(left_width * 1.5)),
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0)
            self.place_entry.pack(pady=10, fill='both', expand=False)

            entry_var = tk.StringVar()
            self.entries_var.append(entry_var)
            self.entry = tk.Entry(self.place_entry,
                    width=(round(left_width * 1.5)), bg='grey',
                    font=conf['font'], fg=conf['font_color'], bd=0,
                    highlightthickness=0)
            self.entry.pack(fill='both', expand=False)
            if index == 0:
                self.entry_select = self.entry
            entry_var.set('?')

        self.button_frame = tk.Frame(self.root, bg=conf['back_ground'])
        self.button_frame.pack(fill='x', ipady=5)

        tk.Button(self.button_frame, text="Abbrechen",
            font=conf['font'], fg=conf['font_color'],
            highlightthickness=0, command=self.root.destroy,).pack(
            side='right', padx=4)

        tk.Button(self.button_frame, text="Übernehmen",
            font=conf['font'], fg=conf['font_color'],
            highlightthickness=0,
            command=self.controller.collect_entries).pack(
            side='right', padx=4)

    def check(self, event):
        indices = list(map(int, self.listbox.curselection()))
        self.controller.process(self.items[indices[0]])
        self.entry_select.delete(0, tk.END)
        self.entry_select.insert(0, self.items[indices[0]])
wuf, aber was ich festgestellt habe, die ausgefüllten Felder werden beim Betätigen des Übernahme-Buttons, nicht in dem Dictionary 'entry_data' mit ausgegeben.
Was könnte das sein?

Hier vielleicht nochmal den kompletten Code:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x

import tkinter as tk

CONFIG = {'width' : 100,
        'title' : "Anlage Neukunden",
        'font': ('NimbusSansL', 14, 'bold'),
        'font_color': 'black',
        'back_ground' : 'orange',
        'select_mode': 'single'}

NAME_ITEMS = ['Kundenkreis', 'Namen', 'Zusatz', 'Straße, Nr.', 'PLZ', 
        'Ort', 'USt-Ident-Nr.', 'Ansprechpartner', 'Telefon', 'Handy',
        'Fax', 'Mail','Internetseite']

LISTBOX_ITEMS = {'0' : 'Privatkunde',
        '1' : 'Kleinbetrieb, bis 1000 € Jahresumsatz',
        '2' : 'Mittelständischer Betrieb, bis 10.000 € Jahresumsatz',
        '3' : 'Großbetrieb, bis 25.000 € Jahresumsatz',
        '4' : 'Konzern, ab 25.000 € Jahresumsatz',
        '5' : 'Komunaler Träger'}

class ListGui(object):

    def __init__(self, controller, items, items2, conf):
        self.root = tk.Tk()
        self.root.title(conf['title'])

        self.controller = controller
        self.items = ['{0}\t{1}'.format(item, items[item])
                                            for item in sorted(items)]
        self.items2 = items2

        self.frame = tk.Frame(self.root)
        self.frame.pack(side='top', padx=5, pady=5, fill='both',
                                                        expand=True)

        box_length = len(self.items)
        box_width = max(len(item) for item in self.items) - 5
        left_width = max(len(item) for item in self.items2)

        self.label_name = tk.Label(self.frame, height=2,
            width=conf['width'], text='Auswahl Kundenkreis',
            bg=conf['back_ground'], font=conf['font'], bd=0,
            highlightthickness=0, fg=conf['font_color'])
        self.label_name.pack(fill='both', expand=False)

        self.label_left = tk.Label(self.frame, bg=conf['back_ground'], 
            width=left_width, bd=0, highlightthickness=0)
        self.label_left.pack(side='left', ipady=10, fill='both',
            expand=False)

        self.place_maker_left = tk.Label(self.label_left,
            bg=conf['back_ground'], height=(box_length + 9),
            width=left_width, bd=0, highlightthickness=0)
        self.place_maker_left.pack(fill='both', expand=False)

        self.listbox = tk.Listbox(self.frame, height=box_length,
            width=box_width, font=conf['font'],
            selectmode=conf['select_mode'], bd=0, highlightthickness=0,
            fg=conf['font_color'])
        self.listbox.pack(padx=30, pady=30,
            fill='both', expand=False)
        self.listbox.insert(0, *self.items)
        self.listbox.bind('<<ListboxSelect>>', self.check)

        self.label_right = tk.Text(self.frame, 
            width=conf['width'], bd=0, highlightthickness=0)
        self.label_right.pack(pady=8, fill='both', expand=True)

        self.entries_var = list()
        self.items2 = ['{0}'.format(item) for item in items2]
        for index, item in enumerate(self.items2):
            self.name = tk.Label(self.label_left, text=item,
                width=(round(left_width * 1.5)), bg=conf['back_ground'],
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0)
            self.name.pack(pady=10, fill='both', expand=False)

            self.place_entry = tk.Label(self.label_right,
                width=(round(left_width * 1.5)),
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0)
            self.place_entry.pack(pady=10, fill='both', expand=False)

            entry_var = tk.StringVar()
            self.entries_var.append(entry_var)
            self.entry = tk.Entry(self.place_entry,
                    width=(round(left_width * 1.5)), bg='grey',
                    font=conf['font'], fg=conf['font_color'], bd=0,
                    highlightthickness=0)
            self.entry.pack(fill='both', expand=False)
            if index == 0:
                self.entry_select = self.entry
            entry_var.set('?')

        self.button_frame = tk.Frame(self.root, bg=conf['back_ground'])
        self.button_frame.pack(fill='x', ipady=5)

        tk.Button(self.button_frame, text="Abbrechen",
            font=conf['font'], fg=conf['font_color'],
            highlightthickness=0, command=self.root.destroy,).pack(
            side='right', padx=4)

        tk.Button(self.button_frame, text="Übernehmen",
            font=conf['font'], fg=conf['font_color'],
            highlightthickness=0,
            command=self.controller.collect_entries).pack(
            side='right', padx=4)

    def check(self, event):
        indices = list(map(int, self.listbox.curselection()))
        self.controller.process(self.items[indices[0]])
        self.entry_select.delete(0, tk.END)
        self.entry_select.insert(0, self.items[indices[0]])

    def run(self):
        self.root.mainloop()


class Controller(object):

    def __init__(self):
        self.model = Model(LISTBOX_ITEMS)
        self.model2 = Model(NAME_ITEMS)
        self.view = ListGui(self, self.model.items, self.model2.items,
                    CONFIG)

    def process(self, listbox_item):
        self.view.entries_var[0].set(listbox_item)
        print(listbox_item)

    def collect_entries(self):
        entry_data = dict()
        for index, entry_var in enumerate(self.view.entries_var):
            print("{} : {}".format(self.model2.items[index],
                entry_var.get()))
            entry_data[self.model2.items[0]] = entry_var.get()
        print()
        print(entry_data)

    def run(self):
        self.view.run()


class Model(object):

    def __init__(self, items):
        self.items = items
        self.items2 = items


def main():
    Controller().run()

if __name__ == '__main__':
    main()
Grüße Nobuddy
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Nobuddy

Mit meinen vorgeschlagenen Änderungen hättest du dir viel Arbeit ersparen können. Die Methode 'check' in 'ListGui' hättest du nicht modifizieren sollen. Auch bei der Erstellung der Entry-Felder hättest du nicht zwischen Eingabe-Feld[0] und den anderen Feldern unterscheiden müssen. Weil der Übertrag der Auswahl aus der Kundenkreisliste im 'Controller' über mit der Methode 'process' ins erste Eingabefeld erledigt wird.

Code: Alles auswählen

    def process(self, listbox_item):
        print(listbox_item)
        self.view.entries_var[0].set(listbox_item)
Bedingung ist natürlich, dass du bei der Erzeugung der Eingabefelder der Option 'textvariable' das Tkinter Steuervariable-Objekt 'entry_var' zugewiesen hättest.

Code: Alles auswählen

            entry_var = tk.StringVar()
            self.entries_var.append(entry_var)
            self.label = tk.Entry(self.label2e,
                width=(round(left_width * 1.5)), bg='grey',
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0, textvariable=entry_var)
            self.label.pack(fill='both', expand=False)
            entry_var.set('?')
Aber du hast bei deiner letzten Variante meine vorgeschlagene Änderung nicht angewendet.
Hier noch die Variante, welche genau meine Änderungen enthält:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x

import tkinter as tk

CONFIG = {'width' : 100,
        'title' : "Anlage Neukunden",
        'font': ('NimbusSansL', 14, 'bold'),
        'font_color': 'black',
        'back_ground' : 'orange',
        'select_mode': 'single'}

NAME_ITEMS = ['Namen', 'Zusatz', 'Straße, Nr.', 'PLZ',
        'Ort', 'USt-Ident-Nr.', 'Ansprechpartner', 'Telefon', 'Handy',
        'Fax', 'Mail','Internetseite']

LISTBOX_ITEMS = {'0' : 'Privatkunde',
        '1' : 'Kleinbetrieb, bis 1000 € Jahresumsatz',
        '2' : 'Mittelständischer Betrieb, bis 10.000 € Jahresumsatz',
        '3' : 'Großbetrieb, bis 25.000 € Jahresumsatz',
        '4' : 'Konzern, ab 25.000 € Jahresumsatz',
        '5' : 'Komunaler Träger'}

class ListGui(object):

    def __init__(self, controller, items, items2, conf):
        self.root = tk.Tk()
        self.root.title(conf['title'])

        self.controller = controller
        self.items = ['{0}\t{1}'.format(item, items[item])
                                            for item in sorted(items)]
        self.items2 = items2

        self.frame = tk.Frame(self.root)
        self.frame.pack(side='top', padx=5, ipady=5, fill='both', expand=True)

        box_length = len(self.items)
        box_width = max(len(item) for item in self.items) - 5
        left_width = max(len(item) for item in self.items2)

        self.label_name = tk.Label(self.frame, height=2,
            width=conf['width'], text='Auswahl Kundenkreis',
            bg=conf['back_ground'], font=conf['font'], bd=0,
            highlightthickness=0, fg=conf['font_color'])
        self.label_name.pack(fill='both', expand=False)

        self.label_left = tk.Label(self.frame, bg=conf['back_ground'],
            width=left_width, bd=0, highlightthickness=0)
        self.label_left.pack(side='left', ipady=10, fill='both',
            expand=False)

        self.label_left2 = tk.Label(self.label_left, bg=conf['back_ground'],
            height=(box_length + 14), width=left_width, bd=0,
            highlightthickness=0)
        self.label_left2.pack(fill='both', expand=False)

        self.listbox = tk.Listbox(self.frame, height=box_length,
            width=box_width, font=conf['font'],
            selectmode=conf['select_mode'], bd=0, highlightthickness=0,
            fg=conf['font_color'])
        self.listbox.pack(padx=30, pady=30,
            fill='both', expand=False)
        self.listbox.insert(0, *self.items)
        self.listbox.bind('<<ListboxSelect>>', self.check)

        self.label_select = tk.Label(self.frame, bg='grey',
            height=5, width=left_width, bd=0, highlightthickness=0)
        self.label_select.pack(fill='both', expand=False)

        self.label_right = tk.Text(self.frame,
            width=conf['width'], bd=0, highlightthickness=0)
        self.label_right.pack(pady=8, fill='both', expand=True)
        
        self.entries_var = list()
        self.items2 = ['{0}'.format(item) for item in items2]
        for item in self.items2:
            self.label = tk.Label(self.label_left, text=item,
                width=(round(left_width * 1.5)), bg=conf['back_ground'],
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0)
            self.label.pack(pady=10, fill='both', expand=False)

            self.label2e = tk.Label(self.label_right,
                width=(round(left_width * 1.5)),
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0)
            self.label2e.pack(pady=10, fill='both', expand=False)

            entry_var = tk.StringVar()
            self.entries_var.append(entry_var)
            self.label = tk.Entry(self.label2e,
                width=(round(left_width * 1.5)), bg='grey',
                font=conf['font'], fg=conf['font_color'], bd=0,
                highlightthickness=0, textvariable=entry_var)
            self.label.pack(fill='both', expand=False)
            entry_var.set('?')

        self.button_frame = tk.Frame(self.root, bg=conf['back_ground'])
        self.button_frame.pack(fill='x', ipady=5)

        tk.Button(self.button_frame, text="Abbrechen",
            font=conf['font'], fg=conf['font_color'], highlightthickness=0,
            command=self.root.destroy,).pack(side='right', padx=4)

        tk.Button(self.button_frame, text="Übernehmen",
            font=conf['font'], fg=conf['font_color'], highlightthickness=0,
            command=self.controller.collect_entries).pack(side='right', padx=4)


    def check(self, event):
        indices = list(map(int, self.listbox.curselection()))
        self.controller.process(self.items[indices[0]])


    def run(self):
        self.root.mainloop()


class Controller(object):

    def __init__(self):
        self.model = Model(LISTBOX_ITEMS)
        self.model2 = Model(NAME_ITEMS)
        self.view = ListGui(self, self.model.items, self.model2.items,
                    CONFIG)


    def process(self, listbox_item):
        print(listbox_item)
        self.view.entries_var[0].set(listbox_item)

    def collect_entries(self):
        entry_data = dict()
        for index, entry_var in enumerate(self.view.entries_var):
            print("{} : {}".format(self.model2.items[index],
            entry_var.get()))
            entry_data[self.model2.items[index]] = entry_var.get()
        print()
        print(entry_data)


    def run(self):
        self.view.run()


class Model(object):

    def __init__(self, items):
        self.items = items
        self.items2 = items


def main():
    Controller().run()

if __name__ == '__main__':
    main()
Beim Start des Skriptes werden alle Eingabefelder mit '?' belegt. Wenn du ein Eintrag in der Kunden-Kreislist aktivierst wird dieser ins erste Eingabefeld übetragen. Wenn du die Schaltfläche 'Übernehmen' aktivierst wird über die Methode 'collect_entries' im 'Controller' alle Werte der Eingabefelder mit 'print(.......) ausgegeben. Bitte mein obiges Skript vor einer neuen Modifikation ausprobieren!

Gruß wuf :wink:
Take it easy Mates!
Nobuddy
User
Beiträge: 1015
Registriert: Montag 30. Januar 2012, 16:38

Hallo wuf,
Du hast Recht, da habe ich irgendwo einen Fehler gemacht.
Werde morgen mal vergleichen, wo bei mir da der Fehler liegt.

Danke für Deine Unterstützung! :wink:

Grüße Nobuddy

Nachtrag:
Habe meinen Fehler gefunden, habe das unterschlagen ', textvariable=entry_var'.
Hätte ich kopiert, wäre das nicht passiert. :oops:
Antworten