Checkbutton select mit Liste

Fragen zu Tkinter.
Antworten
Philipp68
User
Beiträge: 34
Registriert: Freitag 23. Juni 2017, 10:14

Hallo,
ich habe folgendes vorliegen. Zwei verschiedene Ringe, die aus jeweils 24 Checkbuttons erstellt wurden. Bei Ring 1 werden checkbuttons nach belieben ausgewählt und manche ausgelassen. Die Auswahl wird in einer .txt-Datei als Liste mit "0", für nicht ausgewählt und mit "1", für ausgewählt, abgespeichert.

In einem anderen Fenster ist ein Ring 2, gleiche Anordnung nur kleiner, dargestellt. Über eine Listbox wird die .txt-Datei angezeigt und gelesen. Ring 2 soll nun als Information der zuvor erstellten Auswahl die gleichen checkbuttons für "0" auf deselect() und für "1" auf select() setzen, also nur eine Kennzeichnung mit Haken.

Ring 2 (24 Elemente) wurde so erstellt:

Code: Alles auswählen

for i in np.arange(0,math.pi*2,math.pi/12):
    x = math.cos(i)*r
    y = math.sin(i)*r
    mycolor = '#324E5C'
    zzz = Checkbutton(f2,bg=mycolor,height=0, width=0)
    zzz.place(x=360+x, y=356+y)
Die Liste (Auswahl von Ring 1) sieht so aus [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Ich möchte nun mit einer Schleife die Liste durchgehen und wenn zB index 5 aus Liste = 1, soll er von zzz index 5, den Checkbutton mit gleichem index als select setzen.

Hiermit lese ich die Zeile, in der die Liste ist. Im Ring 2 setzt er nur einen Checkbutton als select, nur weiß ich nicht, wie ich es hinbekomme, dass mehrere auf select gesetzt werden.

Code: Alles auswählen

fobj = open("data.txt").readlines()[6]
for line in fobj:
    print(line)
    if "1" in fobj:
        zzz.select() #zzz[index von Liste mit 1].select() oder zzz[index von Liste mit 0].deselect()
Ich habe auch nochmal ein Bild hinzugeügt, auf dem man sieht, was ich vorhabe.
Vielen Dank für eure Hilfe!

Bild
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Philipp68: da ist so einiges schief. Dateien, die man öffnet, sollte man auch wieder schließen (am besten mit with-Statement). fobj ist kein File-Objekt, wie der Name vermuten läßt, sondern ein String. Die for-Schleife geht dann über die Zeichen der Zeile, Du speicherst aber anscheinend die Zahlen als Python-Liste (das sollte am besten JSON sein und mit Hilfe des entsprechenden Modul geschrieben und gelesen werden). `line` verwendest Du aber gar nicht, sondern nur `fobj` das zzz selektiert, wenn irgendwo eine 1 in dieser Zeile vorkommt. Dann steht in `zzz` nur die letzte Checkbox, Du mußt Dir also alle Checkboxen beim Erzeugen merken (am besten in einer Liste).
Philipp68
User
Beiträge: 34
Registriert: Freitag 23. Juni 2017, 10:14

Alles klar. Werde mich heute noch belesen und wieder melden!
Danke bis hier hin :)
Philipp68
User
Beiträge: 34
Registriert: Freitag 23. Juni 2017, 10:14

Hallo Sirius,
"fobj.close()" habe ich vergessen zu übernehmen. Ich habe es nun auch verstanden, dass ich eine Liste der Checkbuttons erstellen muss, um auf einzelne zuzugreifen. Logisch ist auch, dass er den letzten erstellten Checkbutton auf "select" setzt. Ich habe mich daran versucht eine Liste für die Checkbuttons zu erstellen. Ich habe in vielen Beispielen gesehen, dass integers verwendet werden. Ich habe es an meinem Fall probiert und bekomme leider einen Fehler "TypeError: list indices must be integers or slices, not float". Das liegt wohl an "for i in np.arange(0, math.pi * 2, math.pi / 12):".
Ein anderer Versuch wäre dieser:

Code: Alles auswählen

    for i in np.arange(0, math.pi * 2, math.pi / 12):
        listcheck = []
        r = 100
        x = math.cos(i) * r
        y = math.sin(i) * r
        mycolor = '#324E5C'
        zzz = Checkbutton(f2, bg=mycolor, height=0, width=0)
        zzz.place(x=360 + x, y=356 + y)
        listcheck.append(zzz)
    
    print(listcheck)
Die Ausgabe ist leider nur ein Checkbutton Nr.24. Müsste nun nicht "listcheck" mit jedem Durchlauf der Schleife mit dem nächsten Checkbutton erweitert werden?
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Philipp68: dann sind die vielen Beispiele alle schlecht. In Python werden selten Indexzugriffe benutzt. Schau mal, wo Du überall `listcheck` setzt.
Philipp68
User
Beiträge: 34
Registriert: Freitag 23. Juni 2017, 10:14

