Datenaustausch zwischen 2 Windows

Fragen zu Tkinter.
Antworten
sc19
User
Beiträge: 10
Registriert: Samstag 18. Dezember 2021, 15:09

Hallo,
ich bin neu auf diesem Forum und habe eine Frage die mich seit Tagen beschäftigt.
Ich habe zu Übungszwecken zwei Windows (Fenster), erstellt, das zweite Windows wird als Modul "textbetrachter" von 1. Windows (MainWindow) aufgerufen.
Soweit alles gut, das zweite Window wird über eine Tastenkombination "self.bind("<Control-s>",self.win2)" aufgerufen und das funktioniert auch wie gesagt.
Mein Problem ist, dass vor dem Aufruf folgende Variable erstellte "self.liste = frame_01.config()" und diese Variable (Werte) an das 2. Window übergeben möchte um damit dort weiterarbeiten zu können. Genau an der Stelle mache ich eben einen Programmierfehler.
Die Fehlermeldung lautet:

print(self.win.liste)
AttributeError: 'Toplevel' object has no attribute 'liste'

Hier mal das von mir gebastelte Programm:

Code: Alles auswählen

import tkinter as tk
from tkinter import ttk
import textbetrachter

class MainWindow(tk.Tk):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.title("Lektion: Frame-Widget")

        frame_01 = tk.Frame(self, bg="red", width=600, height=200)
        frame_01.grid(column=0, row=0, padx=5, pady=5, sticky="w")

        frame_01a = tk.LabelFrame(frame_01, text="Rahmen 1:", bg="gray", width=330, height=190)
        frame_01a.grid(column=0, row=0, padx=5, pady=5)

        frame_01b = tk.LabelFrame(frame_01, text="Rahmen 2:", bg="lightgray", width=330, height=190)
        frame_01b.grid(column=2, row=0, padx=(0,5), pady=5)

        self.liste  = frame_01.config()

        self.bind("<Control-s>",self.win2)

    def win2(self, event):
        self.mein_textbetrachter = textbetrachter.Textbetrachter()
        #self.mein_textbetrachter.win.liste
        self.mein_textbetrachter.win.mainloop()


root = MainWindow()
root.mainloop()
Und das ist das Modul "textbetrachter" (gespeichert als textbetrachter.py):

Code: Alles auswählen

import tkinter as tk
from tkinter import ttk

class Textbetrachter():
    def __init__(self):
        self.win = tk.Toplevel()
        self.win.title("Textbetrachter")
        self.win.resizable(False, False)

        frame_02 = tk.Frame(self.win, bg="green")
        frame_02.grid(column=0, row=0, padx=5, pady=5)

        texteditor = tk.Text(frame_02, bg="lightyellow", height=20)
        texteditor.grid(column=0, row=0, padx=5, pady=5)

        text_scroller = tk.Scrollbar(frame_02, orient="vertical", command=texteditor.yview)
        text_scroller.grid(column=1, row=0, sticky="ns")


        print(self.win.liste)

        for item in self.win.liste.config():
               texteditor.insert(tk.INSERT, (item, ":", self.win.liste[item], "\n"))
Also hier im zweiten Window möchte ich mit der Variablen "liste" weiterarbeiten, aber das funktioniert eben leider nicht. Es würde mich sehr freuen, wenn mir Jemand hierbei weiterhelfen könnte.

Liebe Grüße
sc19
Sirius3
User
Beiträge: 17782
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie auch bei einfachen Funktionen auch, wenn Du etwas in einer anderen Klasse verwenden willst, dann mußt Du es als Argument an __init__ übergeben.
Es darf nur ein `mainloop` im ganzen Programm geben, weitere Aufrufe machen keinen Sinn.
Anhängsel wie mein_ bieten keinen Mehrwert und können weg. Warum nennst Du ein Wörterbuch `liste`?

Code: Alles auswählen

import tkinter as tk

class Textbetrachter(tk.Toplevel):
    def __init__(self, liste):
        tk.Toplevel.__init__(self)
        self.liste = liste
        self.title("Textbetrachter")
        self.resizable(False, False)

        frame_02 = tk.Frame(self, bg="green")
        frame_02.grid(column=0, row=0, padx=5, pady=5)

        texteditor = tk.Text(frame_02, bg="lightyellow", height=20)
        texteditor.grid(column=0, row=0, padx=5, pady=5)

        text_scroller = tk.Scrollbar(frame_02, orient="vertical", command=texteditor.yview)
        text_scroller.grid(column=1, row=0, sticky="ns")

        print(self.liste)
        for item, value in self.liste.items():
            texteditor.insert(tk.INSERT, (item, ":", value, "\n"))

