Dialog Ableitung von TKinter tkSimpleDialog.Dialog

Fragen zu Tkinter.
Antworten
twist
User
Beiträge: 13
Registriert: Donnerstag 8. April 2010, 11:04

Hallo,

Vielleicht könnt Ihr mir helfen.

Versuche ein Dateiauswahl Dialog für Touchscreens mit Tkinter zu bauen.

wenn ich von tkSimpleDialog.Dialog
ableite und in Body eine CTouchFileSelectBox gride.

bekomme ich immer die Fehlermeldung:

Code: Alles auswählen

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\tools\Python26\lib\lib-tk\Tkinter.py", line 1410, in __call__
    return self.func(*args)
  File "C:\_user\sg\Projekte\Kontrollprofilanalysator\SVMTrainer.py", line 26, in selectProfile
    MyDialog(self)
  File "C:\tools\Python26\lib\lib-tk\tkSimpleDialog.py", line 68, in __init__
    self.wait_visibility() # window needs to be visible for the grab
  File "C:\tools\Python26\lib\lib-tk\Tkinter.py", line 412, in wait_visibility
    self.tk.call('tkwait', 'visibility', window._w)
TclError: window ".49860856" was deleted before its visibility changed
obwohl ich den Frame grid_remove und destroye in der Ok() funktion.

Code: Alles auswählen


import fnmatch,  re,  os
import tkSimpleDialog
from Tkinter import *
from PIL import Image as tImage, ImageTk as ImgTk
fntTitle=("Helvetica", 14)

class AutoScrollbar(Scrollbar):
        # a scrollbar that hides itself if it's not needed.  only
        # works if you use the grid geometry manager.
        def set(self, lo, hi):
                if float(lo) <= 0.0 and float(hi) >= 1.0:
                        # grid_remove is currently missing from Tkinter!
                        self.tk.call("grid", "remove", self)
                else:
                        self.grid()
                Scrollbar.set(self, lo, hi)
        def pack(self, **kw):
                raise TclError, "cannot use pack with this widget"
        def place(self, **kw):
                raise TclError, "cannot use place with this widget"

## Widget anzeige einer Datei
class CFileWidget(Frame):
        def __init__(self,parent, textvariable=None,image="./icon/file.png", bg="white", text=None, command=None , width=100, height=3):
                Frame.__init__(self, parent, bg=bg)
                Imageicon = tImage.open(image)
                graphImage = Imageicon.resize((75, 90), resample=3)
                graphImage = ImgTk.PhotoImage(Imageicon)
#               Imageicon=self.load_icon(image)
                self.ilab=Label(self, image=graphImage)
                self.ilab.grid(row=0, column=0, sticky=W+E)
                self.ilab.image = graphImage
                self.path=text
                self.open=False
                Button(self, text=os.path.basename(text) , anchor=W, bg="white", relief=None,font=fntTitle , command=command, width=width, height=height).grid(row=0, column=1, sticky=W+E)
                self.update()

## Widget anzeige eines Verzeichnisses
class CDirectoryWidget(Frame):
        def __init__(self,parent, textvariable=None,image="./icon/folder.png", bg="white", text=None, command=None , updatecmd=None, width=100, height=3, listdir=None, sep="\\", exists=None, isdir=None, modus="all"):
                Frame.__init__(self, parent)
                Imageicon = tImage.open(image)
                self.Modus=modus
                self.listdir=os.listdir
                if(listdir):
                        self.listdir=listdir
                self.sep=sep
                self.exists=os.path.exists
                self.isdir=os.path.isdir
                if(isdir):
                        self.isdir=isdir
                if(exists):
                        self.exists=exists
                graphImage = Imageicon.resize((75, 90), resample=3)
                graphImage = ImgTk.PhotoImage(Imageicon)
                self.updatecmd=updatecmd