Guten Morgen Sirius,
der Fehler liegt an der Stelle von "listcheck = []", richtig? Ich habe den leeren Array vor die for-Schleife gesetzt. Nun wird durch print
"[<tkinter.Checkbutton object .!frame2.!checkbutton>, <tkinter.Checkbutton object .!frame2.!checkbutton2>, <tkinter.Checkbutton object .!frame2.!checkbutton3>, <tkinter.Checkbutton object .!frame2.!checkbutton4>,......, <tkinter.Checkbutton object .!frame2.!checkbutton24>]" in der Console ausgegeben.
Das Array hat nun die gleiche Form, wie das meiner Liste mit [0,1,1,1,0......,0].
Philipp68
User
Beiträge: 34
Registriert: Freitag 23. Juni 2017, 10:14

Neues Problem:
Die oben beschriebene Ausgabe kommt bei der Auswahl einer txt-Datei. Bei auswählen einer nächsten txt.-Datei sieht die Ausgabe in der Console so aus "[<tkinter.Checkbutton object .!frame2.!checkbutton25>, <tkinter.Checkbutton object .!frame2.!checkbutton26>, <tkinter.Checkbutton object .!frame2.!checkbutton27>,....,<tkinter.Checkbutton object .!frame2.!checkbutton48>]"
Aber diese Buttons habe ich gar nicht. Da muss irgendwo noch ein Fehler sein.
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Namen die du da siehst sind interne Namen von tkinter. Der nummeriert halt irgendwas durch. Was hat das mit dir zu tun? Du musst doch nur mit dem entsprechenden Index auf die entsprechende Checkbox zugreifen.
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Weil ich gerade mal Lust hatte zu zeigen, wie man sowas eigentlich macht habe ich mal dieses kleine Testprogramm geschrieben.

Tkinter ist zwar nicht das gelbe vom Ei, aber etwas das es gut macht und das man verwenden sollte sind die Var-Klassen. Damit kann man sauber Daten von GUI trennen, und sich reziprok von Aenderungen benachrichtigen lassen. Und bei Checkboxen insbesondere ist das auch das vorgeschlagene Vorgehen.

Code: Alles auswählen

import math
import tkinter as tk
import json
import tempfile
from functools import partial
from itertools import cycle


TEST_DATA = [
    [
        1, 1, 0, 1,
        0, 1, 0, 1,
        1, 1, 0, 1,
        0, 1, 0, 1,
        1, 1, 0, 1,
        0, 1, 0, 1
    ],
    [
        1, 0, 1, 1,
        0, 1, 0, 1,
        1, 0, 1, 1,
        0, 1, 0, 1,
        0, 0, 1, 1,
        0, 1, 1, 0
    ],
]


class CircleView(object):

    def __init__(self, parent, model, width=400, height=400):
        frame = tk.Frame(parent)
        frame.config(width=width, height=height)
        frame.pack()

        for i, var in enumerate(model):
            step = math.pi * 2 / len(model) * i
            x = math.cos(step) * (width / 2) * .8 + width / 2
            y = math.sin(step) * (width / 2) * .8 + width / 2
            cb = tk.Checkbutton(frame, var=var)
            cb.place(x=x, y=y)


class CircleModel(object):

    def __init__(self):
        self._vars = [tk.IntVar() for _ in range(24)]


    def __iter__(self):
        return iter(self._vars)


    def __len__(self):
        return len(self._vars)


    def load(self, path):
        with open(path) as inf:
            data = json.load(inf)
            for var, value in zip(self._vars, data):
                var.set(value)


    def save(self, path):
        with open(path, "w") as outf:
            json.dump([var.get() for var in self._vars], outf)


def write_test_data():
    res = []
    for data in TEST_DATA:
        f = tempfile.mktemp()
        with open(f, "w") as outf:
            json.dump(data, outf)
        res.append(f)
    return res


def swap_test_data(filenames, model, root):
    model.load(next(filenames))

    f = partial(swap_test_data, filenames, model, root)
    root.after(2000, lambda: f())


def main():
    test_data_files = write_test_data()
    root = tk.Tk()
    model = CircleModel()
    v = CircleView(root, model)

    f = partial(swap_test_data, cycle(test_data_files), model, root)
    root.after(2000, lambda: f())

    b = tk.Button(root, text="Save", command=lambda: model.save("/tmp/test.json"))
    b.pack()
    tk.mainloop()

if __name__ == '__main__':
    main()
Philipp68
User
Beiträge: 34
Registriert: Freitag 23. Juni 2017, 10:14

Hallo deets,
vielen Dank für deine Mühe! Da ich leider bis Montag fertig sein muss, habe ich jetzt nicht die Zeit, an diesem Problem weiterzumachen, werde mich aber zu einem anderen Zeitpunkt mit deinem Beispiel und meinem Vorhaben beschäftigen, weil ich das ganz gerne hinbekommen möchte. Ich habe mich nun für eine Alternative entschieden, die die eigentliche Idee auch umsetzt. LED-Config wird rot, wenn keine einzige LED vorher ausgewählt wurde, enthält die Liste min. eine "1", wird sie grün. Die Zahlen im Ring werden noch vervollständigt, aber wie die Anordnung sein soll, wird noch mit dem Prof besprochen, da der Ring auf der Platine mehrfach gespiegelt wird, bevor das Licht ins Auge geht.
Es sieht nun so aus :)
Bild
Antworten