class MainWindow(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.title("Lektion: Frame-Widget")

        frame_01 = tk.Frame(self, bg="red", width=600, height=200)
        frame_01.grid(column=0, row=0, padx=5, pady=5, sticky="w")

        frame_01a = tk.LabelFrame(frame_01, text="Rahmen 1:", bg="gray", width=330, height=190)
        frame_01a.grid(column=0, row=0, padx=5, pady=5)

        frame_01b = tk.LabelFrame(frame_01, text="Rahmen 2:", bg="lightgray", width=330, height=190)
        frame_01b.grid(column=2, row=0, padx=(0,5), pady=5)

        self.liste  = frame_01.config()
        self.bind("<Control-s>", self.open_textbetrachter)

    def open_textbetrachter(self, event):
        self.textbetrachter = Textbetrachter(self.liste)

def main():
    root = MainWindow()
    root.mainloop()

if __name__ == "__main__":
    main()
sc19
User
Beiträge: 10
Registriert: Samstag 18. Dezember 2021, 15:09

Hallo,
erst einmal danke für Deine Bemühungen und für die schnelle Antwort.
Ich habe den Code , den Du freundlicherweise korrigiert hast ausprobiert und es funktioniert wie erwartet.
Du hast jedoch aus das Modul "textbetrachter" herausgenommen und hast es in ein Programmcode gepackt.
Das aber war u.a. wichtig für mich, da ich damit auch das Einbinden von selbsterstellten Modulen üben wollte.

Ich habe das nochmals anhand deines Programmcodes umgeschrieben und erhalte folgende Fehlermeldung beim Ausführen:
self.mein_textbetrachter = textbetrachter(self)
NameError: name 'textbetrachter' is not defined


Dann habe ich auch noch folgende Frage(n):
Ist "tk.Toplevel.__init__(self)" nicht das selbe wie "super.__init__(self)"?

Code: Alles auswählen

class Textbetrachter(tk.Toplevel):
    def __init__(self, liste):
        tk.Toplevel.__init__(self
Genauso auch hier:

Code: Alles auswählen

class MainWindow(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
ist das nicht das selbe?

Code: Alles auswählen

tk.Tk.__init__(self)
super(MainWindow, self).__init__()
Du schreibst:
Es darf nur ein `mainloop` im ganzen Programm geben, weitere Aufrufe machen keinen Sinn.
Anhängsel wie mein_ bieten keinen Mehrwert und können weg.
Ich vermute mal, dass Du damit die Trennung der beiden Klassen meinst, also das ich aus der Klasse Textbetrachter einen Modul erstellt habe und diesen über die Klasse MainWindow importiere, oder?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Gross- und Kleinschreibung sind wichtig in Python. Textbetrachter ist etwas anderes als textbetrachter. super() ruft *alle* potentiellen Elternklassen auf. Es ist also nicht dasselbe, kommt aber oft aufs gleiche raus.

Und was den mainloop angeht: nein, das meint Sirius3 nicht. Sondern sprichwörtlich was er gesagt hat. Dein Programm darf genau einen mainloop Aufruf enthalten. Denn ab da wandert die Kontrolle ab ins GUI-Rahmenwerk. Das geht sinnvoll nur einmal.
sc19
User
Beiträge: 10
Registriert: Samstag 18. Dezember 2021, 15:09

Hallo und Danke vorab für Dein Kommentar. Jedoch wäre etwas mehr Kontext hilfreich.
Ist "tk.Toplevel.__init__(self)" nicht das selbe wie "super.__init__(self)"?
Ich verstehe Deinen Hinweis mit der Gross- und Kleinschreibunn im Zusammenhang mit meiner obigen Frage nicht.

Du schreibst:
Dein Programm darf genau einen mainloop Aufruf enthalten.
Aber ich habe doch auch nur einen mainloop, wo in meinem Code ist ein weiterer Aufruf.
Wäre sehr hilfreich, damit ich dass auch nachvollziehen kann.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Schau dir mal deinen Code an, und deine Fehlermeldung. Dann sollte der Hinweis zur Schreibweise hoffentlich klar werden.

Und nein, du hast nicht nur einen mainloop Aufruf. Bemüh mal die Textsuchfunktion in deinem Editor.

Zur Funktion super() gibt es die offizielle Dokumentation: https://docs.python.org/3/library/functions.html
Antworten