Seite 1 von 1
Tkinter Eingabe
Verfasst: Donnerstag 11. Dezember 2014, 15:02
von asdfgh
Hallo! Mein bisheriger Code:
https://github.com/toxinman/zeug/blob/m ... Vignere.py
Diesen will ich jetzt mittels Tkinter eine Gui verleihen, stehe aber ziemlich auf dem Schlauch. Muss ich eine eigene Klasse erstellen? Oder kann ich einfach eine Funktion erstellen?
Ich habe den auf dieser Seite:
http://effbot.org/tkinterbook/entry.htm geschriebenen Code versucht zu bearbeiten, leider hat es nicht funktioniert.
Re: Tkinter Eingabe
Verfasst: Donnerstag 11. Dezember 2014, 20:47
von asdfgh
Hier meine veränderte Main-Funktion:
Code: Alles auswählen
def main():
"""Hauptfunktion"""
root = tk.Tk()
tk.Label(root, text="Vigenere").pack()
eingabe = tk.Entry(root).pack()
neu = eingabe.get()
root.mainloop()
#text = raw_input("Text: ").upper()
#code = (raw_input("Code: ").upper())*50
#tabelle = [
# list(text),
# list(code)[:len(text)],
# ["0"]*len(text)
#]
tabelle_ausgeben(vigenere_anwenden(tabelle))
Wie kann ich jetzt Sachen aus dem Eingabefeld auffangen?
Fehlermeldung:
Code: Alles auswählen
Traceback (most recent call last):
File "/Users/ich/Desktop/t.py", line 56, in <module>
main()
File "/Users/ich/Desktop/t.py", line 42, in main
neu = eingabe.get()
AttributeError: 'NoneType' object has no attribute 'get'
Re: Tkinter Eingabe
Verfasst: Donnerstag 11. Dezember 2014, 20:55
von Sirius3
@asdfgh: die pack-Methode eines Entry-Objekts liefert eben None als Rückgabewert. Es wäre auch sinnvoller, wenn Du das Entry-Objekt direkt an eine Variable binden würdest. Was erwartest Du, wenn Du direkt nach erstellen den Wert Deines Eingabefeldes abfragst? GUIs verarbeiten Ereignisse. mit einem linearen Programmablauf kommst Du da nicht weiter.
Re: Tkinter Eingabe
Verfasst: Donnerstag 11. Dezember 2014, 21:11
von asdfgh
@ Sirius3 Also sollte ich das ganze in eine Klasse packen?
P.S.: Hast du gute Website-Empfehlungen zu Tkinter?
Re: Tkinter Eingabe
Verfasst: Donnerstag 11. Dezember 2014, 21:44
von BlackJack
@asdfgh: Man kann das auch funktional lösen, aber objektorientiert wäre in Python ”natürlicher”. Der Punkt ist wie von Sirius3 schon geschrieben wurde, dass GUI-Programmierung nicht linear funktioniert, also nicht *Du* die Reihenfolge des Programmablaufs insgesamt bestimmst, sondern nur in kleinen Abschnitten die auf Ereignisse aus der GUI reagieren. Du musst also den Code der das Eingabefeld ausliest, den Text verschlüsselt, und das Ergebnis irgendwie anzeigt an ein Ereignis binden das von der GUI kommt und vom Benutzer ausgelöst wird. Zum Beispiel die Enter-Taste die im Texteingabefeld betätigt wird, eine zusätzliche Schaltfläche, oder zum Beispiel ein `Tkinter.StringVar`-Objekt an das `Entry`-Objekt beim erstellen als `textvariable` übergeben. Bei `StringVar` kann man dann eine Funktion binden die bei jeder Veränderung des Inhalts aufgerufen wird.
Re: Tkinter Eingabe
Verfasst: Freitag 12. Dezember 2014, 20:32
von asdfgh
Ok, ich habe mal ein paar Versuche gemacht:
Code: Alles auswählen
# -*- coding: UTF8
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
ALPHABET = map(chr, [x for x in range(65,91)])
class Vigenere(object):
def __init__(self):
self.root = tk.Tk()
self.ausgabe = tk.Label(self.root)
self.text = tk.Entry(self.root)
self.codewort = tk.Entry(self.root)
self.button = tk.Button(self.root, text="Codieren", command=self.codieren)
self.text.pack()
self.codewort.pack()
self.button.pack()
self.ausgabe.pack()
self.root.mainloop()
def codieren(self):
text = self.text.get()
codewort = self.codewort.get()
tabelle = [
list(text),
list(codewort)[:len(text)],
["0"]*len(text)
]
tabelle_ausgeben(vigenere_anwenden(tabelle))
def verschieben(buchstabe, verschiebezahl):
"""Buchstaben der Ausgangsnachricht im Alphabet
um Verschiebezahl verschieben"""
neu = chr(ord(buchstabe) + verschiebezahl)
if neu not in ALPHABET:
return chr(ord(neu) - 26)
else:
return neu
def verschiebezahl_ermitteln(buchstabe):
"""Verschiebezahl eines Buchstaben aus dem
Code-Wort ermitteln"""
return ord(buchstabe) - 65
def vigenere_anwenden(tabelle):
"""Vignere-Verschluesselung anwenden"""
for idx, buchstabe in enumerate(tabelle[0]):
tabelle[2][idx] = verschieben(
buchstabe, verschiebezahl_ermitteln(tabelle[1][idx])
)
return tabelle
def tabelle_ausgeben(tabelle):
"""Tabelle bestehend aus Ausgangstext, CodeWort
und Verschluesselung formatiert ausgeben"""
for reihe in tabelle:
print "".join(reihe)
Sollte ich das Programm an sich und die GUI in zwei verschiedene Klassen packen?
Re: Tkinter Eingabe
Verfasst: Samstag 13. Dezember 2014, 13:27
von asdfgh
Also ich habe mir gerade das MVC-Modell angeschaut, aber dass schien mir ein wenig überdimensioniert für diese Aufgabe. Gibt es noch andere Möglichkeiten, dass Programm und die GUI sinnvoll zu trennen?
Re: Tkinter Eingabe
Verfasst: Sonntag 14. Dezember 2014, 10:04
von asdfgh
Könnte mir jemand eine grobe Struktur vorgeben, wie man sowas macht?
Re: Tkinter Eingabe
Verfasst: Sonntag 14. Dezember 2014, 13:36
von asdfgh
Oder mir eine Website empfehlen?
Re: Tkinter Eingabe
Verfasst: Sonntag 14. Dezember 2014, 13:57
von Sirius3
@asdfgh: das einzige was Du beachten solltest ist "Separation of Concerns", dass also Deine Berechnungsfunktionen nichts über Deine GUI und umgekehrt, die GUI nichts über den Inneren Aufbau Deiner Berechnung wissen dürfen.
PS: ein __init__-ialisierter sollte nur Initialisieren und nicht auch noch die ganze Arbeit machen (mainloop). Die vigenere_anwenden-Funktion ist seltsam, da sie die Parameter als Tabelle will, und man sogar noch die Ergebnisliste vorinitialisieren muß. Alles Aufgaben, die die eigentliche Funktion vor dem Anwender verstecken sollte. In diesem Zusammenhang, es ist unüblich in Python mit einem Index explizit auf Tabellen zuzugreifen, wenn man auch über die Elemente iterieren kann. Also:
Code: Alles auswählen
def vigenere_anwenden(text, code):
"""Vignere-Verschluesselung anwenden"""
return [ verschieben(char_text, verschiebezahl_ermitteln(char_code))
for char_text, char_code in zip(text, code)]
Und tabelle_ausgeben wäre ja eine Funktion, in der die GUI beteiligt ist.
Re: Tkinter Eingabe
Verfasst: Sonntag 14. Dezember 2014, 14:26
von asdfgh
Danke für deine Hilfe

