Mehrere entry-widgets gleichzeitig konfigurieren

Fragen zu Tkinter.
heiliga horsd

Hallo,

ich bräuchte mal wieder eure Hilfe, und zwar habe ich in einem Programm 11 entry-widgets, die alle gleich konfiguriert werden müssen. Gibts da ne kurze und knackige Möglichkeit (die widgets heißen bspw "entry_blabla1" etc.), alle auf einmal zu konfigurieren oder muss ich das für jedes einzeln machen? Es heißt ja immerhin auch "Don't repeat yourself" oder?

Lg HH
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Vorneweg, ich habe keine Ahnung von tkindter und von den Widgets,
Du könntest Instanzen von jedem wifget in einer Liste speichern, und dann mit einer for-Schleife über die Liste iterieren und dann jedes Widget einzeln (in der For-Schleife) konfigurieren und / oder du erstell die Widgets gleich mit einer For-Schleife dann kannst du dir den Umweg über eine Liste sparen
the more they change the more they stay the same
heiliga horsd

Hatte ich anfangs auch überlegt, jedoch dann schnell wieder verworfen, aber wenn ich das hier auch als Tipp bekomme, kann es wohl nicht so schlecht gewesen sein, ich schau mir das morgen mal an (außer es hat noch jemand eine Idee).

Danke dir!


Lg HH
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo heiliga horsd

Hier eine von vielen Varianten:

Code: Alles auswählen

# python3.1
# wuf_ref: py31_multiple_entries_02.py

import tkinter as tk

NUM_OF_ENTRIES = 11
ENTRY_BG_COLOR = 'white'

def enter_value(event):
    entry_obj = event.widget
    print(entry_obj.get())

app_win=tk.Tk()

entry_obj_dict = dict()

for entry_index in range(NUM_OF_ENTRIES):
    entry_obj = tk.Entry(app_win, bg=ENTRY_BG_COLOR)
    entry_obj.pack(padx=5, pady=2)
    entry_obj.bind('<Return>', enter_value)
    entry_key = 'entry_blabla_'+str(entry_index)
    entry_obj.insert(0, entry_key)
    entry_obj_dict[entry_key] = entry_obj

print(entry_obj_dict['entry_blabla_0'].get())

entry_obj_dict['entry_blabla_10'].config(bg='mistyrose')
entry_obj_dict['entry_blabla_10'].delete(0, 'end')
entry_obj_dict['entry_blabla_10'].insert(0, 'Meine Eingabe')

app_win.mainloop()
Gruss wuf :wink:
Take it easy Mates!
heiliga horsd

Super, funktioniert einwandfrei! Danke!!
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das ist doch nur umständlich eine Liste nachgebaut. Wenn man Namen durchnummeriert, dann macht man meistens etwas falsch und sollte gleich eine Liste benutzen.
Das Leben ist wie ein Tennisball.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo EyDu
EyDu hat geschrieben:dann macht man meistens etwas falsch
Ich respektiere deine Auffassung. Meine ist halt eine andere. Vielleicht kannst du deine Gedanken hier auch in Codeform präsentieren dann profitieren wir alle davon.

Danke. Gruss wuf :wink:
Take it easy Mates!
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Ich galub das kann ich auch

Code: Alles auswählen

# python3.1
# wuf_ref: py31_multiple_entries_02.py

import tkinter as tk

NUM_OF_ENTRIES = 11
ENTRY_BG_COLOR = 'white'

def enter_value(event):
    entry_obj = event.widget
    print(entry_obj.get())

app_win=tk.Tk()

entry_obj_list= list()

for entry_index in range(NUM_OF_ENTRIES):
    entry_obj = tk.Entry(app_win, bg=ENTRY_BG_COLOR)
    entry_obj.pack(padx=5, pady=2)
    entry_obj.bind('<Return>', enter_value)
    entry_key = 'entry_blabla_'+str(entry_index)
    entry_obj.insert(0, entry_key)
    entry_obj_list.append(entry_obj)

print(entry_obj_list[0].get())

entry_obj_list[10].config(bg='mistyrose')
entry_obj_list[10].delete(0, 'end')
entry_obj_list[10].insert(0, 'Meine Eingabe')

app_win.mainloop() 
the more they change the more they stay the same
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

EyDu hat natuerlich recht. Hier noch ein Pattern:

Code: Alles auswählen

#!/usr/bin/env python3.1

####

