Erstellung eines Programms mit Einsatz von Tkinter

Fragen zu Tkinter.
Antworten
.devista
User
Beiträge: 7
Registriert: Montag 23. Februar 2015, 23:04

Hi zusammen,

ich bin gerade dabei, ein kleines Programm zu schreiben, welches zur Dokumentation der Amphibienwanderung im Rahmen des Amphibienschutzes behilflich sein soll. Das Programm beinhaltet die Eingabe von Daten in verschiedene Felder und die anschließende Übertragung in eine Datenbank. Das Hauptelement des Programms ist eine Art Tabelle, in der je nach Bedarf Zeilen hinzugefügt werden können. Nachfolgend der vorläufige Aufbau des Programms:

Bild

Ich habe ein wenig Vorerfahrung, was das Programmieren betrifft. In der Vergangenheit habe ich jedoch hauptsächlich mit Java programmiert. Erst sein wenigen Tagen beschäftige ich mit Python. Ich habe mich dazu entschlossen, das Projekt mit Python umzusetzen, weil ich die Sprache lernen möchte und Python recht flexibel ist.

Ich werde morgen bzw. später :) abschnittsweise meinen Code posten. Vorab eine grundsätzliche Frage: wie würdet ihr das Tabellenkonstrukt aufbauen? Bisher sieht es bei mir so aus, dass ich sämtliche Elemente (Entry, Label, etc.) in eine Liste packe, welche ich dann wiederum beim Klicken auf "Zeile hinzufügen" an eine Liste hänge. Was mir am meisten Probleme bereitet, ist die "Indexierung" von den einzelnen Zeilen. Mehr dazu im nächsten Post.

Vielleicht kann der ein oder andere schon mal kurz einen Input geben. Ich würde mich freuen.


P.S.: Ich bin mir nicht ganz sicher, ob ich mit dem Beitrag im richtigen Subforum bin. Wenn nötig, bitte verschieben.
.devista
User
Beiträge: 7
Registriert: Montag 23. Februar 2015, 23:04

Ok, ich poste jetzt einfach 'mal meinen bisherigen Code. Dazu ein paar Fragen:

1) Wie realisiere ich die Aktualisierung der Tabelle auf dem Bildschirm, wenn ich eine Zeile lösche? Beim Hinzufügen einer Zeile geschieht das (automatisch).
2) Wenn ich die Werte aus den Entries in die Datenbank übertragen möchte, brauche ich noch eine weitere Liste, in der ich die ganzen Werte in korrekter Form ablege. Ist das richtig?
3) Kennt ihr ein paar gute Tutorials bzw. Literatur, welche Python und GUI Programmierung behandeln (wenn möglich nach dem MVC Pattern)?

Code: Alles auswählen

from tkinter import *
from tkinter import ttk

class MyApp:

    def __init__(self, parent):

    # setup frames and their widgets
        # setup frame containing the table
        self.tableFrame = ttk.Frame(parent)
        self.tableFrame.grid(row=1, columnspan=14, padx=5, pady=3)
        table = MyTable(self.tableFrame, 0, 15)

        # setup frame at the top
        self.upperFrame = ttk.Frame(parent)
        self.upperFrame.grid(row=0, columnspan=5, padx=5, pady=5, sticky="w")
        # setup labels in this frame (Record, etc.)
        label = ttk.Label(self.upperFrame, text = "Frühjahrswanderung: XYZ")
        label.config(font=("Helvetica", 26), relief=SUNKEN)
        label.grid(row = 0, column=0, columnspan=4, padx=7, pady=7)
        ttk.Label(self.upperFrame, text = "Record:").grid(row = 1, column=0, sticky="w", padx=7)
        ttk.Label(self.upperFrame, text = "Datum:").grid(row = 2, column=0, sticky="w", padx=7)
        ttk.Label(self.upperFrame, text = "Zeit:").grid(row = 3, column=0, sticky="w", padx=7)
        ttk.Label(self.upperFrame, text = "Temperatur:").grid(row = 4, column=0, sticky="w", padx=7)
        ttk.Label(self.upperFrame, text = "Witterung:").grid(row = 5, column=0, sticky="w", padx=7)
        # setup entries next to the labels, the label here is an exception (should not be editable)
        ttk.Label(self.upperFrame, text = "No of the record, this text is replaced later").grid(row = 1, column=1, sticky="w")
        self.entryDate = ttk.Entry(self.upperFrame, width=15).grid(row = 2, column=1, sticky="w")
        self.entryTime = ttk.Entry(self.upperFrame, width=15).grid(row = 3, column=1, sticky="w")
        self.entryTemperature = ttk.Entry(self.upperFrame, width=15).grid(row = 4, column=1, sticky="w")
        self.entryWeather = ttk.Entry(self.upperFrame, width=15).grid(row = 5, column=1, sticky="w")

        # setup frame with the main buttons
        self.buttonFrame = ttk.Frame(parent)
        self.buttonFrame.grid(row=0, column=5, pady=5, sticky="s")
        addButton = ttk.Button(self.buttonFrame, text="Zeile hinzufügen", width=12)
        addButton.bind("<Button-1>", table.createRow)
        addButton.grid(row=0, column=0, padx=7, pady=2)
        delButton = ttk.Button(self.buttonFrame, text="Zeile entfernen", width=12)
        delButton.bind("<Button-1>", table.deleteRow)
        delButton.grid(row=1, column=0, padx=7, pady=2)
        saveButton = ttk.Button(self.buttonFrame, text="Speichern", width=10)
        saveButton.grid(row=0, column=1, padx=7, rowspan=2)


