Hi suk
Die while-Schleife scheint mir jedoch bedenklich zu sein.
Vor allem was eventuell die Abarbeitungszeit anbelangt. Die Texthöhe habe ich leider nicht berücksichtigt. Der
'while' Hänger kann behoben werden mit:
if len(var_text) == 0: return
Übrigens wirft dieser Fall bei deinem Skript in Zeile
82 die Exception:
var_verhaeltnis = self.a_x / var_textlaenge
ZeroDivisionError: division by zero
Was macht self.entry_var.trace ? Wie bekommst Du es hin, dass ein eingegebenes Zeichen größer max_char gar nicht erst angezeigt wird?
Bei Verwendung einer Kontrollvariabel wird schon ein Event ausgelöst, wenn sie verändert wird bevor die Änderung ins Textfeld übertragen wird. Mit der Methode
'trace'kannst du somit etwas abfangen bevor es im Texteingabefeld erscheint. In unserem Fall wird der Eingabestring auf die vorgegebene Länge
MAX_ENTRY_CHAR gestutzt mit dem callback:
Code: Alles auswählen
def entry_trace_callback(self, *args):
char = self.entry_var.get()[0:MAX_ENTRY_CHAR]
self.entry_var.set(char)
Du könntest dies auch erreichen durch auslösen eines:
self.entry.bind("<KeyPress>", self.event_key_press)
Code: Alles auswählen
def event_key_press(self, event):
char = self.entry_var.get()[0:self.max_char]
self.entry_var.set(char)
Hiermit wird der Text direkt bei der Eingabe über die Tastatur gestutzt. Es passiert so schnell, dass du das Zeichen, welches die maximale Länge übersteigt im Texteingabefeld gar nicht siehst.
Der Unterschied zwischen diesen beinden Varianten ist folgender:
Fall-1: Beim setzen der Kontrollvariablen wird ein überlanger Textstring sofort gestutzt und erst dann im Texteingabefeld angezeigt.
Fall-2: Beim setzen des Texteingabefeldeigenen
'set' Methode wird aber ein überlanger Textstring mit seine voller Länge angezeigt und erst beim drücken einer Tastaturtaste gestutzt.
Noch ein Tipp. In der Methode
event_keyrelease würde ich an stelle von
keycode eher
keysym verwenden. Dann würde der Kode wie folgt lesbarer:
if (event.keycode == 9): = Escape
if (event.keycode == 36): = Return
if (event.keysym == 'Escape'):
if (event.keysym == 'Return'):
Was bezweckst du in Zeile 71 mit dieser Textrückkopplung?
self.eingabefeld.config(text = self.eingabefeld.get())
Noch weiter Tipps:
a) Versuche die PEP8 Richtlinen zu befolgen
b) Codezeilenlänge möglichts maximal auf Seitenbreite begrenzen (Seite im Hochformat).
Überlange Kodezeilen können mit einem \ gekürzt werden
c) Ein Skript möglichts ohne Überlange print-Anweisungen ins Forum platzieren
d) Im Forum möglichst die nummerierten Code Tags benutzen
Habe für die Bestimmung der Textlänge in meinem Skript den Kodeabschnitt aus deinem Skript (weil er besser ist) abgeändert übernommen. Um zu verstehen was in diesem Kodabschnitt abläuft decodierte ich in von:
Code: Alles auswählen
def event_keyrelease(self, event):
# print(event.keycode)
maxchar = 8
if (int(len(self.eingabefeld.get()) > maxchar)):
# Länge auf maximale Anzahl Zeichen zurücksetzen
print("maximale Anzahl Zeichen erreicht")
self.eingabefeld.delete(maxchar, len(self.eingabefeld.get()))
# self.eingabefeld.xview_moveto(0)
if (event.keycode == 9):
# ESC-Taste
print("Abbruch durch Escape")
self.ausgabefeld.config(text = "")
self.eingabefeld.config(text = self.eingabefeld.get())
if (event.keycode == 36):
# Enter-Taste
print("\neingegebener Text ist: %s" % (self.eingabefeld.get()))
# anpassen der Schriftgröße
var_font = tkf.Font(family=self.a_font, size=int(self.a_font_size))
var_text = self.eingabefeld.get()
# textmaße ermitteln
var_textlaenge = var_font.measure(var_text)
var_texthoehe = var_font.metrics("linespace")
# Verhältnis zum ausgabefeld ermitteln
var_verhaeltnis = self.a_x / var_textlaenge
print("Verhältnis Textfeldbreite zu Textbreite: {} / {} = {}".format(self.a_x, var_textlaenge, var_verhaeltnis))
# maximale schriftgröße ermitteln, so dass der Text in das Ausgabefeld passen würde
var_font_size_neu = int(self.a_font_size * var_verhaeltnis * 0.95)
print("Schriftgröße alt: {}, neu: {}".format(self.a_font_size, var_font_size_neu))
var_font_neu = tkf.Font(family=self.a_font, size=var_font_size_neu)
print("neu: (Textbreite, Textfeldbreite) (Texthöhe, Textfeldhöhe): ({}, {}) ({}, {})".format(var_font_neu.measure(var_text), self.a_x, var_font_neu.metrics("linespace"), self.a_y))
# wenn Ergenbis Texthöhe zu hoch, Schriftgröße nochmal verringern
if (var_font_neu.metrics("linespace") > self.a_y):
var_verhaeltnis = self.a_y / var_font_neu.metrics("linespace")
print("Verhältnis Textfeldhöhe zu Texthöhe: {} / {} = {}".format(self.a_y, var_font_neu.metrics("linespace"), var_verhaeltnis))
var_font_size_neu = int(var_font_size_neu * var_verhaeltnis)
print("Schriftgröße alt: {}, neu: {}".format(self.a_font_size, var_font_size_neu))
var_font_neu = tkf.Font(family=self.a_font, size=var_font_size_neu)
print("neu: (Textbreite, Textfeldbreite) (Texthöhe, Textfeldhöhe): ({}, {}) ({}, {})".format(var_font_neu.measure(var_text), self.a_x, var_font_neu.metrics("linespace"), self.a_y))
self.ausgabefeld.config(text = self.eingabefeld.get(), font = var_font_neu)
self.text = self.eingabefeld.get()
um in besser lesen zu können:
Code: Alles auswählen
self.text = "Name 1"
self.output_field.width = 150
self.output_field.height = 100
self.output_field_font = "Arial"
self.output_field_font_size = 15
if (event.keycode == 36):
# anpassen der Schriftgröße
var_font = tkf.Font(family=self.output_field_font, size=int(
self.output_field_font_size))
var_text = self.eingabefeld.get()
# textmaße ermitteln
var_textlaenge = var_font.measure(var_text)
var_texthoehe = var_font.metrics("linespace")
# Verhältnis zum ausgabefeld ermitteln
var_verhaeltnis = self.output_field.width / var_textlaenge
# maximale schriftgröße ermitteln, so dass der Text in das
# Ausgabefeld passen würde
var_font_size_neu = int(
self.output_field_font_size * var_verhaeltnis * 0.95)
var_font_neu = tkf.Font(
family=self.output_field_font, size=var_font_size_neu)
# wenn Ergenbis Texthöhe zu hoch, Schriftgröße nochmal verringern
if (var_font_neu.metrics("linespace") > self.output_field.height):
var_font_size_neu = int(var_font_size_neu * var_verhaeltnis)
var_font_neu = tkf.Font(family=self.output_field_font,
size=var_font_size_neu)
self.output_fieldusgabefeld.config(text = self.eingabefeld.get(),
font=var_font_neu)
self.text = self.eingabefeld.get()
Daraus entstand mein Skript wie folgt:
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tkinter as tk
import tkinter.font as tkf
APP_TITLE = "Text Fitter"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 600
APP_HEIGHT = 310
MAX_ENTRY_CHAR = 8
OUTPUT_WIN_WIDTH = 150
OUTPUT_WIN_HEIGHT = 100
class Application(tk.Canvas):
def __init__(self, app_win, **kwargs):
self.app_win = app_win
app_win.protocol("WM_DELETE_WINDOW", self.close_app)
tk.Canvas.__init__(self, app_win, **kwargs)
def build(self):
self.measure_samples("yellow world")
self.entry_frame = tk.Frame(self, bg='gray', bd=3, relief="groove",
width=300, height=150)
# Eingabefeld
self.entry_var = tk.StringVar()
self.entry_var.trace("w", self.entry_trace_callback)
self.entry = tk.Entry(self.entry_frame, relief = "sunken", bd=2,
textvariable=self.entry_var, font=("Arial", 15))
self.entry.place(x=10, y=5, width=270, height=30)
self.entry_var.set("Name1")
self.entry.select_range(0, len(self.entry.get()))
self.entry.focus()
self.entry.bind("<KeyRelease>", self.event_key_release)
# Ausgabefeld
self.output_font = tkf.Font(family="Arial", size=15)
self.output_var = tk.StringVar()
self.output = tk.Label(self.entry_frame, relief="groove", bd=2,
font=self.output_font, bg="lightgray", textvariable=self.output_var)
self.output.place(x=10, y=40, width=OUTPUT_WIN_WIDTH,
height=OUTPUT_WIN_HEIGHT)
self.create_window(20, 150, window=self.entry_frame, anchor="nw")
tk.Button(self.app_win, text="close",
command=self.app_win.destroy).pack(pady=2)
def entry_trace_callback(self, *args):
char = self.entry_var.get()[0:MAX_ENTRY_CHAR]
self.entry_var.set(char)
def event_key_release(self, event):
if event.keysym == 'Escape':
self.output_var.set("")
if event.keysym == 'Return':
#--- Anpassen der Schriftgröße ---
# Texteingabe kontrollieren
var_text = self.entry_var.get()
if len(var_text) == 0: return
# Textlänge ermitteln
var_text_length = self.output_font.measure(var_text)
# Verhältnis zum Ausgabefeld ermitteln
var_ratio = OUTPUT_WIN_WIDTH / var_text_length
# Maximale Schriftgröße ermitteln, so dass der Text in das
# Ausgabefeld passen würde
old_font_size = self.output_font.cget('size')
new_font_size = int(old_font_size * var_ratio * 0.95)
self.output_font.configure(size=new_font_size)
# Wenn Ergenbis Texthöhe zu hoch, Schriftgröße nochmal verringern
text_height = self.output_font.metrics("linespace")
if text_height > OUTPUT_WIN_HEIGHT:
var_ratio = OUTPUT_WIN_HEIGHT / text_height
new_font_size = int(new_font_size * var_ratio)
self.output_font.configure(size=new_font_size)
# Ausgabefeld aktualisieren
self.output.config(font=self.output_font)
self.output_var.set(var_text)
def measure_samples(self, text):
xpos, ypos = (20,20)
fonts = (
tkf.Font(family='Helvetica', size=20),
tkf.Font(family='Times', size=20))
for font in fonts:
font_fam, size, text_length, height = (
font.cget('family'),
font.cget('size'),
font.measure(text),
font.metrics("linespace"),
)
self.create_text(xpos, ypos, text="_{}_".format(text), font=font,
anchor="nw")
self.create_text(xpos, ypos + height + 5,
text="{} {}: BxH=({},{})".format(font_fam, size, text_length,
height), font=("Arial", 10),anchor="nw")
ypos += height + 25
def close_app(self):
# Here do something before apps shutdown
print("Good Bye!")
self.app_win.destroy()
def main():
app_win = tk.Tk()
app_win.title(APP_TITLE)
app_win.option_add("*highlightThickness", 0)
app = Application(app_win, width=APP_WIDTH, height=APP_HEIGHT,
relief="groove", bg="white", bd=2)
app.pack()
app.build()
app_win.mainloop()
if __name__ == '__main__':
main()
Ich habe außerdem noch ein Verständnisproblem zu Euren Programmstrukturen ...
Wenn ich es richtig verstanden habe, ist app_win eine Instanz von tk.Tk und sollte alle Module kennen.
self.app_win ist eine Referenz auf app_win.
Warum muss tk.Canvas über die Klassendefinition noch zusätzlich vererbt werden? Eigentlich müsste die Klasse doch Canvas über app_win bereits kennen?!
Darüber können dir unsere versierten und allzeit hilfsbereiten Forumsmitglieder
__deets__ und
Sirius3 schneller und besser Auskunft geben.
Gruss wuf