import tkinter as tk

####

class Entries(object):

   
  def __init__(self, names, bg='black', fg='green', hl='red'):

    self.root = tk.Tk()
    self.svars = [tk.StringVar() for _ in names]         
    self.entries = [tk.Entry(self.root, textvariable=v, width=20,
                             bg=bg, fg=fg, highlightcolor=hl)
                    for v in self.svars]

    self.labels = [tk.Label(self.root, text=name) for name in names]
    for i, (label, entry) in enumerate(zip(self.labels, self.entries)):
      entry.bind('<Return>', lambda ev, i=i: self.doit(i))
      label.grid(column=0, row=i)
      entry.grid(column=1, row=i)
                    
      
  def doit(self, i):

    content = self.svars[i].get()
    print(content)
    

  def run(self):

    self.root.mainloop()

####

if __name__ == '__main__':

  MAXI = 11
  Entries(['Text%02d' % i for i in range(MAXI)]).run() 
:wink:
yipyip
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

@Dav1d: Ist eine billige Kopie wie sie im fernen Osten praktiziert wird.

@yipyip: Danke für deinen Beitrag: Super! Ist einer der vielen möglichen Varianten.

Gruss wuf :wink:
Take it easy Mates!
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

@wuf das war Absicht!
the more they change the more they stay the same
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

@Dav1d: Das galub ich dir. Habe es auch so aufgefasst. :lol:

Gruss wuf :wink:
Take it easy Mates!
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Gut ;)

Mir gings nur darum eine 2. Möglichkeit zu zeigen und zwar mit einer Liste statt einem Dict aufgrund dem hier:
EyDu hat geschrieben:Das ist doch nur umständlich eine Liste nachgebaut. Wenn man Namen durchnummeriert, dann macht man meistens etwas falsch und sollte gleich eine Liste benutzen.
the more they change the more they stay the same
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Dav1d

Im ersten Moment sah es wirklich so aus wie eine 1:1 Kopie, da die Zeilenanzahl die genau gleiche ist. Somit haben wir die dict- und list-Variante. OK Dav1d danke noch für deine Variante.

Wünsche dir noch ein schönes WE.

Gruss wuf :wink:
Take it easy Mates!
heiliga horsd

Hallo yipyip, Danke für deinen Vorschlag! Er begeistert mich insofern, dass ich auch grade versuche, das Programm Objektorientiert zu schreiben und ich verschiedene namen verwenden kann. Jedoch verstehe ich einige Passagen aus dem Quelltext noch nicht so ganz und ich wäre über eine Erklärung daher sehr erfreut!

Code: Alles auswählen

#!/usr/bin/env python3.1

####    # Hat das irgendeinen tieferen Sinn?

import tkinter as tk

####

class Entries(object):

   
  def __init__(self, names, bg='black', fg='green', hl='red'):

    self.root = tk.Tk() # MUSS es root heißen?
    self.svars = [tk.StringVar() for _ in names]    # Hat der Unterstrich eine spezielle Bedeutung?     
    self.entries = [tk.Entry(self.root, textvariable=v, width=20,
                             bg=bg, fg=fg, highlightcolor=hl)
                    for v in self.svars]

    self.labels = [tk.Label(self.root, text=name) for name in names]
    for i, (label, entry) in enumerate(zip(self.labels, self.entries)): # Könntest du bitte die ganze Zeile ein wenig erläutern?
      entry.bind('<Return>', lambda ev, i=i: self.doit(i)) # Den lambda-Ausdruck in diesem Falle verstehe ich auch nicht so ganz :(
      label.grid(column=0, row=i)
      entry.grid(column=1, row=i)
                   
     
  def doit(self, i):

    content = self.svars[i].get()
    print(content)
   

  def run(self):

    self.root.mainloop()

####

if __name__ == '__main__':

  MAXI = 11
  Entries(['Text%02d' % i for i in range(MAXI)]).run() # Was hat >>'Text%02d' % i<< zu bedeuten?

Entschuldigung für die wahrscheinlich dummen Fragen, aber ich arbeite das erste mal tiefer mit Objektorientierter Programmierung und GUIs und befinde mich auch noch allgemein in der Lernphase.

Lg HH
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