class MyTable():

    def __init__(self, parent, rows, columns):
        # define variables
        self.parent = parent
        self.rowCount = rows
        self.columnCount = columns
        self.tableContent = []
        self.row = []
        self.rowsToDel = []
        # call methods to build up initial table
        self.createHeader()
        self.createRow(event="")

    def createHeader(self):

        # setup first labels (Lebende Tiere, Tote Tiere)
        filabel1 = ttk.Label(self.parent, text=" Lebende Tiere")
        filabel1.config(font=("Helvetica", 18), relief=RIDGE)
        filabel1.grid(row=0, column=1, columnspan=10, sticky="we")
        filabel2 = ttk.Label(self.parent, text=" Tote Tiere")
        filabel2.config(font=("Helvetica", 18), relief=RIDGE)
        filabel2.grid(row=0, column=11, columnspan=3, sticky="we")

        # setup upper labels (Eimer Nr., etc.)
        uplabel1 = ttk.Label(self.parent, text="    Eimer Nr.", width=10)
        uplabel1.config(relief=RIDGE)
        uplabel1.grid(row=0, column=0, rowspan=3, sticky="nwse")
        uplabel2 = ttk.Label(self.parent, text="  Erdkröten", width=10)
        uplabel2.config(relief=RIDGE)
        uplabel2.grid(row=1, column=1, columnspan = 4, sticky="we")
        uplabel3 = ttk.Label(self.parent, text="  Grasfrösche", width=10)
        uplabel3.config(relief=RIDGE)
        uplabel3.grid(row=1, column=5, columnspan = 4, sticky="we")
        uplabel4 = ttk.Label(self.parent, text="  Andere Tiere", width=10)
        uplabel4.config(relief=RIDGE)
        uplabel4.grid(row=1, column=9, rowspan=2, sticky="nwse")
        uplabel5 = ttk.Label(self.parent, text="  Erdkröten", width=10)
        uplabel5.config(relief=RIDGE)
        uplabel5.grid(row=1, column=11, rowspan=2, sticky="nwse")
        uplabel6 = ttk.Label(self.parent, text="  Andere Tiere", width=10)
        uplabel6.config(relief=RIDGE)
        uplabel6.grid(row=1, column=12, rowspan=2, sticky="nwse")

        # setup lower labels (Männlich, etc.)
        lolabel1 = ttk.Label(self.parent, text="  Männlich", width=10)
        lolabel1.config(relief=RIDGE)
        lolabel1.grid(row=2, column=1, sticky="we")
        lolabel2 = ttk.Label(self.parent, text="  Weiblich", width=10)
        lolabel2.config(relief=RIDGE)
        lolabel2.grid(row=2, column=2, sticky="we")
        lolabel3 = ttk.Label(self.parent, text="  Junge", width=10)
        lolabel3.config(relief=RIDGE)
        lolabel3.grid(row=2, column=3, sticky="we")
        lolabel4 = ttk.Label(self.parent, text="  Paare", width=10)
        lolabel4.config(relief=RIDGE)
        lolabel4.grid(row=2, column=4, sticky="we")
        lolabel5 = ttk.Label(self.parent, text="  Männlich", width=10)
        lolabel5.config(relief=RIDGE)
        lolabel5.grid(row=2, column=5, sticky="we")
        lolabel6 = ttk.Label(self.parent, text="  Weiblich", width=10)
        lolabel6.config(relief=RIDGE)
        lolabel6.grid(row=2, column=6, sticky="we")
        lolabel7 = ttk.Label(self.parent, text="  Junge", width=10)
        lolabel7.config(relief=RIDGE)
        lolabel7.grid(row=2, column=7, sticky="we")
        lolabel8 = ttk.Label(self.parent, text="  Paare", width=10)
        lolabel8.config(relief=RIDGE)
        lolabel8.grid(row=2, column=8, sticky="we")

        # increase row count so that the rows with the content are appended correctly
        self.rowCount+=3

    def createRow(self, event):
        for column in range(self.columnCount):
            if column == 9 or column == 12:
                button = ttk.Button(self.parent, text="+", width=10)
                button.grid(column=column, row=self.rowCount, sticky="we")
                self.row.append(button)
            elif column == 10 or column == 13:
                label = ttk.Label(self.parent, text="Platzhalter", width=10)
                label.grid(column=column, row=self.rowCount, sticky="we")
                self.row.append(label)
            elif column == 14:
                checkButton = ttk.Checkbutton(self.parent, onvalue=True, offvalue=False, command=lambda row=self.rowCount: self.setRowForDeletion(row))
                checkButton.grid(column=column, row=self.rowCount, sticky="we", padx=3)
                self.row.append(checkButton)
            else:
                entry = ttk.Entry(self.parent, width=10)
                entry.grid(column=column, row=self.rowCount, sticky="we")
                self.row.append(entry)
            self.tableContent.append(self.row)
        # increase row count for the next row
        self.rowCount+=1
        #return self.mainRows

    def deleteRow(self, event):
        for row in self.rowsToDel:
            del self.tableContent[row-3]
            self.rowsToDel.remove(row)

    def setRowForDeletion(self, row):
        self.rowsToDel.append(row)

