Hallo,
ich möchte eine einfache GUI für mein Dateiumbenennungsprogramm stricken, das die vorgegebenen Quelldateinamen (nicht änderbar) und die änderbaren Umbenennungsvorschläge in 2 Spalten nebeneinander anzeigt.
Da es sich um ca. 80-100 Einträge handelt, wollte ich mir hierfür eine GUI mit TkTable bauen, damit man rasch mit den Cursortasten zwischen den Vorschlägen navigieren kann.
Weitere Anforderungen:
- Die Tabelle sollte in einem Fenster mit Scrollleiste integriert sein, 30 Einträge sollten gleichzeitig im Fenster erscheinen, darunter OK/Abbrechen-Buttons (permanent sichtbar)
- Beim Klicken auf Ok wird eine Plausibilitätsprüfung für die Dateinamen gestartet (schon vorhanden).
Problem: es gibt kaum Codesamples für Tktable/Python, selbst der Wrapper scheint buggy zu sein. Wenn es also brauchbare Codesnippets gibt, die in diese Richtung gehen... nur her damit!
Natürlich bin ich auch für Alternativvorschläge dankbar.
GUI mit TkTable
So auf Anhieb finde ich nur: http://tkinter.unpythonic.net/wiki/TkTable
Aber vertrauend erweckend sieht das nicht aus.
Ich habe mal für meine Kontoverwaltung sowas hier zusammengebastelt:
http://www.python-forum.de/post-32776.html#32776
Aber vertrauend erweckend sieht das nicht aus.
Ich habe mal für meine Kontoverwaltung sowas hier zusammengebastelt:
http://www.python-forum.de/post-32776.html#32776
-
- User
- Beiträge: 29
- Registriert: Donnerstag 7. September 2006, 21:30
aber wie könnte ich dein Beispiel am elegantesten so abändern, dass die Umbennennungsvorschläge in Textfeldern ausgegeben werden (= vom Benutzer editierbar sind)?
Danke,
Franz
Danke,
Franz
Da die Multilistbox aus mehreren Listboxen zusammengabaut wird, sollte es möglich sein ein Tasttaturkürzel oder eine Maustaste an einzelne Felder zu binden. Um dann ein Dialogfenster aufzurufen.
Aber um ehrlich zu sein, mal eben könnte ich das nicht.
Aber um ehrlich zu sein, mal eben könnte ich das nicht.
- Michael Schneider
- User
- Beiträge: 569
- Registriert: Samstag 8. April 2006, 12:31
- Wohnort: Brandenburg
Hallo Franz,fbuchinger hat geschrieben:aber wie könnte ich dein Beispiel am elegantesten so abändern, dass die Umbennennungsvorschläge in Textfeldern ausgegeben werden (= vom Benutzer editierbar sind)?
ich finde die MultiListbox von M.Snede einfach klasse! Als Hommage habe ich mal die Funktionalität zum Ändern der Spaltenwerte per Rechtsklick (auf einen MARKIERTEN!! Eintrag) eingefügt, hier die EditableMultiListbox:
Code: Alles auswählen
#http://tkinter.unpythonic.net/wiki/SortableTable
#based on http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52266 by Brent Burley's excellent widget,
#then copy over the following methods to make it sortable by clicking on column header
from Tkinter import *
class EditableMultiListbox(Frame):
def __init__(self, master, lists):
Frame.__init__(self, master)
self.lists = []
self.colmapping={}
self.origData = None
m = PanedWindow(self)#(orient=VERTICAL)
m.config(handlesize=0, sashrelief=SUNKEN, borderwidth=0)
m.pack(side=LEFT,fill=BOTH, expand=1)
for l,w in lists:
frame = Frame(m)
frame.config(bg="red", padx=5, pady=5, relief=RAISED, bd=4)
frame.pack(side=LEFT, expand=YES, fill=BOTH)
b = Button(frame, text=l, borderwidth=1, relief=RAISED)
b.pack(fill=X)
b.bind('<Button-1>', self._sort)
self.colmapping[b]=(len(self.lists),1)
lb = Listbox(frame, width=w, borderwidth=4, selectborderwidth=0,
relief=RAISED, exportselection=FALSE)
lb.pack(expand=YES, fill=BOTH)
self.lists.append(lb)
m.add(frame)
lb.bind('<B1-Motion>', lambda e, s=self: s._select(e.y))
lb.bind('<Button-1>', lambda e, s=self: s._select(e.y))
lb.bind('<Leave>', lambda e: 'break')
lb.bind('<B2-Motion>', lambda e, s=self: s._b2motion(e.x, e.y))
lb.bind('<Button-3>', self._modify)
lb.bind('<Button-2>', lambda e, s=self: s._button2(e.x, e.y))
lb.bind('<Button-4>', lambda e, s=self: s._scroll(SCROLL, -1, UNITS))
lb.bind('<Button-5>', lambda e, s=self: s._scroll(SCROLL, 1, UNITS))
frame = Frame(self)
frame.config(bg="green", padx=5, pady=5, relief=RAISED, bd=4)
frame.pack(side=LEFT, fill=Y)
b = Button(frame, text="", borderwidth=1, relief=RAISED).pack(fill=X)
sb = Scrollbar(frame, orient=VERTICAL, command=self._scroll)
sb.pack(expand=YES, fill=Y)
self.lists[0]['yscrollcommand']=sb.set
sb.bind('<Button-4>', lambda e, s=self: s._scroll(SCROLL, -1, UNITS))
sb.bind('<Button-5>', lambda e, s=self: s._scroll(SCROLL, 1, UNITS))
def _modify(self, e):
import tkSimpleDialog
# get current selection line, abort if no line is selected
i = e.widget.curselection()
if not i: return
# ask for new String
Eingabe = tkSimpleDialog.askstring("Neuer Wert", "Eingabe:")
# insert new String and update selection
e.widget.delete(i)
e.widget.insert(i, Eingabe)
self.selection_set(i)
def _sort(self, e):
# get the listbox to sort by (mapped by the header button)
b=e.widget
col, direction = self.colmapping[b]
# get the entire table data into mem
tableData = self.get(0,END)
if self.origData == None:
import copy
self.origData = copy.deepcopy(tableData)
rowcount = len(tableData)
#remove old sort indicators if it exists
for btn in self.colmapping.keys():
lab = btn.cget('text')
if lab[0]=='[': btn.config(text=lab[4:])
btnLabel = b.cget('text')
#sort data based on direction
if direction==0:
tableData = self.origData
else:
if direction==1: b.config(text='[+] ' + btnLabel)
else: b.config(text='[-] ' + btnLabel)
# sort by col
def colsort(x, y, mycol=col, direction=direction):
return direction*cmp(x[mycol], y[mycol])
tableData.sort(colsort)
#clear widget
self.delete(0,END)
# refill widget
for row in range(rowcount):
self.insert(END, tableData[row])
# toggle direction flag
if(direction==1): direction=-1
else: direction += 1
self.colmapping[b] = (col, direction)
def _select(self, y):
row = self.lists[0].nearest(y)
self.selection_clear(0, END)
self.selection_set(row)
return 'break'
def _button2(self, x, y):
for l in self.lists: l.scan_mark(x, y)
return 'break'
def _b2motion(self, x, y):
for l in self.lists: l.scan_dragto(x, y)
return 'break'
def _scroll(self, *args):
for l in self.lists:
apply(l.yview, args)
return 'break'
def curselection(self):
return self.lists[0].curselection()
def delete(self, first, last=None):
for l in self.lists:
l.delete(first, last)
def get(self, first, last=None):
result = []
for l in self.lists:
result.append(l.get(first,last))
if last: return apply(map, [None] + result)
return result
def index(self, index):
self.lists[0].index(index)
def insert(self, index, *elements):
for e in elements:
i = 0
for l in self.lists:
l.insert(index, e[i])
i = i + 1
def size(self):
return self.lists[0].size()
def see(self, index):
for l in self.lists:
l.see(index)
def selection_anchor(self, index):
for l in self.lists:
l.selection_anchor(index)
def selection_clear(self, first, last=None):
for l in self.lists:
l.selection_clear(first, last)
def selection_includes(self, index):
return self.lists[0].selection_includes(index)
def selection_set(self, first, last=None):
for l in self.lists:
l.selection_set(first, last)
if __name__ == '__main__':
tk = Tk()
Label(tk, text='MultiListbox').pack()
mlb = EditableMultiListbox(tk, (('Head1', 5), ('Head2', 10), ('Head3', 20)))
for zeile in xrange(20):
mlb.insert(END, (zeile, 'john', 'Alex Kellman'))
mlb.pack(expand=YES,fill=BOTH)
tk.mainloop()
Grüße,
der Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Super Sache! So macht das Laune :-)
Der Code hätte aber besser in dem Thread [1] gepasst, in dem ich dieses Widget vorgestellt und erweitert habe.
Vielleicht mag ein Mod den Post verschieben.
[1] http://www.python-forum.de/post-32776.html#32776
Der Code hätte aber besser in dem Thread [1] gepasst, in dem ich dieses Widget vorgestellt und erweitert habe.
Vielleicht mag ein Mod den Post verschieben.
[1] http://www.python-forum.de/post-32776.html#32776