Tkinter Label aus Schleife anzeigen Schachfiguren

Fragen zu Tkinter.
Antworten
arrakis303
User
Beiträge: 2
Registriert: Samstag 1. Mai 2021, 09:07

Hallo zusammen,
ich möchte gerne auf einem kleinen 3,5"-Display ein Schachbrett mit Figuren anzeigen.
Mit pygame klappt es, ich möchte aber gerne tkinter verwenden.
Ich habe Probleme damit, dass nur im mainloop Label aktualsiert etc. werden
After finde ich bei meinem Problem "unschön".
Es wird nur das Label aus dem letzten Durchlauf angezeigt.
Klar, die anderen Labelanweisungen "landen" ja nicht im mainloop.
Was kann ich tun? Geht da was ausser "after"?


from tkinter import *
from PIL import ImageTk, Image
import os.path

class CHESS:
PIECES = ({}, {})
for i, ptype in enumerate(["k", "q", "b", "n", "r", "p"]):
for side, ctype in enumerate(["w", "b"]):
PIECES[side][ptype] = Image.open(os.path.join("img", ctype+ptype+".png"))

def initBoardVars():
side = False
board = [
[
[1, 5, "p"], [2, 7, "p"], [3, 7, "p"], [4, 7, "p"],
[5, 7, "p"], [6, 7, "p"], [7, 7, "p"], [8, 7, "p"],
[1, 8, "r"], [2, 8, "n"], [3, 8, "b"], [4, 8, "q"],
[5, 8, "k"], [6, 8, "b"], [7, 8, "n"], [8, 8, "r"],
], [
[1, 2, "p"], [2, 2, "p"], [3, 2, "p"], [4, 2, "p"],
[5, 2, "p"], [6, 2, "p"], [7, 2, "p"], [8, 2, "p"],
[1, 1, "r"], [2, 1, "n"], [3, 1, "b"], [4, 1, "q"],
[5, 1, "k"], [6, 1, "b"], [7, 1, "n"], [8, 1, "r"],
]
]
flags = [[True for _ in range(4)], None]
return side, board, flags

# ermittelt Pixelposition x
def posx(x):
return (-4 + ((x-1) * 40))

# ermittelt Pixelposition y
def posy(y):
return (-4 + ((y-1) * 40))

fenster = Tk()
fenster.geometry('320x480')
side, board, flags = initBoardVars()

q = 0
label = { }
for side in range(2):
for x, y, ptype in board[side]:
image1 = ImageTk.PhotoImage(CHESS.PIECES[side][ptype])
label[q] = Label(image=image1)
label[q].place(x=posx(x),y=posy(y))
q = q + 1

fenster.mainloop()
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also ich finde ja eher globale Variablen und fest kodierte Layouts mit place unschön. after hingegen ist nicht eine Frage der Ästhetik, sonder der Notwendigkeit: so funktionieren GUIs nun mal. Sie sind inhärent Ereignisgetrieben, und man muss sich Ereignisse schaffen, wie even zb Timer-Events, wenn man etwas losgelöst von einer Nutzeraktion machen will. Kommst du also nicht drumrum.

Nachtrag: das die Einträge nicht gemacht werden liegt daran, dass du das PhotoImage nicht aufhebst. Einfach mal hier im Forum danach suchen, da ist in der Top 10, wenn nicht Top 5 der tkinter Probleme.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

*-Import sind schlecht, weil man dann nicht nachvollziehen kann, woher welcher Name stammt.
Die Klasse CHESS ist ja keine, weil sie nur aus einer Konstante besteht. Kann also weg.
Das `i` wird gar nicht verwendet und warum Du `side` statt "w" und "b" benutzt, ist inkonsistent.

Funktionen schreibt man wie Variablennamen komplett klein.
`side` in `initBoardVars` wird gar nicht benutzt. In board ist ein Fehler.
Was ist der Sinn von flags?
Die Funktionen posx und posy sind identisch. Statt Positionen selbst zu berechnen, benutze ein grid-Layout.

Ein Wörterbuch ist dazu da, dass man beliebige Schlüssel speichert, wenn Du aber nur einen Index hast, dann ist eine Liste besser.
Was soll denn die 1 bei image1?

Code: Alles auswählen

import tkinter as tk
from PIL import ImageTk, Image
from pathlib import Path