Werde versuchen, es umzusetzen.
Re: Tkinter Eingabe
Verfasst: Sonntag 14. Dezember 2014, 14:45
von asdfgh
Habe das ganze jetzt so gemacht:
Code: Alles auswählen
# -*- coding: UTF8
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
ALPHABET = map(chr, [x for x in range(65, 91)])
class Vigenere(object):
def __init__(self):
self.root = tk.Tk()
self.text = tk.Entry(self.root)
self.code = tk.Entry(self.root)
self.button = tk.Button(
self.root, text="Codieren",
command=self.vigenere_anwenden
)
self.ausgabe = tk.Label(self.root)
self.text.pack()
self.code.pack()
self.button.pack()
self.ausgabe.pack()
def vigenere_anwenden(self):
text = self.text.get()
code = self.code.get()
self.ausgabe.config(text="".join([
self.verschieben(char_text, self.verschiebezahl_ermitteln(char_code))
for char_text, char_code in zip(text, code)
]))
def verschieben(self, buchstabe, verschiebezahl):
neu = chr(ord(buchstabe) + verschiebezahl)
if neu not in ALPHABET:
return chr(ord(neu) - 26)
else:
return neu
def verschiebezahl_ermitteln(self, buchstabe):
return ord(buchstabe) - 65
def run(self):
self.root.mainloop()
if __name__ == '__main__':
vigenere = Vigenere()
vigenere.run()
Leider stürzt das Programm ab. Außerdem weiß ich nicht, wie ich sowas
Code: Alles auswählen
def vigenere_anwenden(self):
text = self.text.get()
code = self.code.get()
self.ausgabe.config...
ändern soll, weil hier ja die GUI in den Berechnungen auftritt. Leider wird das in meinen Büchern auch so gemacht, deshalb kenne ich keine andere Möglichkeit.
Re: Tkinter Eingabe
Verfasst: Sonntag 14. Dezember 2014, 15:09
von EyDu
asdfgh hat geschrieben:Code: Alles auswählen
def vigenere_anwenden(self):
text = self.text.get()
code = self.code.get()
self.ausgabe.config...
ändern soll, weil hier ja die GUI in den Berechnungen auftritt. Leider wird das in meinen Büchern auch so gemacht, deshalb kenne ich keine andere Möglichkeit.
Du schreibst einfach zwei Funktionen dafür. Die erste wird beim Klick auf den Button aufgerufen, liest die Werte der Widgets aus und wandelt ggf. noch die Eingaben in Integer, Floats oder welcher Datentyp auch immer gebraucht wird. Dann ruft die Funktion die reine Berechnungsfunktion auf, nimmt dessen Ergebnis entgegen und zeigt das dann ggf. an.
Re: Tkinter Eingabe
Verfasst: Sonntag 14. Dezember 2014, 15:56
von asdfgh
Danke für den Tipp

