Hallo zusammen,
ich arbeite an einem tk-Projekt, bei dem das Hauptfenster folgende Komponenten beinhaltet:
Header, Label für Tabelle, Tabelle, xscroll und yscroll Tabelle, eine Infoeingabezeile, Positionsinfo zu Tabelle und Buttons.
Das Ganze funktioniert prima.
Wenn ich bei aktivem Hauptfenster, Tabellenzeilen hinzufüge, wird nach der Aktualisierung des Hauptfenster, das richtige Fensterformat ausgegeben.
Wenn ich aber dagegen Tabellenzeilen entferne, wird das Fensterformat falsch ausgegeben, das sich so verhält dass das Fenster der Tabelle sich nicht verändert, hingegen wird die Buttonzeile entsprechend abeschnitten.
Ich verwende grid und canvas.
Würde Euch gerne den Code posten, dieser ist aber zu umfangreich.
Vielleicht aber von Euch eine Idee, an was dieses merkwürdige Verhalten liegen könnte?
Grüße Nobuddy
Falsches Fensterformat, bei Änderung der Spaltenanzahl in Tabelle
Hier ein Teilausschnitt:
Code: Alles auswählen
.......
....
..
# Aktualisierung Canvas.
self.canvas.update_idletasks()
self.x_window += max(self.x_window_list)
# Layoutsteuerung für Canvas
(self.x, self.y, self.x_table_scroll, self.y_table_scroll
) = WindowDimensions().set_up_dimensions(self)
# Konfiguration Canvas mit aktuellen Werten für:
# Scrollregion, Fensterbreite und Fensterhöhe.
self.canvas.config(
scrollregion=(self.canvas.bbox(tk.ALL)),
width=self.x_table_scroll,
height=self.y_table_scroll
)
# Aktualisierung Fenster
self.screen_update()
try:
self.viewstart
except AttributeError:
self.viewstart = True
def screen_update(self):
"""
Aktualisierung, X- und Y-Koordinaten der GUI.
"""
# Zentriere das Fenster auf dem Bildschirm
x, y, hdw, hdh = CenterWindow().center_window(self)
self.my_win.geometry('{}x{}+{}+{}'.format(x, y, hdw, hdh))
self.my_win.update()
Code: Alles auswählen
class WindowDimensions(object):
"""
Überprüfung und Berechnung der Größen x und y für canvas.
"""
def set_up_dimensions(self, master):
"""
Überprüfung und Aktualisierung der Fenster-Breite / Höhe.
"""
# Zeichenweite
sign_text_width = int(master.txt2[1])
# Fensterbreite in X
self.width_to_screen(master)
# Fensterhöhe in Y
self.heigth_to_screen(master)
# Scrollbreite in X
self.scroll_to_x(master)
# Scrollhöhe in Y
self.scroll_to_y(master)
return master.x, master.y, master.x_table_scroll, master.y_table_scroll
def width_to_screen(self, master):
"""
Ermittlung der Fensterbreite, unter Beachtung der Displaybreite.
"""
master.x = master.x_window
if master.x_window > master.screenx:
master.x = master.screenx
return
def heigth_to_screen(self, master):
"""
Ermittlung der Fensterhöhe, unter Beachtung der Displayhöhe.
"""
master.y = master.y_header + master.y_button + master.y_xscroll
data_counter = len(master.data)
diff_data_counter = 0
if data_counter > 0:
try:
master.viewstart
diff_data_counter = master.old_data_counter - data_counter
y_row = diff_data_counter * -1 * master.y_row
master.old_y += y_row
master.y = master.old_y
master.old_data_counter = data_counter
master.old_y = master.y
except AttributeError:
faktor = MultipleRowHeader(master).check_screensize(master)
master.y += round(master.y_table * 0.405 * faktor)
master.y_row = round(master.y_table / data_counter)
master.old_data_counter = data_counter
master.old_y = master.y
if master.y > master.screeny:
master.y = master.screeny
return
def scroll_to_x(self, master):
"""
Ermittlung der maximalen Scrollbreite für yscroll,
unter Beachtung der Displaybreite.
"""
master.x_table_scroll = master.x_window - master.x_yscroll
if not master.table_work:
# Leere Tabelle
master.x_table_scroll = 0
elif master.x_table_scroll > master.screenx:
# Scrollbreite größer als Displaybreite
master.x_table_scroll = (
master.window.winfo_reqheight() - master.x_yscroll)
return
def scroll_to_y(self, master):
"""
Ermittlung der maximalen Scrollhöhe für yscroll,
unter Beachtung der Displayhöhe.
"""
master.y_table_scroll = master.y_table
if (master.screeny - master.y) < master.y_table:
# Scrollhöhe größer als Displayhöhe
master.y_table_scroll = master.screeny - master.y
return
Tut mir leid. Aber das ist so trotzdem nicht nachvollziehbar. Das einzige das auffällt - WindowDimensions ist keine Klasse. Ich vermute das gleiche gilt für CenterWindow. Benutz Module statt künstlich Namensräume für eine Reihe von Funktionen zu basteln durch eine Klasse. Aber mit dem Problem an sich hat das erstmal so nichts zu tun.
Wenn du kannst, Bau ein minimales Beispiel, welches das gleiche Verhalten erzeugt. Entweder fällig dir dabei schon selbst auf, wo du ein Problem hast. Oder wir können das dann nachvollziehen & entwanzen.
Wenn du kannst, Bau ein minimales Beispiel, welches das gleiche Verhalten erzeugt. Entweder fällig dir dabei schon selbst auf, wo du ein Problem hast. Oder wir können das dann nachvollziehen & entwanzen.
@Nobuddy: was auffällt, `update_idletasks` sollte in einem Programm nicht vorkommen. `x_window` wird offensichtlich nicht benutzt, oh halt, doch, in einer ganz anderen Klasse, sehr verwirrend. AttributeError ist normalerweise ein Programmierfehler und sollte nicht missbraucht werden um verspätet Attribute zu initialisieren. Initialisiere `viewstart` in __init__.
Habe hier einen funktionierenden Code, der das Problem erkennen lässt.
Wenn Du ein paar mal auf den Button "+Data" betätigst und dann das Gleiche mit dem "-Data" Button machst, kannst Du es erkennen, was ich meine.
Wenn Du ein paar mal auf den Button "+Data" betätigst und dann das Gleiche mit dem "-Data" Button machst, kannst Du es erkennen, was ich meine.
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x
import tkinter as tk
from datetime import date, timedelta
now = date.today()
heute = now.strftime('%Y.%m.%d')
class BuildingWindow(object):
"""
Bausteine zur Fenster-Erstellung.
"""
def __init__(self, tk_status, document, label, data):
# TK
try:
self.tk_status = tk_status
except AttributeError:
self.tk_status = 'tk'
tk_check = {'tk' : tk.Tk, 'top' : tk.Toplevel}
self.my_win = tk_check[self.tk_status]()
self.my_win.protocol("WM_DELETE_WINDOW", self.close)
self.label = label
self.data = data
self.table_width2column = dict([(i, len(x) + 10)
for i, x in enumerate(data[0])])
self.color = 'yellow'
# Ermittle die Größe des Bildschirmes
self.screenx = self.my_win.winfo_screenwidth()
self.screeny = self.my_win.winfo_screenheight()
# Basis-Fenster
self.window = tk.Frame(
self.my_win,
bg=self.color
)
self.window.grid(
row=0,
column=0,
sticky=tk.NSEW
)
self.window.grid_rowconfigure(0, weight=1)
self.window.grid_columnconfigure(0, weight=1)
# Build formular
def build_formulars_view(self):
"""
Erstellung Formular-Fenster.
"""
# Startwerte für Gesamtfenster.
self.y_window = 17 # title
self.x_window = 0
self.x_window_list = list()
# Erstelle scrollbar für y und x.
self.table_work = False
self.canvas = tk.Canvas(
self.window,
)
self.canvas.grid(
row=0,
column=0,
sticky=tk.NSEW
)
self.x_yscroll = 0
self.y_xscroll = 0
if len(self.data) > 0:
self.table_work = True
yscrollbar = tk.Scrollbar(
self.window,
orient=tk.VERTICAL,
activebackground='lightsteelblue',
troughcolor='yellow'
)
yscrollbar.grid(
row=0,
column=1,
sticky=tk.NS
)
xscrollbar = tk.Scrollbar(
self.window,
orient=tk.HORIZONTAL,
activebackground='lightsteelblue',
troughcolor='yellow'
)
xscrollbar.grid(
row=1,
column=0,
sticky=tk.EW
)
# Festlegung der Scrollregion.
self.canvas.config(
scrollregion=(0, 0, 0, 0),
xscrollcommand=xscrollbar.set,
yscrollcommand=yscrollbar.set)
# Konfiguration Scrollbar in y und x.
yscrollbar.config(command=self.canvas.yview)
xscrollbar.config(command=self.canvas.xview)
self.x_yscroll = yscrollbar.winfo_reqwidth()
self.y_xscroll = xscrollbar.winfo_reqheight()
self.y_window += self.y_xscroll
# Buttons erstellen
self.y_button = 0
self.load_buttons()
self.y_window += self.y_button
# Erstelle Benennungsspalte.
self.y_label = 0
self.set_labels()
# Erstelle Tabelle mit Daten.
self.y_table = 0
self.set_entrys()
self.x_window += max(self.x_window_list)
print('###################################')
print('self.y_window', self.y_window)
print('self.x_window', self.x_window)
print('self.y_button', self.y_button)
print('self.y_label', self.y_label)
print('self.y_table', self.y_table)
print('###################################')
print(self.canvas.bbox(tk.ALL))
# Layoutsteuerung für Canvas
(self.x, self.y, self.x_table_scroll, self.y_table_scroll
) = self.set_up_dimensions()
print(self.x, self.y, self.x_table_scroll, self.y_table_scroll)
print('###################################')
# Konfiguration Canvas mit aktuellen Werten für:
# Scrollregion, Fensterbreite und Fensterhöhe.
self.canvas.config(
scrollregion=(self.canvas.bbox(tk.ALL)),
width=self.x_table_scroll,
height=self.y_table_scroll
)
# Aktualisierung Fenster
self.screen_update()
def add_data(self):
"""
Füge einen Datensatz in die Tabelle ein.
"""
new_row = self.data[-1].copy()
new_pos = str(int(new_row[0]) + 1)
position = '{}{}'.format((3 - len(new_pos)) * '0', new_pos)
new_row[0] = position
self.data.append(new_row)
self.build_formulars_view()
return
def remove_data(self):
"""
Füge einen Datensatz in die Tabelle ein.
"""
del self.data[-1]
self.build_formulars_view()
return
def screen_update(self):
"""
Aktualisierung, X- und Y-Koordinaten der GUI.
"""
# Zentriere das Fenster auf dem Bildschirm
x, y, hdw, hdh = self.center_window()
self.my_win.geometry('{}x{}+{}+{}'.format(x, y, hdw, hdh))
self.my_win.update()
def center_window(self):
"""
Zentrierung von Fenster auf Bildschirm,
wenn Fenster kleiner als Bildschirm.
"""
# Berechne die halbe Differenz zwischen Bildschirm und Fenster
half_diff_width = 0
if ((self.screenx - self.x) / 2) > 0:
half_diff_width = round((self.screenx - self.x) / 2)
half_diff_hight = 0
if ((self.screeny - self.y) / 2) > 0:
half_diff_hight = round((self.screeny - self.y) / 2)
# Werte für das Zentrieren das Fensters auf dem Bildschirm
return self.x, self.y, half_diff_width, half_diff_hight
def set_up_dimensions(self):
"""
Überprüfung und Aktualisierung der Fenster-Breite / Höhe.
"""
# Fensterbreite in X
self.width_to_screen()
# Fensterhöhe in Y
self.heigth_to_screen()
# Scrollbreite in X
self.scroll_to_x()
# Scrollhöhe in Y
self.scroll_to_y()
return self.x, self.y, self.x_table_scroll, self.y_table_scroll
def width_to_screen(self):
"""
Ermittlung der Fensterbreite, unter Beachtung der Displaybreite.
"""
self.x = self.x_window + self.x_yscroll
if self.x_window > self.screenx:
self.x = self.screenx + self.x_yscroll
return
def heigth_to_screen(self):
"""
Ermittlung der Fensterhöhe, unter Beachtung der Displayhöhe.
"""
self.y = self.y_window + self.y_table
if self.y > self.screeny:
self.y = self.screeny
return
def scroll_to_x(self):
"""
Ermittlung der maximalen Scrollbreite für yscroll,
unter Beachtung der Displaybreite.
"""
self.x_table_scroll = self.x_window + self.x_yscroll
if not self.table_work:
# Leere Tabelle
self.x_table_scroll = 0
elif self.x_table_scroll > self.screenx:
# Scrollbreite größer als Displaybreite
self.x_table_scroll = self.screenx - (2*self.x_yscroll)
return
def scroll_to_y(self):
"""
Ermittlung der maximalen Scrollhöhe für yscroll,
unter Beachtung der Displayhöhe.
"""
self.y_table_scroll = self.y_table
if self.screeny < self.y:
# Scrollhöhe größer als Displayhöhe
self.y_table_scroll = self.screeny - self.y_window
return
def load_buttons(self):
"""
Erstellung Buttons.
"""
self.buttons = {
0 : ('+ data', lambda: self.add_data()),
1 : ('- data', lambda: self.remove_data()),
3 : ('Schließen', lambda: self.close()),
}
self.button_frame = tk.Label(
self.window,
bg=self.color
)
self.button_frame.grid(
row=2,
column=0,
sticky=tk.E
)
button_width = max([len(self.buttons[i])
for i in self.buttons]) + 5
x_sum = 0
for i in sorted(self.buttons):
name, command = self.buttons[i]
self.button_widget = tk.Button(
self.button_frame,
width=button_width,
text=name.upper(),
command=command
)
self.button_widget.grid(
row=0,
column=i + 1
)
x_sum += self.button_widget.winfo_reqwidth()
self.y_button += self.button_widget.winfo_reqheight()
self.x_window_list.append(x_sum)
return
def set_labels(self):
"""
Erstellung Benennungsspalte
"""
ypos = 0
xpos = 0
for i, name in enumerate(self.label):
width = self.table_width2column[i]
label = tk.Label(
self.canvas,
width=width,
text=name.upper(),
bg='lightgreen',
bd=1,
highlightthickness=1,
anchor=tk.NW
)
label.grid(
row=0,
column=i,
)
self.canvas.create_window(
xpos,
label.winfo_reqheight(),
window=label,
anchor=tk.NW
)
xpos += label.winfo_reqwidth()
self.x_window_list.append(xpos)
self.y_label += label.winfo_reqheight()
return
def set_entrys(self):
"""
Erstellung Tabellenspalte
"""
row_start = 0
if self.y_label > 0:
#self.y_table += self.y_label
row_start = 1
self.y_table += (2*self.y_label)
for i, row in enumerate(self.data):
xpos = 0
for s, width in self.table_width2column.items():
self.var = tk.StringVar(value=row[s].upper())
self.entry = tk.Entry(
self.canvas,
text=self.var,
width=width,
bd=1,
highlightthickness=1
)
self.entry.grid(
row=i + row_start,
column=s,
)
self.canvas.create_window(
xpos,
self.y_table,
window=self.entry,
anchor=tk.NW
)
xpos += self.entry.winfo_reqwidth()
self.y_table += self.entry.winfo_reqheight()
self.x_window_list.append(xpos)
self.y_table -= self.y_label
return
def close(self):
"""
Beendigung ohne Datenübernahme.
"""
self.take_end = False
self.my_win.quit()
self.my_win.destroy()
return
def run(self, title):
self.my_win.title(title)
self.build_formulars_view()
self.my_win.mainloop()
def main(document):
tk_status = 'tk'
client = 'kunde'
label = ['position', 'artikel', 'benennung', 'hersteller',
'herstellernummer', 've', 'inhalt', 'vk', 'mwst']
data = [['001', '123456789', 'pppppppppppppppppppppppppppppppppppppppppppppppprodukt 123456789, din a4, weiß, 80g',
'hersteller', 'herstellernummer', 'stück', '1', '3.25', '0.19']]
title = '{}: {}'.format(document.upper(), client.upper())
BuildingWindow(tk_status, document, label, data).run(title)
if __name__ == '__main__':
document = 'test'
main(document)
Meine bisherige Erkenntnis, ist dass es irgendwas mit der yscrollbar zu tun hat.
Ich habe mal dies geändert:
Beim ersten Start, wird yscrollbar und xscrollbar erstellt.
Danach ändert sich das Fenster, je nach dem ich Daten hinzufügen oder lösche.
Allerdings sind die gelöschten Datenzeilen nicht wirklich gelöscht, sondern sind in der Tabelle durch scrollen in y sichtbar.
In der Datenliste, sind diese aber nicht mehr vorhanden........!?
Das ist wirklich bescheuert!
Ich habe mal dies geändert:
Code: Alles auswählen
try:
self.viewstart
except AttributeError:
self.y_window = 17 # title
self.row_counter = 0
self.x_yscroll = 0
self.y_xscroll = 0
# Erstelle scrollbar für y und x.
self.table_work = False
self.canvas = tk.Canvas(
self.window,
)
self.canvas.grid(
row=0,
column=0,
sticky=tk.NSEW
)
if len(self.data) > 0:
self.table_work = True
self.yscrollbar = tk.Scrollbar(
self.window,
orient=tk.VERTICAL,
activebackground='lightsteelblue',
troughcolor='yellow'
)
self.yscrollbar.grid(
row=self.row_counter,
column=1,
sticky=tk.NS
)
self.xscrollbar = tk.Scrollbar(
self.window,
orient=tk.HORIZONTAL,
activebackground='lightsteelblue',
troughcolor='yellow'
)
self.xscrollbar.grid(
row=self.row_counter+1,
column=0,
sticky=tk.EW
)
# Festlegung der Scrollregion.
self.canvas.config(
scrollregion=(0, 0, 0, 0),
xscrollcommand=self.xscrollbar.set,
yscrollcommand=self.yscrollbar.set)
# Konfiguration Scrollbar in y und x.
self.yscrollbar.config(command=self.canvas.yview)
self.xscrollbar.config(command=self.canvas.xview)
self.y_window += self.y_xscroll
Danach ändert sich das Fenster, je nach dem ich Daten hinzufügen oder lösche.
Allerdings sind die gelöschten Datenzeilen nicht wirklich gelöscht, sondern sind in der Tabelle durch scrollen in y sichtbar.
In der Datenliste, sind diese aber nicht mehr vorhanden........!?
Das ist wirklich bescheuert!
Die einzigste Lösung, was ich gefunden habe, ist:
Code: Alles auswählen
def add_data(self):
"""
Füge einen Datensatz in die Tabelle ein.
"""
new_row = self.data[-1].copy()
new_pos = str(int(new_row[0]) + 1)
position = '{}{}'.format((3 - len(new_pos)) * '0', new_pos)
new_row[0] = position
self.data.append(new_row)
self.my_win.quit()
self.my_win.destroy()
BuildingWindow(self.tk_status, self.document, self.label, self.data
).run(self.title)
#self.build_formulars_view()
return
def remove_data(self):
"""
Füge einen Datensatz in die Tabelle ein.
"""
del self.data[-1]
self.my_win.quit()
self.my_win.destroy()
BuildingWindow(self.tk_status, self.document, self.label, self.data
).run(self.title)
#self.build_formulars_view()
return
`einzig` ist nicht steigerbar. Ein Code wo AttributeError für irgendwas krudes missbraucht wird, ist kein guter Ansatz um ein Programm aufzubauen.
In einem Programm sollte es auch nur einen Aufruf von mainloop geben. Es sollten auch nicht ständig das Hauptfenster zerstört und neu gebaut werden.
`BuildingWindow` hört sich vom Namen her mehr nach einer Funktion als einer Klasse an. Ist das überhaupt eine Klasse?
Suchst Du einfach nur entry.forget?
In einem Programm sollte es auch nur einen Aufruf von mainloop geben. Es sollten auch nicht ständig das Hauptfenster zerstört und neu gebaut werden.
`BuildingWindow` hört sich vom Namen her mehr nach einer Funktion als einer Klasse an. Ist das überhaupt eine Klasse?
Suchst Du einfach nur entry.forget?
Puh. Ich kann das zwar nachvollziehen. Doch simples forget reicht leider nicht, weil du da so unglaublich viel rumroedelst.
Gibt es einen Grund, warum du da das Rad mit so viel Muehe neu erfindest? Fuer solche tabellarischen Ansichten gibt es den TreeView.
https://stackoverflow.com/questions/361 ... rting-data
Und du solltest auch eine andere Struktur der ganzen GUI waehlen. Das sich das Anwendungsfenster um eine Zeile vergroessert, ist ungewoehnlich und ziemlich nervend. Wenn du das machen wuerdest wie jedes andere Programm (zB Excel), dann haettest du einen *Frame* (bzw Tree-View), der groesser und kleiner wird, und an dessen Position man hinscrollt.
Du erledigst hier viel Arbeit selbst, und das auf ungewoehnliche und fehleranfaellige Art und Weise, fuer die das GUI-Toolkit schon Mittel hat.
Gibt es einen Grund, warum du da das Rad mit so viel Muehe neu erfindest? Fuer solche tabellarischen Ansichten gibt es den TreeView.
https://stackoverflow.com/questions/361 ... rting-data
Und du solltest auch eine andere Struktur der ganzen GUI waehlen. Das sich das Anwendungsfenster um eine Zeile vergroessert, ist ungewoehnlich und ziemlich nervend. Wenn du das machen wuerdest wie jedes andere Programm (zB Excel), dann haettest du einen *Frame* (bzw Tree-View), der groesser und kleiner wird, und an dessen Position man hinscrollt.
Du erledigst hier viel Arbeit selbst, und das auf ungewoehnliche und fehleranfaellige Art und Weise, fuer die das GUI-Toolkit schon Mittel hat.
Dass mein letztes Code-Beispiel, natürlich Quatsch ist ist doch völlig klar, das ist so keine Lösung.
Habe das Gefühl, dass ich mich da im Kreis drehe ...., vielleicht ist ja TreeView die Lösung, kenne mich aber damit noch nicht aus.
Wie kann ich anhand dieses Code-Beispiel TreeView umsetzen?
Habe das Gefühl, dass ich mich da im Kreis drehe ...., vielleicht ist ja TreeView die Lösung, kenne mich aber damit noch nicht aus.
Wie kann ich anhand dieses Code-Beispiel TreeView umsetzen?
Code: Alles auswählen
def set_entrys(self):
"""
Erstellung Tabellenspalte
"""
for i, row in enumerate(self.data):
xpos = 0
print(i, row)
for s, width in self.table_width2column.items():
self.var = tk.StringVar(value=row[s].upper())
self.entry = tk.Entry(
self.canvas,
text=self.var,
width=width,
bd=1,
highlightthickness=1
)
self.entry.grid(
row=i + 1,
column=s,
)
self.canvas.create_window(
xpos,
self.y_table,
window=self.entry,
anchor=tk.NW
)
xpos += self.entry.winfo_reqwidth()
self.y_table += self.entry.winfo_reqheight()
self.x_window_list.append(xpos)
self.y_table -= self.y_label
return
Es sieht nicht so aus, als ob man das 1:1 uebertragen kann, da ein TreeView auch wirklich nur ein View ist. Das waere anders bei Qt, da kann man den ItemListView auch editierbar machen.
Aber die Loesung ist einfach, und so wie in dem von mir verlinkten Beispiel dargestellt: die Entries zum bearbeiten eines Eintrags sind extra, und der Inhalt einer ausgewaehlten Zeile wird dann darin zur Anzeige und Bearbeitung gebracht.
Aber die Loesung ist einfach, und so wie in dem von mir verlinkten Beispiel dargestellt: die Entries zum bearbeiten eines Eintrags sind extra, und der Inhalt einer ausgewaehlten Zeile wird dann darin zur Anzeige und Bearbeitung gebracht.
Habe mir das verlinkte Beispiel angeschaut.
Werde mich damit intensiver beschäftigen.
"die Entries zum bearbeiten eines Eintrags sind extra, und der Inhalt einer ausgewaehlten Zeile wird dann darin zur Anzeige und Bearbeitung gebracht."
Das würde mich interessieren!
Werde mich damit intensiver beschäftigen.
"die Entries zum bearbeiten eines Eintrags sind extra, und der Inhalt einer ausgewaehlten Zeile wird dann darin zur Anzeige und Bearbeitung gebracht."
Das würde mich interessieren!
Habe das Beispiel ein wenig modifiziert:
Bei "EXIT" lasse ich mir die Values ausgeben.
Ich habe dabei bemerkt, dass bei reinen Zahlenfeldern, wenn eine "0" voran steht diese entfernt wird.
Es gibt ja z.B. Bestellartikel, bei der eine 0 voran steht > 01236689 == 1236689?
Ist das so gewollt, oder gibt es da einen Trick, dies zu unterbinden?
Auch, ist die erste Spalte sehr breit, wie kann ich da die Breite verändern?
Code: Alles auswählen
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# For Python3.x
import tkinter as tk
import tkinter.ttk as ttk
'''
Created on Mar 21, 2016
@author: Bill Begueradj
'''
class Begueradj(tk.Frame):
'''
classdocs
'''
def __init__(self, parent, label, data, width):
'''
Constructor
'''
tk.Frame.__init__(self, parent)
self.parent=parent
self.label=label
self.data=data
self.width=width
self.initialize_user_interface()
def initialize_user_interface(self):
"""Draw a user interface allowing the user to type
items and insert them into the treeview
"""
self.parent.title("Canvas Test")
self.parent.grid_rowconfigure(0,weight=1)
self.parent.grid_columnconfigure(0,weight=1)
self.parent.config(background="lavender")
self.tree = ttk.Treeview(self.parent, columns=self.label)
for i, name in enumerate(self.label):
name = name.upper()
text = '{}:'.format(name)
width = self.width[i] * 10
# Set the treeview
self.tree.heading('{}'.format(i), text=name, anchor=tk.W)
self.tree.column('{}'.format(i), width=width, stretch=tk.YES)
self.tree.grid(row=0, columnspan=i+1, sticky=tk.NSEW)
# Define the different GUI widgets
if name == 'LIEFERANT':
self.supplier_label = tk.Label(self.parent, width=width,
bg='lavender', text = text, anchor=tk.E)
self.supplier_entry = tk.Entry(self.parent)
self.supplier_label.grid(row = 1, column = 0, sticky = tk.E)
self.supplier_entry.grid(row = 1, column = 1, sticky = tk.W)
elif name == 'ARTIKEL':
self.article_label = tk.Label(self.parent, width=width,
bg='lavender', text = text, anchor=tk.E)
self.article_entry = tk.Entry(self.parent)
self.article_label.grid(row = 2, column = 0, sticky = tk.E)
self.article_entry.grid(row = 2, column = 1, sticky = tk.W)
self.submit_button = tk.Button(self.parent, text = "Insert",
command = self.insert_data)
self.submit_button.grid(row = 3, column = 1, sticky = tk.W)
self.exit_button = tk.Button(self.parent, text = "Exit",
command = self.output_data)
self.exit_button.grid(row = 3, column = 2, sticky = tk.W)
self.treeview = self.tree
# Initialize the counter
self.i = 1
def insert_data(self):
"""
Insertion method.
"""
data = self.data[(self.supplier_entry.get(), self.article_entry.get())]
pos = '#{}{}'.format((3 - len(str(self.i))) * '0', self.i)
data[0] = str(pos)
self.treeview.insert('', 'end', text='ITEM_{}'.format(self.i),
values=[x.upper() for x in data])
# Increment counter
self.i = self.i + 1
def output_data(self):
"""
Output method.
"""
self.parent.quit()
for child in self.treeview.get_children():
print(self.treeview.item(child)["values"])
def main():
root=tk.Tk()
label = ['position', 'lieferant', 'artikel', 'benennung', 'hersteller',
'herstellernummer', 've', 'inhalt', 'vk', 'mwst']
data = {
('123', '123456789') :['', '123', '123456789',
'produkt 123456789, din a4, weiß, 80g',
'hersteller', 'herstellernummer', 'stück', '1', '3.25', '0.19']
}
width = [10, 10, 20, 50, 25, 30, 10, 10, 15, 10]
d=Begueradj(root, label, data, width)
root.mainloop()
if __name__=="__main__":
main()
Ich habe dabei bemerkt, dass bei reinen Zahlenfeldern, wenn eine "0" voran steht diese entfernt wird.
Es gibt ja z.B. Bestellartikel, bei der eine 0 voran steht > 01236689 == 1236689?
Ist das so gewollt, oder gibt es da einen Trick, dies zu unterbinden?
Auch, ist die erste Spalte sehr breit, wie kann ich da die Breite verändern?
Dein Beispiel funktioniert fuer mich nicht, beim versuch, ein Datum einzutragen kracht es, weil data ein Dictionary ist, bei dem du auf einen nicht-existierenden Schuessel zugreifen willst.
Code: Alles auswählen
(foobar) beer:tmp deets$ python /tmp/test.py
2018-12-06 18:20:29.929 Python[75513:738406] ApplePersistenceIgnoreState: Existing state will not be touched. New state will be written to (null)
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
File "/tmp/test.py", line 76, in insert_data
data = self.data[(self.supplier_entry.get(), self.article_entry.get())]
KeyError: ('peter', 'wagen')
Ja, ich habe hier ein Dictionary verwendet, um mit einem Produkt-Schlüssel, eine Datenzeile zu erstellen, im Gegensatz zur reinen Eingabe.
Als Schlüssel, verwende dies: Lieferant: 123, Artikel: 123456789 (Steht auch im Code unten)
Den KeyError kann man ja abfangen, was ich jetzt in dem Beispiel nicht getan habe.
Als Schlüssel, verwende dies: Lieferant: 123, Artikel: 123456789 (Steht auch im Code unten)
Den KeyError kann man ja abfangen, was ich jetzt in dem Beispiel nicht getan habe.
@Nobuddy: Doc-Strings für Module müssen vor den Importen stehen. Der Doc-String für die Klasse und __init__ sind nicht wirklich sinnvoll, bzw. falsch. Das was in `initialize_user_interface` steht sollte direkt __init__ stehen. Das Kind sollte nicht den `parent` konfigurieren.
Begueradj ist ein Frame, Du packst aber alles in parent. Die Widgets sollten aber im Frame sein.
supplier_label und article_label werden später nicht mehr gebraucht und sollten keine Attribute sein. Die beiden if-Blöcke sind quasi identisch und können zusammengefaßt werden. submit_button und exit_button werden später nicht mehr gebraucht und sollten keine Attribute sein.
`i` ist ein sehr schlechter Attributname.
Zeile 77ff: Wenn man führende Nullen will, macht man das über format-Parameter, pos ist schon ein String, den nochmal in einen String umzuwandeln ist unsinnig.
Warum konvertierst Du alles zu Großbuchstaben?
Begueradj ist ein Frame, Du packst aber alles in parent. Die Widgets sollten aber im Frame sein.
supplier_label und article_label werden später nicht mehr gebraucht und sollten keine Attribute sein. Die beiden if-Blöcke sind quasi identisch und können zusammengefaßt werden. submit_button und exit_button werden später nicht mehr gebraucht und sollten keine Attribute sein.
`i` ist ein sehr schlechter Attributname.
Zeile 77ff: Wenn man führende Nullen will, macht man das über format-Parameter, pos ist schon ein String, den nochmal in einen String umzuwandeln ist unsinnig.
Code: Alles auswählen
data[0] = '#{:03d}'.format(self.i)
Ich verwende Großbuchstaben in den Datenzeilen, dies vereinheitlicht ich die Texte.
Ich verwende dies z.B. bei Produktdaten. Ausschlaggebend war mit unter die verschiedenen Schreibweisen von Lieferanten.
Z.B. Herstellernummer: cB-123abc, Cb-123-abc, CB123-abc
Nach meiner Formatierung, wird daraus: CB123ABC
Buchstaben und Zahlen bleiben in der Reihenfolge bestehen, der Rest wird entfernt und ist nun untereinander vergleichbar.
Ich habe das Beispiel aus dem Beispiel-Link von weiter oben verwendet und wie gepostet abgeändert.
Das was Du über "Doc-Strings für Module müssen vor den Importen stehen" geschrieben hast, verstehe ich ansatzweise, weis aber nicht wie ich dies hier umsetzen soll, vielleicht kannst Du mir anhand von Code dies verdeutlichen?
Ich verwende dies z.B. bei Produktdaten. Ausschlaggebend war mit unter die verschiedenen Schreibweisen von Lieferanten.
Z.B. Herstellernummer: cB-123abc, Cb-123-abc, CB123-abc
Nach meiner Formatierung, wird daraus: CB123ABC
Buchstaben und Zahlen bleiben in der Reihenfolge bestehen, der Rest wird entfernt und ist nun untereinander vergleichbar.
Ich habe das Beispiel aus dem Beispiel-Link von weiter oben verwendet und wie gepostet abgeändert.
Das was Du über "Doc-Strings für Module müssen vor den Importen stehen" geschrieben hast, verstehe ich ansatzweise, weis aber nicht wie ich dies hier umsetzen soll, vielleicht kannst Du mir anhand von Code dies verdeutlichen?