Eingabefeld entsperren

Fragen zu Tkinter.
Antworten
GHoeberth
User
Beiträge: 8
Registriert: Mittwoch 27. August 2014, 17:44

Hallo ...
Ich versuche gerade irgendwiein Tkinter einzusteigen... :(
Wie kann ich auf Elemente des Fensters aus dem Programm zugreifen?
Ein Beipiel:

Code: Alles auswählen

from tkinter import *

def init(top, gui):
    global w, top_level, root
    w = gui
    top_level = top
    root = top

def destroy_window():
    global top_level
    top_level.destroy()
    top_level = None

def vp_start_gui():
    global val, w, root
    root = Tk()
    top = New_Toplevel_1 (root)
    init(root, top)
    root.mainloop()

def destroy_New_Toplevel_1():
    global w
    w.destroy()
    w = None

class New_Toplevel_1:
    def __init__(self, top=None):
        top.title("New Toplevel 1")

        self.Entry1 = Entry(top)
        self.Entry1.place(relx=0.1, rely=0.17, relheight=0.17, relwidth=0.8)
        self.Entry1.configure(state=DISABLED)

        self.Button1 = Button(top)
        self.Button1.place(relx=0.25, rely=0.5, height=24, width=67)
        self.Button1.configure(command=Entsp)
        self.Button1.configure(text='''Entsperren''')

def Entsp():
    print("Entsperren")
    """
    Was muss ich hier einfügen, damit das Textfeld (Entry1)
    von state=DISABELD auf state=NORMAL gesetzt wird?
    """

if __name__ == '__main__':
    vp_start_gui()
Gibt es irgendwo eine Referenz für Tkinter, bei der man grundsätzlich nachsehen kann, wie man die Eigenschaften der GUI-Elemente abfragt und wie man sie verändert?
Wäre für einen Link dankbar. Google hat mir bisher nicht weitergeholfen. :(

herzlichen Gruß
Gerhard
Zuletzt geändert von Anonymous am Donnerstag 30. März 2017, 15:45, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@GHoeberth: Als erstes solltest Du mal ``global`` vergessen. Das schafft mehr Probleme als es löst und spätestens für GUI-Programmierung muss man sich mit objektorientierter Programmierung beschäftigen und dann gibt's auch keinerlei Rechtfertigung für ``global`` mehr.

Wie man `state` auf `DISABLED` setzt weisst Du doch schon. Auf `NORMAL` setzen funktioniert genauso. Wobei `configure()` im Programm bisher unnötig eingesetzt wird: man kann die Optionen auch gleich beim erstellen des jeweiligen Widgets als Schlüsselwortargumente angeben. Und selbst wenn man `configure()` verwendet und zwei Optionen setzen möchte, sollte man das in *einem* Aufruf machen und nicht zwei. Wenn ich nur eine Option ändern möchte, nehme ich eher die „subscription“-Syntax, also ``widget['option'] = value``.

Referenzen sind in der Python-Dokumentation zum `tkinter`-Modul verlinkt. Die von Effbot und die von New Mexico Tech sind am brauchbarsten, IMHO.

Von `place()` würde ich auch mit relativen Angaben Abstand nehmen.

Kryptische Abkürzungen (`vp_*`? `Entsp`) und nummerierte Namen sind keine gute Idee.
GHoeberth
User
Beiträge: 8
Registriert: Mittwoch 27. August 2014, 17:44

Hallo BlackJack,

also erstmal danke für die schnelle Reaktion.
Allerdings kann ich soviel noch nicht damit anfangen.
Die Datei, die ich als CODE eingefügt habe ist ein von mir auf reine Funktionalität gekürzte Version von PAGE, daher die "kryptischen Abkürzungen".
"Global" stand bei den Variablen deshalb dabei, weil PAGE das GUI in zwei Dateien ausgibt (die ich zu einer zusammengefasst habe).

Ich mach mich jetzt mal über "subscription" schlau ;-)

Danke
Gerhard
BlackJack

@GHoeberth: Das dieser Code von einem Werkzeug generiert wurde wäre eine nützliche Information gewesen. So musste man ja davon ausgehen Du hast den selbst geschrieben und wüsstest was die Sachen bedeuten weil Du sie ja geschrieben hättest.

Ich würde von dem Programm dringend abraten. Die Funktionen mit den ganzen ``global``\s und insgesamt die Struktur die das Programm ausspuckt sind extrem gruselig.
GHoeberth
User
Beiträge: 8
Registriert: Mittwoch 27. August 2014, 17:44

Okay,

also als ersten Schritt einmal einen anderen GUI-Builder...
BlackJack

@GHoeberth: Bei Tk würde ich eher sagen gar keinen GUI-Builder.

Edit: Würde ich für den Anfang auch bei jedem anderen GUI-Rahmenwerk sagen, damit man die Komponenten und Zusammenhänge kennenlernt.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:@GHoeberth: Als erstes solltest Du mal ``global`` vergessen. Das schafft mehr Probleme als es löst und spätestens für GUI-Programmierung muss man sich mit objektorientierter Programmierung beschäftigen und dann gibt's auch keinerlei Rechtfertigung für ``global`` mehr.
Also, in diesem Forum, ist man der Ansicht, alles soll Objektorientiert sein und global ist total verpönt. Aber global kann man durch Objektorientierung - das heißt Klassen, leicht ersetzen:

Code: Alles auswählen

class MyData():
    def __init__(self):
        self.var1 = "Test 1"
        self.var2 = "Test 2"

my_OOP_global = MyData()

class andere_Klasse():
    def __init__(self):

        print(my_OOP_global.var1)
        print(my_OOP_global.var2)

        my_OOP_global.var1 = "Test 3"

        print(my_OOP_global.var1)
        print(my_OOP_global.var2)

andere_Klasse()
Statt global geht also genausogut auch OOP
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Globaler Zustand ist nicht nur "in diesem Forum", sondern ganz allgemein verpönt. Weil er lose Kopplung, Wiederverwendbarkeit und eine lokale Betrachtung verhindert.

Und das durch Einführung eines mutablen Objektes Modul-globalen Zustand erzeugt hast beweist jetzt was genau? Ein dict hätte genauso gereicht, und mir fallen da auf Anhieb noch diverse andere "Tricks" ein, macht aber alles keinen Unterschied. Denn nur weil man das global Statement gespart hat, ist es IMMER noch globaler Zustand. Semantik und so. Weiß ich ja, biste auf dem Kriegsfuß mit. Aber glaubst du das ist jetzt irgendwie clever, oder belegt irgendeinen Punkt?
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@__deets__: lass Dich von Benennungen nicht in das Boxhorn jagen.

Soll man tkinter benutzen oder nicht?

ist tkinter nach "import tkinter as my_OOP_global" nun global?
soll man es also nicht benutzen?

Worum es geht ist doch: nicht eine einzige Klasse machen, in welche man alles hineistopft, sondern sinnvoll in Zusammengehöriges unterteilen. Dabei kann es aber auch sein, dass ein Modul Sinnvoll Zusamengehöriges enthält, welches man nicht weiter in verschiedene Klassen unterteilen will.

'gobal' soll man nicht nehmen, sondern eine oder mehrere Klassen sind gut. Denn man kann dann solche Variablen auch auslagern, etwa "import mydata as my_OOP_global". Solches Auslagern braucht man, wenn mehrere Module darauf zugreifen sollen.
Zuletzt geändert von Alfons Mittelmeyer am Freitag 21. April 2017, 06:51, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: Deine unqualifizierten Bemerkungen beweisen, dass Du keine Ahnung hast, was ein globaler Zustand ist, den es zu vermeiden gilt. tkinter ist ein Modul und damit global Verfügbar, es ist aber keine Variable, die man von überall her ändern kann/sollte.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@__deets__. stimmt, habe ich nicht ganz richtig gemacht, aber so ist es nun richtig, oder?

Code: Alles auswählen

class MyData():
    def __init__(self):
        self.var1 = "Test 1"
        self.var2 = "Test 2"

    def set_var1(self,value):
        self.var1 = value
 
    def set_var2(self,value):
        self.var2 = value

    def get_var1(self):
        return self.var1
 
    def get_var2(self):
        return self.var2


my_OOP_global = MyData()
 
class andere_Klasse():
    def __init__(self):
 
        print(my_OOP_global.get_var1())
        print(my_OOP_global.get_var2())
 
        my_OOP_global.set_var1("Test 3")
 
        print(my_OOP_global.get_var1())
        print(my_OOP_global.get_var2())
 
andere_Klasse()
Zuletzt geändert von Alfons Mittelmeyer am Freitag 21. April 2017, 19:33, insgesamt 1-mal geändert.
BlackJack

@Alfons Mittelmeyer: Nein natürlich nicht, und das weisst Du auch. Könntest Du das getrolle bitte einstellen. :roll:
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:@Alfons Mittelmeyer: Nein natürlich nicht, und das weisst Du auch. Könntest Du das getrolle bitte einstellen. :roll:
Ich trolle doch nicht, ich will nur von Euch wissen, wie es stimmt und warum. Stimmt es vielleicht so?

Code: Alles auswählen

class MyData():
    def __init__(self):
        self.var1 = "Test 1"
        self.var2 = "Test 2"

class andere_Klasse(MyData):
    def __init__(self):

        MyData.__init__(self)
 
        print(self.var1)
        print(self.var2)
 
        self.var1 = "Test 3"
 
        print(self.var1)
        print(self.var2)

andere_Klasse()
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

GHoeberth hat geschrieben:Hallo ...
Ich versuche gerade irgendwiein Tkinter einzusteigen... :(
Wie kann ich auf Elemente des Fensters aus dem Programm zugreifen?
indem Du zuerst einmal den überflüssigen Mist aufräumst.

def init?

Eine sinnlose Verwirrfunktion, die außerdem falsch ist, sie bekommt in vp_start_gui folgende Parameter übergeben: root, top

root ist klar
top ist aber kein Toplevel GUI Element sondern überhaupt kein GUI Element - ein sinnloses Objekt, das in __init__ lediglich Gui Elemente erstellte, sozusagen ist das nur eine Funktion gewesen.

top ist also etwas, mit dem man gar nichts anfangen kann.

Die Funktion init beginnt mit verwirrenden Parametern. Jetzt heißt die übergebene root plötzlich top und das übergebene sinnlose top wird zu gui. Das sinnlose top wird dann in eine globalen Variablen w gespeichert.

Danach wird eine globale Variable top_level belegt mit:

top_level = root
Und dann noch völlig überflüssig:
root = root

destroy_New_Toplevel_1?

destroy_New_Toplevel_1() kann nicht funktionieren, weil es kein tkinter GUI Objekt ist, sondern etwas Sinnloses bei dem kein destroy() geht.

destroy_window?

destroy_window: soll das Anwendungsfenster schließen, was dann das Programm beenden würde. Was soll aber diese Funktion, wenn kein Button dafür da ist? Einfach mit der Maus rechts oben im Fenster geklickt, schließt auch das Programm, also eine unnötige Funktion.

Und dann sollte der Rest klar geordnet und als Klasse implementiert werden:

Sinnvollerweise enthält eine Klasse die Definition eines Container Widgets (hier das Anwendungsfensters) nebst Erzeugen und Platzieren der Gui Elemente darin und die Rückruffunktionen am Besten als Methoden, weil sie dann schon selber das self des Containerwidgets bekommen, mit dem man dann die Wiggets im Containerwidget ansprechen kann.

Code: Alles auswählen

import tkinter as tk

class Application(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self.title("New Toplevel 1")

        self.Entry1 = tk.Entry(self,state=tk.DISABLED)
        self.Entry1.place(relx=0.1, rely=0.17, relheight=0.17, relwidth=0.8 )
 
        self.Button1 = tk.Button(self,text='Entsperren',command=self.entsperren)
        self.Button1.place(relx=0.25, rely=0.5)

    def entsperren(self):
        print("Entsperren")
        self.Entry1['state']=tk.NORMAL

if __name__ == '__main__':
    Application().mainloop()
Man braucht also hier keine globale Variable, es genügt: self

Das kann bei einer komplexen GUI auch anders sein. Etwa ein Blinkschalter wird an einem Ort gefertigt, eine Blinkleuchte an einem anderen Ort. Man kann dann nicht gleich imblementieren, dass dieser Blinkschalter die nämliche Blinkleuchte ansteuern soll, man kann nur die Ausgabe eines Blinksignals implementieren. Beim späteren Zusammenbau muss man dann den Schalter mit der Leuchte verkabeln, mit Hilfe eines dafür vorgesehenen Kabels in einem Kabelstrang. Man muss also doch unter Umständen zentrale Schaltstellen bzw. Schaltverbindungen haben.

Noch Fragen?
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi GHoeberth

Hier noch eine andere Variante:

Code: Alles auswählen

# -*- coding: utf-8 -*-

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
    # Tkinter for Python 3.xx
    import tkinter as tk
    
APP_WIN_XPOS = 100
APP_WIN_YPOS = 100


class Application(tk.Frame):
    def __init__(self,app_win):
        self.app_win = app_win
        
        app_win.protocol("WM_DELETE_WINDOW", self.close)
        
        tk.Frame.__init__(self, app_win)
        
        self.entry = tk.Entry(self, state=tk.DISABLED)
        self.entry.pack(padx=10, pady=10)
 
        self.button = tk.Button(self, text='Entsperren',
            command=self.entsperren)
        self.button.pack(padx=10, pady=10)
        
    def entsperren(self):
        self.entry.config(state=tk.NORMAL)
        self.entry.focus_set()

    def close(self):
        print("Mach noch etwas for dem schliessen der Anwendung")
        self.app_win.destroy()
        
def main():
    app_win=tk.Tk()
    app_win.title("New Toplevel 1")
    app_win.geometry("+{}+{}".format(APP_WIN_XPOS, APP_WIN_YPOS))
    Application(app_win).pack(expand=True)
    app_win.mainloop()
    
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
Antworten