. Jetzt sieht das ganze so aus:
Code: Alles auswählen
def __init__(self):
self.root = tk.Tk()
self.text = tk.Entry(self.root)
self.code = tk.Entry(self.root)
self.button = tk.Button(
self.root, text="Codieren",
command=self.button_clicked
)
self.ausgabe = tk.Label(self.root, text="Text und Codewort eingeben")
self.text.pack()
self.code.pack()
self.button.pack()
self.ausgabe.pack()
def button_clicked(self):
text = self.text.get()
code = self.code.get()
ergebnis = "".join(self.vigenere_anwenden(text, code))
self.ausgabe.config(text=ergebnis)
def vigenere_anwenden(self, text, code):
return [
self.verschieben(
char_text, self.verschiebezahl_ermitteln(char_code))
for char_text, char_code in zip(text, code)
]
...
def run(self):
self.root.mainloop()
Leider hängt es sich immer noch bei Betätigen des Buttons auf. Wie finde ich die Ursache davon?
Re: Tkinter Eingabe
Verfasst: Sonntag 14. Dezember 2014, 20:33
von Sirius3
@asdfgh: das ist ja jetzt das genaue Gegenteil von Trennen der Verantwortlichkeiten. Was haben vigenere_anwenden, verschieben und verschiebezahl_ermitteln mit der GUI-Klasse zu tun?
Re: Tkinter Eingabe
Verfasst: Montag 15. Dezember 2014, 00:36
von EyDu
asdfgh hat geschrieben:Leider hängt es sich immer noch bei Betätigen des Buttons auf. Wie finde ich die Ursache davon?
Fehlermeldung?
Re: Tkinter Eingabe
Verfasst: Montag 15. Dezember 2014, 12:50
von Kalli87
Wenn sich der PC aufhängt, was ich bei dieser Aussage vermute, hat er eine
Endlosschleife die den Speicher zu spamt. Da wird es zu keiner Fehlermeldung
kommen

Re: Tkinter Eingabe
Verfasst: Montag 15. Dezember 2014, 12:59
von BlackJack
In dem Fall fehlt allerdings der Quelltext in dem das Problem ist, denn im bisher gezeigten sehe ich keine solche Schleife.
Re: Tkinter Eingabe
Verfasst: Mittwoch 17. Dezember 2014, 18:44
von asdfgh
Hier der aktuelle Quelltext:
Code: Alles auswählen
# -*- coding: UTF8 -*-
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
ALPHABET = map(chr, [x for x in range(65, 91)])
class Vigenere(object):
def __init__(self):
self.root = tk.Tk()
self.text = tk.Entry(self.root)
self.code = tk.Entry(self.root)
self.button = tk.Button(
self.root, text="Codieren", command=self.button_clicked)
self.ausgabe = tk.Label(self.root, text="Text und Codewort eingeben")
self.text.pack()
self.code.pack()
self.button.pack()
self.ausgabe.pack()
def button_clicked(self):
text = self.text.get()
code = self.code.get()
ergebnis = "".join(self.vigenere_anwenden(text, code))
self.ausgabe.config(text=ergebnis)
def vigenere_anwenden(self, text, code):
return [
self.verschieben(
char_text, self.verschiebezahl_ermitteln(char_code))
for char_text, char_code in zip(text, code)
]
def verschieben(self, buchstabe, verschiebezahl):
neu = chr(ord(buchstabe) + verschiebezahl)
if neu not in ALPHABET:
return chr(ord(neu) - 26)
else:
return neu
def verschiebezahl_ermitteln(self, buchstabe):
return ord(buchstabe) - 65
def run(self):
self.root.mainloop()
if __name__ == '__main__':
vigenere = Vigenere()
vigenere.run()
Zum Trennen von GUI und Logik muss ich die Logik-Funktionen außerhalb der Klasse schreiben und in der Klasse aufrufen?
Re: Tkinter Eingabe
Verfasst: Mittwoch 17. Dezember 2014, 19:15
von BlackJack
@asdfgh: Ich sehe da keine Endlosschleife. Also weder im Code, noch hängt da irgendwas wenn ich das Programm ausführe.
Die Verschlüsselung ist allerdings fehlerhaft, da verschwindet Text wenn man Text/Code eingibt der nicht irgendwelchen Bedingungen entspricht.