def main():
    root = Tk()
    root.config(bg="GREY")
    myGUI = MyApp(root)
    root.mainloop()

if __name__ == '__main__': main()
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Hallo und willkommen bei Python und hier im Forum!

Ich kann das Bild in deinem ersten Beitrag nicht sehen. Geht das nur mir so?
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
.devista
User
Beiträge: 7
Registriert: Montag 23. Februar 2015, 23:04

Danke für die Begrüßung :)

Ich weiß leider nicht genau, warum du das Bild nicht sehen kannst. Geht es noch mehreren so?
BlackJack

Ich kann das Bild sehen.

@Kebap: Ist bei Dropbox gehostet. Filterst/blockierst Du das zufällig?
BlackJack

@.devista: Erst einmal ein paar Anmerkungen zum Quelltext:

Schau Dir mal den Style Guide for Python Code an. Deine Namensschreibweise und die Zeilenlängen halten sich da beispielsweise nicht immer dran.

Sternchenimporte sollte man vermeiden. Dadurch werden Programme unübersichtlich weil man nicht mehr so leicht sieht wo ein Name herkommt. Und es besteht die Gefahr von Namenskollisionen. Die Tk-Anbindung kippt einem beim *-Import mal eben ca. 190 Namen ins Modul.

Was bringt der Präfix `my` bei `MyApp`, `MyTable`, und `myGUI`? Ohne würden die Namen letztlich genau das selbe bedeuten.

Statt eine einzelne Tabellenzeile als Liste mit Widgets in einer Zeilenliste zu speichern, würde ich tatsächlich anfangen GUI und Programmlogik/Datenhaltung zu trennen. Soweit ich das sehe kann man aus einem Gridlayout keine Zeilen löschen. Man müsste also wenn man Datensätze aus dem Modell löscht, das Grid verwerfen und neu erstellen, ohne die gelöschten Datensätze.

Das `row`-Attribut auf dem `MyTable`-Objekt macht keinen Sinn. Das müsste eigentlich eine lokale Variable in `createRow()` sein. Dann hat man auch gar nicht erst das Problem was der Code momentan hat: Jede Zeile hat immer noch die Einträge von allen vorhergehenden weil Du `row` niemals an eine neue Liste bindest. Und das Anhängen an die Zeilenliste ist an der falschen Stelle im Code. Du solltest Dir die Liste mal anschauen. ;-)

Das `MyTable` per Gridlayout Widgets im `parent` platziert ist unflexibel und fehleranfällig. Damit rechnet auch niemand. `MyTable` sollte selbst ein Widget sein und zum Beispiel von `Frame` erben.

