Sudoku in Tk

Fragen zu Tkinter.
Antworten
KlausP
User
Beiträge: 60
Registriert: Mittwoch 8. Juli 2020, 17:00

Hallo,
ich habe ein Terminalprogramm erstellt, um Sodoku aufzulösen.
Es läuft, aber in einer GUI wäre es viel schöner.
Ich habe mit Tk auch schon Erfahrung - allerdings nicht mit einer Matrix mit 81 Feldern.
Selbst, wenn die Feldnamen erstellt wären wie z.b. matrix11, matrix12, matrix19, matrix21 ... matrix29, ... matrix99 müssen diese ja alle angesprochen werden.
Ehe ich nun loslege, mal die Frage, ob ich in diesem Sinne weitermachen sollte.
Ich würde vielleicht eine Class mit 81 Variablen erstellen.

Habt ihr irgendwelche Empfehlungen?
Ich will erstmal nicht nach fertigen Lösungen suchen.

In meinem Terminalprogramm habe ich mit neun Reihen als Listen mit je 9 Feldern gearbeítet und daraus Spalten und die 9 Cubes errechnet (alles Listen).
Das war eine ziemliche Akrobatik.
Vielleicht wäre es besser, mich mit Arrays für Python anzufreunden?

Vielen Dank für eure Kommentare.
Klaus
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und auch Entries kann man in Listen stecken. Dann hat man keine 81 Variablen, sondern eben eine Liste von Listen.

Code: Alles auswählen

import tkinter as tk


class SudokuField:

    def __init__(self, parent):
        rows = []
        for row in range(9):
            row_frame = tk.Frame(parent)
            row_frame.pack(side=tk.BOTTOM)
            for column in range(9):
                entry = tk.Entry(row_frame, text="0", width=1)
                entry.pack(side=tk.LEFT)


def main():
    root = tk.Tk()
    field = SudokuField(root)
    root.mainloop()


if __name__ == '__main__':
    main()
Wobei du natuerlich auch noch andere Strukturierungen haben kannst, also zB 3 * 3 Bloecke von jeweils wieder 3 * 3 Entries, etc. Was auch immer da gewuenscht/besser ist. Und die Werte koennen auch noch tk.IntVar() sein, statt direkt mit den Entries zu arbeiten, etc. pp.
KlausP
User
Beiträge: 60
Registriert: Mittwoch 8. Juli 2020, 17:00

Danke für den guten Hinweis.
Es ist mir schon prinzipiell klar, wie du die Matrix in Tk initialisierst.
Aber könntest du wohl noch 2 Zeilen in main() ergänzen, wie ich per SudokuField z.B. zwei Eingaben in der Matrix adressiere?
Wie übergebe oder lese ich ein bestimmtes "field" ?
Muss doch irgendwie als field von (x,y) angesprochen werden.
Sorry, ein kleiner Hinweis wäre schon noch hilfreich für mich.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

So zB:

Code: Alles auswählen

import tkinter as tk


class SudokuField:

    def __init__(self, parent):
        self._rows = []
        for j in range(9):
            row_frame = tk.Frame(parent)
            row_frame.pack(side=tk.BOTTOM)
            row = []
            self._rows.append(row)
            for i in range(9):
                entry = tk.Entry(row_frame, width=1)
                entry.insert(0, f"{j},{i}")
                entry.pack(side=tk.LEFT)
                row.append(entry)

    def __getitem__(self, index):
        return self._rows[index]


def main():
    root = tk.Tk()
    field = SudokuField(root)
    print(field[7][3].get())
    root.mainloop()


if __name__ == '__main__':
    main()
Wobei das __getitem__ auch ein bisschen ueberkandidelt ist. Du kannst aber doch jetzt schon mit Listen umgehen, anders ist das hier auch nicht.
KlausP
User
Beiträge: 60
Registriert: Mittwoch 8. Juli 2020, 17:00

hmm, leider noch ne Frage:

print (field[7][3].get()) ... verstehe ich schon.

aber:
def __getitem__(self, index):
verstehe ich nicht ... wofür?

Es würde auch nur den Index der Reihe zurückgeben. Aber den hätte ich mit [7] doch schon.

Und in der Printzeile wird ja gar kein Index (an _get_item_) übergeben?
wofür auch?
Warum sollte sich _getitem_ nur um den Index der Zeile kümmern?

... sind doch ein paar Fragen geworden
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ohne __getitem__ fehlt der Zugriff auf _rows. Kann man auch machen, verletzt aber Demeter’s law.
KlausP
User
Beiträge: 60
Registriert: Mittwoch 8. Juli 2020, 17:00

Hatte vorgestern "danke" sagen wollen; offenbar hatte ich vergessen zu senden.
KlausP
User
Beiträge: 60
Registriert: Mittwoch 8. Juli 2020, 17:00

danke dir. Habe nochmal hereingeschaut
Ja, sind Entries.
Aber wenn ich z.b. im Code "field[6][5].set("A")" ergänze, bringt es einen Fehler.
Da hab ich es dann anders versucht.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das waere ja eher mal ein Grund nachzufragen, was denn da schief lief, statt es komplett anders zu machen. Aber kannst du natuerlich auch machen.
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich tippe mal ganz stark auf `AttributeError` weil `Entry`-Objekte keine `set()`-Methode haben.

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
KlausP
User
Beiträge: 60
Registriert: Mittwoch 8. Juli 2020, 17:00

@_deets_:
na, ich wollte dich nicht nerven, weil ich ja nicht explizit "speichern" erwähnt hatte.
Und zunächst hatte ich gedacht, ich fände brauchbare Tipps im Forum; habe ich aber nicht.

>> AttributeError: 'Entry' object has no attribute 'set'. Did you mean: 'get'?

nein, meinte ich nicht, weil es beim Speichern nicht hilft :)
Wüsstet ihr denn einen Weg, um die Werte der Matrix zu speichern? .... set() geht ja nun nicht.
Die derzeitige Lösung geht gut; aber andere Wege wären ja auch interessant
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@KlausP: Naja da sind ja schon Werte drin, Du weisst also schon mal wie man Werte dort hinein bekommt. Da das den Inhalt nur erweitern kann, muss man einen Weg finden den alten Inhalt zu löschen. Und wenn man sich anschaut was `Entry`-Objekte sonst noch so an Methoden haben, gibt es da auch tatsächlich was zum Löschen des Inhalts (oder sogar nur Teilen davon).

Die andere Möglichkeit wäre für jedes `Entry` ein `StringVar`-Objekt zu erzeugen und als `textvariable`-Option zu übergeben und die `StringVar`-Objekte in der Matrix zu speichern. Die haben dann auch eine `set()`-Methode.

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
KlausP
User
Beiträge: 60
Registriert: Mittwoch 8. Juli 2020, 17:00

@__blackjack__
ja, danke. Per StringVar funktioniert ja das derzeitige Programm recht gut.
Den Ansatz mit Inhalt löschen verschiebe ich erst mal.
Sag mal, in welchem Forum Abschnitt kann ich denn so allgemeine Fragen zum Code, z.B. Frage zur Variablenauswahl aus einer Liste posten?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Im allgemeinen Forum.
Antworten