IMAGE_PATH = Path(__file__).parent / "img"
PIECETYPES = ["k", "q", "b", "n", "r", "p"]
COLORS = ["w", "b"]

PIECES = {
    (color, piecetype): ImageTk.PhotoImage(
        Image.open(IMAGE_PATH / f"{color}{piecetype}.png"))
    for color in COLORS
    for piecetype in PIECETYPES
}

            
def init_board():
    board = [
        [
            [1, 7, "p"], [2, 7, "p"], [3, 7, "p"], [4, 7, "p"],
            [5, 7, "p"], [6, 7, "p"], [7, 7, "p"], [8, 7, "p"],
            [1, 8, "r"], [2, 8, "n"], [3, 8, "b"], [4, 8, "q"],
            [5, 8, "k"], [6, 8, "b"], [7, 8, "n"], [8, 8, "r"],
        ], [
            [1, 2, "p"], [2, 2, "p"], [3, 2, "p"], [4, 2, "p"],
            [5, 2, "p"], [6, 2, "p"], [7, 2, "p"], [8, 2, "p"],
            [1, 1, "r"], [2, 1, "n"], [3, 1, "b"], [4, 1, "q"],
            [5, 1, "k"], [6, 1, "b"], [7, 1, "n"], [8, 1, "r"],
        ]
    ]
    flags = [[True] * 4, None]
    return board, flags


def main():
    fenster = tk.Tk()
    fenster.geometry('320x480')
    board, flags = initBoardVars()

    labels = []
    for side, pieces in zip(COLORS, board):
        for x, y, ptype in pices:
            label = Label(image=PIECES[side, ptype])
            label.grid(row=y, column=x)
            labels.append(label)
    fenster.mainloop()

if __name__ == '__main__':
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@arrakis303: Ergänzende Anmerkungen:

Der Code um das `board` zu erstellen sollte mit weniger Tipparbeit gehen, denn da sind sehr auffällige Regelmässigkeiten. Und ich würde die Koordinaten anpassen: die fangen beim Rechner in der Regel bei 0 an und nicht bei 1, so auch beim `grid()`. Wenn Du `grid()`-Koordinaten in beim Schach übliche Notation brauchst, oder die beim Schach übliche Notation in `grid()`-Koordinaten, brauchst Du sowieso Funktionen zum umrechnen und/oder einen eigenen Datentyp für Koordinatenangaben.

Wenn man mal anfängt die Regelmässigkeiten in den Daten in Code umzusetzen, sieht man hier beispielsweise, dass da immer noch zweimal fast das gleiche gemacht wird:

Code: Alles auswählen

    board = [
        [
            *((x, 6, piece_type) for x, piece_type in enumerate("p" * 8)),
            *((x, 7, piece_type) for x, piece_type in enumerate("rnbqkbnr")),
        ],
        [
            *((x, 1, piece_type) for x, piece_type in enumerate("p" * 8)),
            *((x, 0, piece_type) for x, piece_type in enumerate("rnbqkbnr")),
        ],
    ]
Bevor ich da aber weitermache: Ich finde die Aufteilung/Strukturierung hier sehr ungünstig. Warum wird da erst ausserhalb die Farbe dazu genommen? Warum sind Farbe und Figurtyp zwei unterschiedliche Werte die maximal in einem anonymen Tupel zusammengefasst werden? Beides zusammen macht doch eine Figur aus, das sollte IMHO einen eigenen Datentyp haben. Oder sogar mehr, so dass man den Figurtypen beispielsweise nicht nur einen Buchstaben ausdrückt, sondern vielleicht zumindest mal durch einen ordentlich benannten Aufzählungstypen (`enum`-Modul).

Das ganze scheint von der GUI her gedacht. Ich sehe hier keine Datenstruktur die ein Schachbrett/den Spielzustand rein von der Spiellogik her darstellen würde. Das wäre aber eigentlich die Grundlage. Das sollte man *erst* haben, und da die GUI dann *drauf setzen*.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
arrakis303
User
Beiträge: 2
Registriert: Samstag 1. Mai 2021, 09:07

Vielen Dank an Euch, ich habe manches durch Euch gelernt und verstanden, ich nehme die Anregungen auf, ich bin allerdings noch am verarbeiten Eurer Tipps und Kritik. :-)
Antworten