#               Imageicon=self.load_icon(image)
                self.ilab=Label(self, image=graphImage)
                self.row=0
                self.col=1
                self.command=command
                self.inhaltMap={}
                self.ilab.grid(row=0, column=0, sticky=W+E)
                self.ilab.image = graphImage
                self.path=text
                self.open=False
                test=os.path.basename(text)
                if(test==""):
                        test=text
                Button(self, text=test , anchor=W,font=fntTitle , command=self.activate, width=width, height=height).grid(row=0, column=1, sticky=W+E)
                self.update()
               
        def activate(self):
                if(not self.open):
                        if self.exists(self.path):
                                fList=self.listdir(self.path)
                                fList.sort()
                                for f in fList:
                                        if(self.exists(self.path+self.sep+f)):
                                                self.row+=1
                                                if(f in self.inhaltMap):
                                                        self.inhaltMap[f].grid(row=self.row, column=1, sticky=W+E)
                                                else:
                                                        #Hinzufuegen neuer Verzeichnis oder Datei Widgets
                                                        if(self.isdir(self.path+self.sep+f)):
                                                                self.inhaltMap[f]=CDirectoryWidget(self, text=self.path+self.sep+f, command=self.command, updatecmd=self.uptodate, modus=self.Modus)
                                                                self.inhaltMap[f].config(bg="white")
                                                                self.inhaltMap[f].grid(row=self.row, column=1, sticky=W+E)
                                                        else:
                                                                if(self.Modus=="all"):
                                                                        self.inhaltMap[f]=CFileWidget(self, text=self.path+self.sep+f, command=self.command)
                                                                        self.inhaltMap[f].config(bg="white")
                                                                        self.inhaltMap[f].grid(row=self.row, column=1, sticky=W+E)
                                        else:
                                                if(f in self.inhaltMap):
                                                        self.inhaltMap.pop(f).destroy()
                        self.open=True
                else:
                        self.row=0
                        for f in self.inhaltMap.iterkeys():
                                self.inhaltMap[f].grid_remove()
                        self.open=False
                if(self.command!=None):
                        self.command(self.path)
                self.uptodate()
               
        def uptodate(self):
                self.update()
                if(self.updatecmd!=None):
                        self.updatecmd()

##Scrollbox mit einsetzen von Widgets          
class CTouchFileSelectBox(Frame):
        def __init__(self, parent, path=None,command=None,  width=300, height=300, modus="all"):
                self.path=os.getcwd()
                if(path):
                        self.path=path
                self.command=command
                Frame.__init__(self, parent, width=width, height=height)
                self.maxWidth=width
                self.maxHeight=height
                self.yscrollbar = AutoScrollbar(self)
                self.xscrollbar = AutoScrollbar(self, orient=HORIZONTAL)

                self.canvas = Canvas(self, yscrollcommand=self.yscrollbar.set , xscrollcommand=self.xscrollbar.set , bg="white", width=width, height=height)
                self.canvas.grid(row=0, column=0, sticky=W+N+E+S)

                self.yscrollbar.config(command=self.canvas.yview, width=40)

                self.xscrollbar.config(command=self.canvas.xview, width=40)
               
                # make the canvas expandable
                self.grid_rowconfigure(0, weight=0)
                self.grid_columnconfigure(0, weight=1)
               
                #
                # create canvas contents
                self.frame = Frame(self.canvas, width=400, height=15)
                self.frame.config(bg="white")
                self.frame.rowconfigure(0, weight=1)
                self.frame.columnconfigure(0, weight=1)
                self.yscrollbar.grid(row=0, column=1,padx=5,  sticky=N+S)
                self.xscrollbar.grid(row=1, column=0,pady=5,  sticky=E+W)
#               self.frame.grid(row=0, column=0)
                self.FileBox=CDirectoryWidget(self.frame, text=self.path, command=self.command,  updatecmd=self.uptodate, modus=modus)
                self.FileBox.config(bg="white")
                self.FileBox.grid(row=0, column=0, sticky="nwse")
                self.canvas.create_window(0, 0, anchor=NW, window=self.frame)
                self.frame.update_idletasks()

               
        def uptodate(self):
                self.canvas.config(scrollregion=self.canvas.bbox("all"))
                self.frame.update()
                self.canvas.update()

##Das eigentliche Dialog
class MyDialog(tkSimpleDialog.Dialog):

        def body(self, master):

                self.TFSBox=CTouchFileSelectBox(master, "C:\\",  width=600, height=300)
                self.TFSBox.grid(row=0)

        def ok(self, event=None):
                self.TFSBox.grid_remove()
                self.TFSBox.destroy()
                del self.TFSBox
       
                self.withdraw()
                self.update_idletasks()
       
                self.apply()