Statt beim *Aufruf* von `createRow()` einen Dummywert zu übergeben macht es mehr Sinn bei der Methode einen Dummywert als Default zu setzen. Und dann auch eher `None` als eine leere Zeichenkette, denn genau dafür ist der Wert gedacht. Allerdings wäre das gar nicht notwendig wenn Du nicht manuell den Mausklick an die Schaltfläche binden würdest sondern wie vorgesehen die `command`-Option verwenden würdest. Bei dem `bind()` verhalten sich Schaltflächen auch nicht so wie der Benutzer das gewohnt ist, das ist also keine gute Idee.

Die ganzen durchnummerierten Namen in `createHeader()` werden gar nicht benötigt und der Code wäre leichter wartbar wenn man das nicht alles zigmal hinschreibt und leicht anpasst, sondern die Unterschiede als Daten heraus zieht.

Das löschen von Zeilen ist komisch gelöst beziehungsweise funktioniert so nicht. Wenn man den `Checkbutton` wieder deaktiviert würden die meisten Benutzer erwarten das die Zeile dann nicht gelöscht wird. Das macht der Code aber nicht. Wenn man die selbe Zeile mehrfach zum Löschen anklickt wird sie mehrfach zu der Liste hinzugefügt, was zu einem Fehler führen dürfte beim Löschen.

Die Löschmethode hat ein Problem: Sowie ein Element aus der Liste gelöscht wurde dann stimmen die Indexwerte nicht mehr und es wird mit jedem Löschen ”falscher”. Das löschen der zu löschenden Indexe einzeln innerhalb der Schleife ist ineffizient. Da wäre es geschickter am Ende der Schleife diese Datenstruktur einfach an eine neue, leere zu binden. Letztendlich würde man das aber eher so lösen das man in der Löschmethode über die Zeilen iteriert und sich am Status des `Checkbutton` orientiert.

Ich komme dann als Zwischenergebniss bei so etwas heraus:

Code: Alles auswählen

#!/usr/bin/env python3
# coding: utf8
import tkinter as tk
from tkinter import ttk


class Table(ttk.Frame):
 
    def __init__(self, parent, rows, columns):
        ttk.Frame.__init__(self, parent)
        self.row_count = rows
        self.column_count = columns
        self.table_content = list()
        self.row_numbers_to_delete = list()
        # 
        # Call methods to build up initial table.
        # 
        self._create_header()
        self.create_row()
 
    def _create_header(self):
        helvetica = ('Helvetica', 18)
        for text, position, font in [
            ('Eimer Nr.', (0, 0, 0, 3), None),
            
            ('Lebende Tiere', (0, 1, 10, 0), helvetica),
            ('Tote Tiere', (0, 11, 3, 0), helvetica),
            
            ('Erdkröten', (1, 1, 4, 0), None),
            ('Grasfrösche', (1, 5, 4, 0), None),
            ('Andere Tiere', (1, 9, 0, 2), None),
            ('Erdkröten', (1, 11, 0, 2), None),
            ('Grasfrösche', (1, 12, 0, 2), None),

            ('Männlich', (2, 1, 0, 0), None),
            ('Weiblich', (2, 2, 0, 0), None),
            ('Junge', (2, 3, 0, 0), None),
            ('Paare', (2, 4, 0, 0), None),
            ('Männlich', (2, 5, 0, 0), None),
            ('Weiblich', (2, 6, 0, 0), None),
            ('Junge', (2, 7, 0, 0), None),
            ('Paare', (2, 8, 0, 0), None),
        ]:
            row, column, columnspan, rowspan = position
            options = dict()
            if font:
                options['font'] = font
            if not (columnspan or rowspan):
                options['width'] = 10
            label = ttk.Label(self, text=text, relief=tk.RIDGE, **options)
            options = {
                'row': row,
                'column': column,
                'sticky': 'we' + ('ns' if rowspan > 1 else '')
            }
            if columnspan > 1:
                options['columnspan'] = columnspan
            if rowspan > 1:
                options['rowspan'] = rowspan
            label.grid(**options)
 
        self.row_count += 3
 
    def create_row(self):
        row = list()
        for column in range(self.column_count):
            if column in [9, 12]:
                button = ttk.Button(self, text='+', width=10)
                button.grid(column=column, row=self.row_count, sticky='we')
                row.append(button)
            elif column in [10, 13]:
                label = ttk.Label(self, text='Platzhalter', width=10)
                label.grid(column=column, row=self.row_count, sticky='we')
                row.append(label)
            elif column == 14:
                variable = tk.IntVar()
                button = ttk.Checkbutton(self, variable=variable)
                button.grid(
                    column=column, row=self.row_count, sticky='we', padx=3
                )
                button.variable = variable
                row.append(button)
            else:
                entry = ttk.Entry(self, width=10)
                entry.grid(column=column, row=self.row_count, sticky='we')
                row.append(entry)
            
            self.table_content.append(row)

        self.row_count += 1
 
    def delete_rows(self):
        # 
        # FIXME Need to redraw the table here.
        # 
        # TODO Replace magical number by constant or introduce an own widget
        #   for rows.
        # 
        self.table_content = [
            row for row in self.table_content if not row[14].variable.get()
        ]

 