a) Muss es root heißen? Nein, es bietet sich nur an.
b) Unterstrich: Hier nicht. Man spart sich lediglich einen Namen auszudenken, da ein solcher hier nicht gebracht wird.
c) Zum Rest: Probiere die Sachen doch mal im interaktiven Iterpreter aus und lese ein wenig in der Dokumentation. Das sind alles keine Dinge, die man nicht innerhalb von 30 Minuten selber rausfinden kann.

Sebastian
Das Leben ist wie ein Tennisball.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Zum 1. Ich denke das hat keinen tieferen Sinn ;)

2. Es muss nicht root heißen
3. Unterstriche verwendet man, wenn man die Variable (Bezeichner) nicht braucht
4. Ich hoffe der Code hilft

Code: Alles auswählen

>>> zip([1,2,3,4], [5,6,7,8])
[(1, 5), (2, 6), (3, 7), (4, 8)]
>>> for i, b in enumerate(['a', 'b', 'c']):
	print 'n-ter Buchstabe:', i
	print 'Buchstabe:', b

	
n-ter Buchstabe: 0
Buchstabe: a
n-ter Buchstabe: 1
Buchstabe: b
n-ter Buchstabe: 2
Buchstabe: c 
5. Den Lambdaausdruck kannst du mit

Code: Alles auswählen

def enter_value(event):
    entry_obj = event.widget
    print(entry_obj.get())
vergleichen

//Edit schon wieder zu langsam :evil:
the more they change the more they stay the same
heiliga horsd

Danke euch beiden!
Ich versuche nun das ganze nochmal in Worten auszudrücken, um zu sehen, ob ich es verstanden habe:

1) Ich könnte statt "root" auch "Fernseher" benutzen, wenn ich Lust darauf hätte
2) Statt einem Unterstrich (_) könnte ich auch ein anderes Zeichen verwenden (bspw. ein "w")
3) zip nimmt als Argumente Listen entgegen und gibt dann eine neue Liste aus. Die neue Liste enthält Tupel und in jedem Tupel befindet sich das n-te Objekt der einzelnen (alten) Listen.
4) enumerate zählt letzendlich bloß durch
5) Der lambda-Ausdruck sorgt bei einem bestimmten Event (hier Enter-Taste) dafür, dass der Inhalt des Entry-Feldes ausgegeben wird.

Alles richtig verstanden?
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Fast alles, in diesem Fall ruft der Lambdaausdruck nur die Funktion doit mit einem bestimmten Parameter auf, wenn man statt dem Lambdaasudruck nur seld.doit schreibt, wird self.doit() mit dem Eventparameter der von tkinter kommt aufgerufen
the more they change the more they stay the same
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo!

1) Ja, du kannst Namen beliebig wählen, so lange sie nicht mit einem reservierten Wort kollidieren (wie "for", "if", ...). Außerdem solltest du keine buil-in-Namen verdecken ("list", "dict", "set", ...)
2) Ja, jeden zulässigen Namen
3) Fast richtig: es können nicht nur Listen entgegengenommen werden, sonder alles über das iteriert werden kann. Schau dir auch noch den Sonderfall an, wenn nicht alle Listen die selbe Länge haben
4) Mal etwas anders ausgedrück: enumerate liefert zu jedem Wert noch seinen Index (den Start kann man beliebig einstellen). Auch hier kann wieder alles übergeben werden, über das auch iteriert werden kann
5) Das ist das, was am Schluß rauskommt. Ein lambda-Ausdruck ist eigentlich eine anonyme Funktion. Also eine Funktion ohne Namen. Jeden lambda-Ausdruck kannst du also auch in eine Funktion übersetzen:

Code: Alles auswählen

lambda x : x = 2*x

def function(x):
    return 2*x
@yipyip: Das geht aber noch ein wenig schöner. Mal ein Vorschlag:

Code: Alles auswählen

import Tkinter as tk

MAXI = 11

class Entries(object):
    def __init__(self, names, **keys):
        self.root = tk.Tk()

        for row, name in enumerate(names):
            var = tk.StringVar()
            entry = tk.Entry(self.root, textvariable=var, **keys)
            label = tk.Label(self.root, text=name)

            label.grid(column=0, row=row)
            entry.grid(column=1, row=row)
            entry.bind('<Return>', lambda e, v=var: self.doit(e, v.get()))
     
    def doit(self, event, var):
        print var

    def run(self):
        self.root.mainloop()

if __name__ == '__main__':
    Entries(map('Text{0:02d}'.format, range(MAXI)), width=20).run()
Das Leben ist wie ein Tennisball.
Antworten