#      
                self.cancel()

        def cancel(self, event=None):

                # put focus back to the parent window
                #self.parent.focus_set()
                self.destroy()

                       
        def apply(self):
                return self
root=Tk()
d=MyDialog(root)
Habe ich da irgendetwas vergessen oder was mach ich falsch?

Danke im vorraus für eure Hilfe

gruß
Twist
Zuletzt geändert von twist am Montag 20. September 2010, 10:36, insgesamt 1-mal geändert.
Der Mensch unterscheidet sich von anderen Wirbeltieren im Grunde nur durch den Führerschein...
Die meisten Menschen gehen dann aber einen Schritt zurück in der Evolution!!!!!
twist
User
Beiträge: 13
Registriert: Donnerstag 8. April 2010, 11:04

Hat denn keiner eine Idee was da schiefläuft oder ist euch der Quelltext zulang?

gruß
Twist
Der Mensch unterscheidet sich von anderen Wirbeltieren im Grunde nur durch den Führerschein...
Die meisten Menschen gehen dann aber einen Schritt zurück in der Evolution!!!!!
BlackJack

@twist: Also mir ist es zu lang und es ist nicht lauffähig.
twist
User
Beiträge: 13
Registriert: Donnerstag 8. April 2010, 11:04

Sorry,

So jetzt müsste es lauffähig sein.