class App(object):
 
    def __init__(self, parent):
 
        table = Table(parent, 0, 15)
        table.grid(row=1, columnspan=14, padx=5, pady=3)
 
        # setup frame at the top
        upper_frame = ttk.Frame(parent)
        upper_frame.grid(row=0, columnspan=5, padx=5, pady=5, sticky='w')
        # setup labels in this frame (Record, etc.)
        ttk.Label(
            upper_frame,
            text='Frühjahrswanderung: XYZ',
            font=('Helvetica', 26),
            relief=tk.SUNKEN
        ).grid(row=0, column=0, columnspan=4, padx=7, pady=7)
        ttk.Label(upper_frame, text='Record:').grid(
            row=1, column=0, sticky='w', padx=7
        )
        ttk.Label(upper_frame, text='Datum:').grid(
            row=2, column=0, sticky='w', padx=7
        )
        ttk.Label(upper_frame, text='Zeit:').grid(
            row=3, column=0, sticky='w', padx=7
        )
        ttk.Label(upper_frame, text='Temperatur:').grid(
            row=4, column=0, sticky='w', padx=7
        )
        ttk.Label(upper_frame, text='Witterung:').grid(
            row=5, column=0, sticky='w', padx=7
        )
        # setup entries next to the labels, the label here is an exception
        # (should not be editable)
        ttk.Label(
            upper_frame, text='No of the record, this text is replaced later'
        ).grid(row=1, column=1, sticky='w')
        self.date_entry = ttk.Entry(upper_frame, width=15).grid(
            row=2, column=1, sticky='w'
        )
        self.time_entry = ttk.Entry(upper_frame, width=15).grid(
            row=3, column=1, sticky='w'
        )
        self.temperature_entry = ttk.Entry(upper_frame, width=15).grid(
            row=4, column=1, sticky='w'
        )
        self.weather_entry = ttk.Entry(upper_frame, width=15).grid(
            row=5, column=1, sticky='w'
        )

        # setup frame with the main buttons
        button_frame = ttk.Frame(parent)
        button_frame.grid(row=0, column=5, pady=5, sticky='s')
        ttk.Button(
            button_frame,
            text='Zeile hinzufügen',
            width=12,
            command=table.create_row
        ).grid(row=0, column=0, padx=7, pady=2)
        ttk.Button(
            button_frame,
            text='Zeile entfernen',
            width=12,
            command=table.delete_rows
        ).grid(row=1, column=0, padx=7, pady=2)
        ttk.Button(button_frame, text='Speichern', width=10).grid(
            row=0, column=1, padx=7, rowspan=2
        )
 
  
def main():
    root = tk.Tk()
    root.config(bg='GREY')
    _app = App(root)
    root.mainloop()
 

if __name__ == '__main__':
    main()
.devista
User
Beiträge: 7
Registriert: Montag 23. Februar 2015, 23:04

@BlackJack: Vielen Dank für deine ausführliche Antwort und für das Bearbeiten des Codes. Leider komme ich an der jetzigen Stellen (noch) nicht weiter.

Ich muss mich in den nächsten Tagen einfach intensiver mit der Materie befassen. Zur Quellensuche war das Unterforum "Links und Tutorials" ganz hilfreich. Neben den Tutorials und der Literatur zu Python im Allgemeinen fand ich ein Buch, welches sich speziell Python und Tkinter widmet. Es heisst "Tkinter GUI application development HOTSHOT".

Ich melde mich in ein, zwei Wochen wieder, wenn ich mit dem Programm ein wenig vorangekommen bin. Es tauchen bestimmt noch zahlreiche Fragen auf. Fürs erste bin ich aber versorgt :).
.devista
User
Beiträge: 7
Registriert: Montag 23. Februar 2015, 23:04

Ich bin ein wenig weiter gekommen mit meinem Programm. Das Hinzufügen und Löschen von Tabellenzeilen funktioniert jetzt. Leider gibt es schon das nächste Problem.

