@Philipp68: Das sieht nach Programmieren durch wildes raten oder sich wünschen was etwas bedeuten soll aus. So funktioniert programmieren aber nicht. Auch wenn das natürlich super praktisch wäre wenn Funktione, Methoden, und Syntax einfach das machen und bedeuten würden was man sich wünscht, so muss man leider damit leben das Syntax und APIs nur das tun was dokumentiert ist.
Also schau Dir mal an was die `curselection()`-Methode als Ergebnis liefert und was `os.remove()` als Argument erwartet. Dazwischen muss dann Code liegen den Du schreiben musst, der dafür sorgt das aus dem Rückgabewert von `curselection()` passende Argumente für die (Mehrzahl!) `os.remove()`-Aufrufe werden.
Sonstige Anmerkungen:
`Liste` hält sich in der Schreibweise nicht an die Namenskonvention (siehe Style Guide for Python Code).
Die `delete()`-Funktion sollte auf `Liste` nicht einfach so auf magische Weise zugreifen können, sonst ist das nicht wirklich eine Funktion. Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Auch wenn man mit Funktionen und Closures/`functools.partial()` noch ein gutes Stück weit kommen kann, braucht man für GUI-Programmierung letztlich objektorientierte Programmierung (OOP) für alles was nicht sehr trivial ist.
Datei aus Ordner löschen
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Probiere zuerst einmal aus, was curselection ist:Philipp68 hat geschrieben: "os.remove(current_selection)" wäre natürlich sehr gut, funktioniert leider nicht.
Falls jemand einen Tipp hat, wäre ich sehr dankbar!
Liebe Grüße
Code: Alles auswählen
# -*- coding: utf-8 -*-
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
class Application(tk.Tk):
def __init__(self,**kwargs):
tk.Tk.__init__(self,**kwargs)
# widget definitions ===================================
self.listbox = tk.Listbox(self,selectmode='extended')
self.listbox.delete(0,'end')
for e in 'sel 0\nsel 1\nsel 2\nsel 3\nsel 4\nsel 5\nsel 6\nsel 7\nsel 8\nsel 9\n'.split('\n'):
self.listbox.insert('end',e)
self.listbox.pack()
self.listbox.bind("<Return>",self.output_selection)
self.listbox.bind("<1>",self.output_selection)
def print_after(self):
print(self.listbox.curselection())
# needs some time until curselection fits
def output_selection(self,event=None):
self.after(10,self.print_after)
if __name__ == '__main__':
Application().mainloop()
Also: nicht gleich alles zusammen programmieren, sondern jeden Teil einzeln und durchtesten. Bzw. nicht einzeln, sondern auch aufbauend auf das was bis jetzt geht.
@Alfons Mittelmeyer: Ein ziemlich hässlicher Hack mit der Wartezeit, da will man doch lieber das '<<ListboxSelect>>'-Ereignis verwenden.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Ja, das funktioniert auch viel besser, also nochmals richtig:BlackJack hat geschrieben:@Alfons Mittelmeyer: Ein ziemlich hässlicher Hack mit der Wartezeit, da will man doch lieber das '<<ListboxSelect>>'-Ereignis verwenden.
Code: Alles auswählen
# -*- coding: utf-8 -*-
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
class Application(tk.Tk):
def __init__(self,**kwargs):
tk.Tk.__init__(self,**kwargs)
# widget definitions ===================================
self.listbox = tk.Listbox(self,selectmode='extended')
self.listbox.delete(0,'end')
for e in 'sel 0\nsel 1\nsel 2\nsel 3\nsel 4\nsel 5\nsel 6\nsel 7\nsel 8\nsel 9\n'.split('\n'):
self.listbox.insert('end',e)
self.listbox.pack()
self.listbox.bind("<<ListboxSelect>>",self.output_selection)
def output_selection(self,event=None):
print(self.listbox.curselection())
if __name__ == '__main__':
Application().mainloop()
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Es wird eine Liste von Indizes ausgegeben. Frage: wählt man bei Dir nur einen Eintrag aus, oder auch mehrere gleichzeitig.Philipp68 hat geschrieben: @Alfons: Ich habe mir die Ausgabe angesehen, es wird der Index angegeben und kein String. Vielen Dank für dein Beispiel. D.h für meinen Fall, dass ich den String aus meiner listbox erhalten, den mit meinen Pfad zusammensetzen muss, damit genau diese Datei gelöscht wird?
Wenn es nur einer ist durch Return oder Mausklick, kannst Du es auch anders machen. Im GuiDesigner habe ich ein Mausklick Event und ein Return Event dran hängen und lese es so aus:
Code: Alles auswählen
def do_lbox_click(event,lbox,entry,isMouse):
if isMouse: text = lbox.get(lbox.nearest(event.y))
else: text = lbox.get(tk.ACTIVE)
Du kannst es natürlich auch mit dem oder mehreren Indizes aus curselection auslesen. Die Methode heißt get().
@Philipp68: Zu Problemen mit globalen Variablen kommt es spätestens wenn man den Überblick verliert wann was von welcher ”Funktion” verändert wird. Und vorher halt schon wenn man die Funktionen nicht separat betrachten kann, sondern immer auch den ganzen Rest des Programms im Kopf haben muss, und das dadurch schwieriger ist als nötig.
Das menschliche Gehirn scheint so zwischen 4 und 7 Dinge gleichzeitig im Kopf jonglieren zu können, das ist also der Rahmen der üblicherweise für die maximale Anzahl von Variablen empfohlen wird. Da die meisten Programme natürlich mehr als 7 Variablen haben/brauchen, bricht man Probleme auf kleinere Teilprobleme herunter, die man isoliert betrachten kann und in separaten Funktionen oder Methoden mit wenigen Zeilen Code lösen kann. Dort kann man sich dann auch üblicherweise auf diese kleinere Anzahl von lokalen Variablen und/oder Attributen beschränken.
Globale Variablen machen auch die Fehlersuche schwieriger, weil man nicht einzelne Funktionen isoliert mit Testwerten ausführen kann, sondern immer auch die Variablen ausserhalb der Funktion berücksichtigen muss, die von dieser Funktion verwendet oder verändert werden, oder von Funktionen die von der zu testenden Funktion aufgerufen werden. Theoretisch kann ja jede davon irgend etwas globales ändern und damit Einfluss auf das Ergebnis und den Fehler haben. Um das zu wissen, muss man wieder *alle* Funktionen kennen, und nicht nur die, die man gerade testet.
Programm auf Modulebene macht ebenfalls das testen schwerer. Man kann nicht mal eben das Modul in einer Python-Shell importieren um einzelne Funktionen zu testen, ohne dass das Hauptprogramm losläuft. Automatisierte Tests gehen so auch nicht. Und auch andere Werkzeuge wie Sphinx, zur Erstellung von Dokumentation kann man mit solchen Modulen nicht verwenden. Und es gibt Module wie `multiprocessing` und `concurrent.futures` die erwarten das man das als Programm ausgeführte Modul zumindest unter Windows importieren kann, ohne das dabei gleich wieder das Programm als ganzes startet.
Komplett ungetestet:
Das menschliche Gehirn scheint so zwischen 4 und 7 Dinge gleichzeitig im Kopf jonglieren zu können, das ist also der Rahmen der üblicherweise für die maximale Anzahl von Variablen empfohlen wird. Da die meisten Programme natürlich mehr als 7 Variablen haben/brauchen, bricht man Probleme auf kleinere Teilprobleme herunter, die man isoliert betrachten kann und in separaten Funktionen oder Methoden mit wenigen Zeilen Code lösen kann. Dort kann man sich dann auch üblicherweise auf diese kleinere Anzahl von lokalen Variablen und/oder Attributen beschränken.
Globale Variablen machen auch die Fehlersuche schwieriger, weil man nicht einzelne Funktionen isoliert mit Testwerten ausführen kann, sondern immer auch die Variablen ausserhalb der Funktion berücksichtigen muss, die von dieser Funktion verwendet oder verändert werden, oder von Funktionen die von der zu testenden Funktion aufgerufen werden. Theoretisch kann ja jede davon irgend etwas globales ändern und damit Einfluss auf das Ergebnis und den Fehler haben. Um das zu wissen, muss man wieder *alle* Funktionen kennen, und nicht nur die, die man gerade testet.
Programm auf Modulebene macht ebenfalls das testen schwerer. Man kann nicht mal eben das Modul in einer Python-Shell importieren um einzelne Funktionen zu testen, ohne dass das Hauptprogramm losläuft. Automatisierte Tests gehen so auch nicht. Und auch andere Werkzeuge wie Sphinx, zur Erstellung von Dokumentation kann man mit solchen Modulen nicht verwenden. Und es gibt Module wie `multiprocessing` und `concurrent.futures` die erwarten das man das als Programm ausgeführte Modul zumindest unter Windows importieren kann, ohne das dabei gleich wieder das Programm als ganzes startet.
Komplett ungetestet:
Code: Alles auswählen
#!/usr/bin/env python
# coding: utf-8
from __future__ import absolute_import, division, print_function
import os
import Tkinter as tk
from glob import iglob
PROGRAM_PATH = os.path.dirname(__file__)
CONFIG_PATH = os.path.join(PROGRAM_PATH, 'Config')
def iter_filenames(path, extension):
return (
os.path.basename(p) for p in iglob(os.path.join(path, '*' + extension))
)
def _on_error(_filename, exception):
raise exception
def delete_files(filenames, on_error=_on_error):
for filename in filenames:
try:
os.remove(filename)
except Exception as error:
on_error(filename, error)
class Application(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.filenames_listbox = tk.Listbox(self)
self.filenames_listbox.pack()
tk.Button(self, text='Load', command=self.on_load).pack()
tk.Button(self, text='Delete', command=self.on_delete).pack()
def on_load(self):
filenames = sorted(iter_filenames(CONFIG_PATH, '.csv'))
self.filenames_listbox.delete(0, tk.END)
self.filenames_listbox.insert(0, *filenames)
def on_delete(self):
indices = self.filenames_listbox.curselection()
filenames = [
os.path.join(CONFIG_PATH, self.filenames_listbox.get(i))
for i in indices
]
#
# TODO Instead of ignoring exceptions while deleting files, maybe
# collect errors and display them after deleting.
#
delete_files(filenames, lambda filename, exception: None)
#
# Need to delete in reverse order so not yet deleted entries
# are not moved to a different index.
#
for index in sorted(indices, reverse=True):
self.filenames_listbox.delete(index)
def main():
Application().mainloop()
if __name__ == '__main__':
main()
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Wäre es nicht besser 'extended' zu nehmen?
Da kann man dann auch mehrere Einträge auf einmal auswählen und das auch per Tastatur.
Außerdem sollte man Checkbuttons nicht Radio nennen, weil man dann denkt, dass das Radiobuttons wären.
Verwirrend ist auch das:
Da gibt es eine Funktion Radio7 und einen Checkbutton der genauso heißt. Und v1 bis v24 sowie die Callbacks Radio1 bis Radio24 kannst Du Dir sparen, weil die alles dasselbe tun.
Code: Alles auswählen
self.listbox = tk.Listbox(self,selectmode='extended')
Außerdem sollte man Checkbuttons nicht Radio nennen, weil man dann denkt, dass das Radiobuttons wären.
Verwirrend ist auch das:
Code: Alles auswählen
def Radio7():
if v7.get():
Radio7.config(bg='green')
else:
Radio7.config(bg='red')
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@Phillip68: und so kannst Du Dir den ganzen Code für die Callbacks Radio1 bis Radio 24 sparen:
Wenn man die Koordinaten auch berechnen kann, kannst Du die Checkbuttons 1 bis 24 auch in einer Schleife erzeugen und die Namen Radio1 bis Radio24 braucht man da auch nicht, denn sie sind ja im Dictionary eingetragen.
Wenn alle Checkbuttons im Dictionary eingetragen sind, schrumpft resetsmdled() ganz gehörig zusammen, denn das machst Du dann mit einer Schleife.
Code: Alles auswählen
from functools import partial
def radio_v1_v24_command(checkbutton):
checkbutton['bg'] = 'green' if checkbutton.variable.get() else 'red'
variable = tk.IntVar()
Radio1 = Checkbutton(f3,bg='red',height=1, width=1,variable=variable,onvalue=1,offvalue=0) #3Uhr
Radio1.place(x=590+160.0, y=280+0.0)
Radio1.variable = variable
Radio1['command'] = partial(radio_v1_v24_command,Radio1)
# Dann wäre noch ein Dictionary zu empfehlen, damit man dann auch mehrere behandeln kann und auch über Pins Werte setzen kann
# besser wäre auch mit 0 anzufangen, weil man dann bei range den Startwert nicht mit angeben muss, aber das ist Nebensache
Checkbuttons[1] = Radio1
Wenn alle Checkbuttons im Dictionary eingetragen sind, schrumpft resetsmdled() ganz gehörig zusammen, denn das machst Du dann mit einer Schleife.