Die Länge muss leider sein. Sonst fehlt ja was vom Code um es zu testen! :-(

gruss
twist
Der Mensch unterscheidet sich von anderen Wirbeltieren im Grunde nur durch den Führerschein...
Die meisten Menschen gehen dann aber einen Schritt zurück in der Evolution!!!!!
BlackJack

@twist: Also ich habe 'C:\\' durch '/' ersetzt, dann läuft es auch, aber ich weiss nicht ob es wirklich das tut was es soll. Die Ausnahme bekomme ich jedenfalls nicht.

Es ist auf jeden Fall länger als es sein muss. Du kannst mir nicht erzählen, dass man da nichts kürzen kann ohne dass der Fehler bei Dir verschwindet.
twist
User
Beiträge: 13
Registriert: Donnerstag 8. April 2010, 11:04

Hallo,
Arbeitest unter linux.

Anderes Beispiel. Aber die selbe Ausnahme nach schließung des Dialogs!
Bitte png Bilder ins Script-Verzeichnis kopieren vor dem Start des Scripts

Code: Alles auswählen

import fnmatch,  re,  os
from PIL import Image as tImage, ImageTk as ImgTk
from Tkinter import *
import tkFileDialog
import tkSimpleDialog
from PIL import BmpImagePlugin, PngImagePlugin, Image
fntTitle=("Helvetica", 14)

class CFileSeeker():
	def __init__(self):
		self.FileList=[]
	def searchFiles(self, path=None, expr=""):
		if(path==None):
			return
		if(expr==""):
			expr="*.*"
		for file in os.listdir(path):
			if(os.path.isdir(path+"\\"+file)):
				self.searchFiles(path=path+"\\"+file, expr=expr)
			if(fnmatch.fnmatch(file, expr)):
				print file, " gefunden"
				if not (path+"\\"+file) in self.FileList:
					print "fuege hinzu"
					self.FileList.append(path+"\\"+file)
				else:
					print "schon vorhanden"
		if(len(self.FileList)>0):
			return True
		return False

class CGraphDialog(tkSimpleDialog.Dialog):
	def __init__(self,parent,  graphFile, title=None):
		self.GraphFile=graphFile
		self.FS=CFileSeeker()
		self.found=self.FS.searchFiles("./", self.GraphFile)
		self.Counter=0
		tkSimpleDialog.Dialog.__init__(self,parent,  title)
		
	def body(self, master):
		self.master=master
                if(self.found):
		        self.lab=self.lab=Label(master)
		        self.lab.pack(side='top', fill='both', expand='yes')
		        if(len(self.FS.FileList)<=0):
			        self.ok()
		        self.next()
		
	def ok(self, event=None):
	
		self.withdraw()
		self.update_idletasks()
	
		self.apply()
#	
		self.cancel()

	#Naechstes Bild anzeigen
	def next(self):
		self.lab.pack_forget()
		if(hasattr(self, "nextButton")):
			self.nextButton.pack_forget()
		graphImage = tImage.open(self.FS.FileList[self.Counter])
		#graphImage = graphImage.resize((1000, 580), resample=3)
		graphImage = ImgTk.PhotoImage(graphImage)
		self.lab=Label(self.master, image=graphImage)
		self.lab.pack(side='top', fill='both', expand='yes')
		self.lab.image = graphImage
		self.update()
		self.Counter+=1
		if(self.Counter<len(self.FS.FileList)):
			self.nextButton=Button(self.master, text="naechstes", font=fntTitle, width=10, height=3, command=self.next)
			self.nextButton.pack(side=RIGHT)

	def buttonbox(self):
		box = Frame(self)
	
		w = Button(box, text="OK",font=fntTitle,  width=15,height=4,  command=self.ok, default=ACTIVE)
		w.pack(side=LEFT, padx=5, pady=5)
	
		self.bind("<Return>", self.ok)
	
		box.pack()

root=Tk()
d=CGraphDialog(root,"*.png")


gruss
twist
Der Mensch unterscheidet sich von anderen Wirbeltieren im Grunde nur durch den Führerschein...
Die meisten Menschen gehen dann aber einen Schritt zurück in der Evolution!!!!!
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo twist

Ich arbeite unter Linux SuSE 11.0. Hier erzeugt dein Skript keine Ausnahme. Es zeig zwei folgende Fenster die geschlossen werden können ohne eine Ausnahme zu werfen:

Bild

Bild

Kannst du uns einmal die Ausnahme zeigen?

Gruß wuf :wink:
Take it easy Mates!
twist
User
Beiträge: 13
Registriert: Donnerstag 8. April 2010, 11:04

Hallo,

hast du png Bilder ins Script-Verzeichnis kopiert?
dann müssten sie eigentlich angezeigt werden!

das zweite Fenster ohne inhalt ist das Parentfenster vom Dialog

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\_user\sg\Projekte\Kontrollprofilanalysator\dtest2.py", line 86, in <m
odule>
    d=CGraphDialog(root,"*.png")
  File "C:\_user\sg\Projekte\Kontrollprofilanalysator\dtest2.py", line 36, in __
init__
    tkSimpleDialog.Dialog.__init__(self,parent,  title)
  File "C:\tools\Python26\lib\lib-tk\tkSimpleDialog.py", line 68, in __init__
    self.wait_visibility() # window needs to be visible for the grab
  File "C:\tools\Python26\lib\lib-tk\Tkinter.py", line 412, in wait_visibility
    self.tk.call('tkwait', 'visibility', window._w)
_tkinter.TclError: window ".25437168" was deleted before its visibility changed
Der Fehler Tritt auf wenn man Ok anklickt und sich das Dialog-Fenster schließt!

gruss
Twist
Der Mensch unterscheidet sich von anderen Wirbeltieren im Grunde nur durch den Führerschein...
Die meisten Menschen gehen dann aber einen Schritt zurück in der Evolution!!!!!
BlackJack

@twist: Also bei mir läuft das auch ohne Probleme.

Warum implementierst Du `ok()`?
twist
User
Beiträge: 13
Registriert: Donnerstag 8. April 2010, 11:04

Seltsam!!! welche Python version hast du???
Die Ok() Funktion ist erst hinein gekommen als ich rumexperimentiert hab, um den Fehler zu beheben.
Der Mensch unterscheidet sich von anderen Wirbeltieren im Grunde nur durch den Führerschein...
Die meisten Menschen gehen dann aber einen Schritt zurück in der Evolution!!!!!
twist
User
Beiträge: 13
Registriert: Donnerstag 8. April 2010, 11:04

Unter Linux taucht der Fehler auch net auf! :-(
Sch... Windoof, kann aber auch am Ben... liegen :-((((
Der Mensch unterscheidet sich von anderen Wirbeltieren im Grunde nur durch den Führerschein...
Die meisten Menschen gehen dann aber einen Schritt zurück in der Evolution!!!!!
BlackJack

@twist: Läuft das unter Windows überhaupt wenn man `mainloop()` nicht aufruft? Wie startest Du das unter Windows?

Die Quelltexte sehen übrigens ziemlich verworren aus. Wenn man sich schon nicht an PEP8 hält, wäre es doch zumindest schön sich an *irgendeine* Konvention bei der Namensgebung und Formatierung zu halten und nicht alles so zu mischen.

Im Dialog werden für meinen Geschmack zu viele Widgets erstellt und zerstört. Man sollte die IMHO einmal in `body` alle erstellen und dann im Verlauf des Programms verändern und nicht immer wegwerfen und neu erstellen.

`CFileSeeker` hat durch den ``in``-Test auf bereits vorhandene Dateinamen ein gruseliges Laufzeitverhalten und wäre sicher auch mit `os.walk()` idiomatischer zu schreiben. Das könnte man vielleicht auch als Funktion schreiben. Der Sinn vom Rückgabewert erschliesst sich mir auch nicht so. `found` enthält ja letztendlich genau den selben Wahrheitswert den auch `CFileSeeker.FileList` hat -- eine leere List ist als Wahrheitswert betrachtet "falsch" und nicht-leere Listen sind "wahr".
twist
User
Beiträge: 13
Registriert: Donnerstag 8. April 2010, 11:04

Ja mit der Konvention hab ich es noch nicht so bei Python! :-(. Iritiert irgentwie mit den fehlenden Datentypen!
werde es auch noch mal überarbeiten.
Beim Fileseeker, ja man lernt immer hinzu!!! Aber danke für den Tip!
Der Mensch unterscheidet sich von anderen Wirbeltieren im Grunde nur durch den Führerschein...
Die meisten Menschen gehen dann aber einen Schritt zurück in der Evolution!!!!!
twist
User
Beiträge: 13
Registriert: Donnerstag 8. April 2010, 11:04

also es läuft unter Windows, bis auf die Ausnahme am Ende welche sehr störend ist! :-((( Vor allem wenn man was noch aus dem alten Dialog Objekt rausholen möchte! Denn wenn ich die Exception abfange existiert dat Objekt nicht mehr! :-(

Keine Mainloop: Da tkSimpleDialog wohl das mit der Mainloop übernimmt. Dachte ich mir jedenfalls mal so! Bin erst seit 2-3 Wochen mit Python am arbeiten!
Der Mensch unterscheidet sich von anderen Wirbeltieren im Grunde nur durch den Führerschein...
Die meisten Menschen gehen dann aber einen Schritt zurück in der Evolution!!!!!
BlackJack

@twist: Wenn Du den Namen oder eine andere Referenz hast, dann existiert das Objekt auch noch.
twist
User
Beiträge: 13
Registriert: Donnerstag 8. April 2010, 11:04

ach sch..., aber nicht wenn man sie nur im try-Block deklariert und initialisiert!
Ich voll hammel. Thanks
Der Mensch unterscheidet sich von anderen Wirbeltieren im Grunde nur durch den Führerschein...
Die meisten Menschen gehen dann aber einen Schritt zurück in der Evolution!!!!!
BlackJack

@twist: Deklariert wird da nichts, nur definiert. Aber solange das Erzeugen des Objekts funktioniert, sollte der Name auch im ``except`` definiert sein. ``try``-Blöcke erstellen keinen neuen Sichtbarkeitsbereich für Namen, das macht nur der ``def``-Block der Methode. Andererseits scheint die Ausnahme ja aus der `__init__()` zu kommen, die dann offenbar nicht komplett durch läuft!?

Hast Du eigentlich schon einmal eine andere Python-Version ausprobiert? Nicht dass das einfach nur ein Fehler in der Python/Tk-Version ist, die Du einsetzt.
twist
User
Beiträge: 13
Registriert: Donnerstag 8. April 2010, 11:04

hab ich jetzt auch gemerkt! Steh ich doch net so ganz auf dem schlauch.
Ja hatte erst python 2.6.1 jetzt 2.6.6
Der Mensch unterscheidet sich von anderen Wirbeltieren im Grunde nur durch den Führerschein...
Die meisten Menschen gehen dann aber einen Schritt zurück in der Evolution!!!!!
Antworten