Geplant ist, dass nach Betätigen eines "+" Buttons in einer Zeile ein neues Fenster aufgeht, in welchem weitere Eingaben getätigt werden können. Nachdem dies geschehen ist, soll in dem Textfeld rechts neben dem entsprechenden Button eine Kurzform der Eingaben erscheinen. Dies soll hauptsächlich als Hinweis für den Benutzer dienen.
Das Problem ist, dass sich mein Tabellenkonstrukt, d.h. die Zeilen mit den Widgets, und der Inhalt der Tabelle ("self.tableContent") nicht decken. Daher ist es nicht so einfach, den gedrückten Button eindeutig zu identifizieren. Ich habe schon versucht, den Buttons beim Erzeugen eine Variable mitzugeben, aber bin damit nicht weitergekommen.

Wie könnte ich das am geschicktesten lösen?
BlackJack

@.devista: Suchst Du eventuell `functools.partial()` oder ``lambda``-Ausdrücke?
.devista
User
Beiträge: 7
Registriert: Montag 23. Februar 2015, 23:04

Das hilft mir leider nicht viel weiter. Ich nehme an, die gewünschte Aktion kann über den Status des Buttons getriggert werden. Leider krieg ich das nicht hin. Vielleicht stehe ich auch gerade auf dem Schlauch. Lambda Ausdrücke sind mir jedenfalls schon begegnet.
BlackJack

.devista: Na ich dachte Du wolltest das der Rückruffunktion für alle Buttons ein Wert übergeben werden sollte der bei jedem Button unterschiedlich ist. Und so eine Funktion kann man für jeden Button mit `functools.partial()` aus der Rückruffunktion und dem jeweiligen Wert erstellen. Oder halt als ``lambda``-Ausdruck.
.devista
User
Beiträge: 7
Registriert: Montag 23. Februar 2015, 23:04

Ich habe versucht, den Buttons per Binding die gewünschte Funktionalität zu geben. Leider funktioniert das nicht so, wie ich das möchte, d.h. das Attribut "State" ändert sich nach Betätigen des Buttons nicht. Im Moment sieht das Ganze so aus:

Code: Alles auswählen

def create_row(self):
        #
        # Setup rows for the content
        #
        row = list()
        for column in range(self.column_count):
            if column in [9, 12]:
                #variable_1 = tk.IntVar()
                button = ttk.Button(
                    self.contentFrame,
                    text='Eintrag hinzufügen',
                    width=15
                    #state=variable_1
                    #command=button.__setitem__(self, "State", 1)
                )
                #button.config(command=button.__setitem__("state", 2))
                button.bind("<Button-1>", lambda e: button.__setitem__("state", "active"))
                button.grid(column=column, row=self.row_count, sticky='we')
                row.append(button)
            elif column in [10, 13]:
                label = ttk.Label(self.contentFrame, text='Platzhalter', width=10)
                label.grid(column=column, row=self.row_count, sticky='we')
                row.append(label)
            elif column == 14:
                variable_2 = tk.IntVar()
                button = ttk.Checkbutton(self.contentFrame, variable=variable_2)
                button.grid(
                    column=column, row=self.row_count, sticky='we', padx=3
                )
                button.variable = variable_2
                row.append(button)
            else:
                entry = ttk.Entry(self.contentFrame, width=10)
                entry.grid(column=column, row=self.row_count, sticky='we')
                row.append(entry)

        self.table_content.append(row)
        # Increase variable row count to set the new created widgets in the right row
        self.row_count += 1
Ich wäre echt dankbar für Lösungsvorschläge.
BlackJack

@.devista: Die ”magischen” Methoden sollte man nur direkt aufrufen wenn es nicht anders geht. Statt `__setitem__()` sollte man also die Indexzuweisung machen.

Das Problem hier ist das `button` nicht zu einem Wert aufgelöst wird wenn die anonyme Funktion *erstellt* wird, sondern erst dann wenn sie *aufgerufen* wird. Default-Argumente werden dagegen beim erstellen einer Funktion gebunden. Eine Lösung wäre deshalb ``lambda b=button: b['state'] = tk.ACTIVE``. Oder eben wie schon gesagt `functools.partial()`, in diesem Fall mit der `setitem()`-Funktion aus dem `operator`-Modul: ``partial(setitem, button, 'state', tk.ACTIVE)``.

Und bitte verwende nicht `bind()` bei `Button`\s, denn dann verhalten die sich nicht mehr wie der Benutzer das gewohnt ist.
Antworten