Issue
I am trying to code an GUI APP using python Tkinter that i came across the problem, my main question is what make the button in the following code stays pressed(or goes down) after closing file explorer opened as the result of pushing open button.
I read the the questions this and this but i am not still able to figure out the reason behind this behaviour.
Here is a minimal working code to illustrate my problem and my code structure.
import tkinter as tk
import tkinter.filedialog as fd
class OpenSection:
def __init__(self, parent):
self.parent = parent
def initFrame(self):
self.frmFrame = tk.Frame(self.parent)
def createComponenets(self):
self.btnOpenFile = tk.Button(self.frmFrame, text="OPEN")
def loacateComponents(self):
self.btnOpenFile.pack(side="left")
def constructFrame(self):
self.createComponenets()
self.loacateComponents()
def makeObjAvailable(self):
self.frmFrame.btnOpenFile = self.btnOpenFile
def createSection(self):
self.initFrame()
self.constructFrame()
self.makeObjAvailable()
return self.frmFrame
class OpenSectionFunc():
def askOpenFileNameCmd(self):
path = fd.askopenfilename(initialdir="/", title="Select Your File",filetypes=
(("Excel files", "*.xlsx"), ("Excel Macro enabled files", "*.xlsm")))
# return "break"
class MainWindow:
def __init__(self, title, dimension):
self.mainWinodw = tk.Tk()
self.mainWinodw.title(title)
self.mainWinodw.geometry(dimension)
def createComponents(self):
self.frmOpenSection = OpenSection(self.mainWinodw).createSection()
def locateComponents(self):
self.frmOpenSection.pack(side="top", expand=0, fill="x")
def constructMainWindow(self):
self.createComponents()
self.locateComponents()
def start(self):
self.mainWinodw.mainloop()
mainWinodw = MainWindow("tk", "400x600")
mainWinodw.constructMainWindow()
mainWinodw.frmOpenSection.btnOpenFile.bind("<Button-1>", lambda event:OpenSectionFunc().askOpenFileNameCmd())
mainWinodw.start()
I know uncommenting the last line of askOpenFileNameCmd(self)
would solve the problem(How?) but first of all i would like to get an clear explanation of the reason behind the problem, then i would like to ask is that is using return "break"
to solve the problem an acceptable solution or the root of the problem is me structuring my code badly and it is better for me to rewrite my code, because i like to find more logical solution so i do not have to deal with such problems if my code grows.
Solution
When you bind <Button-1>
to a button it seems to break the default button press behaviour. Returning "break" from an event handler prevents Tkinter from propagating the event to other handlers. In your case, this prevents the default button click handler from running which fixes the problem. Alternatively, you can use the command
attribute of the button as that is the intended way to bind a button click to a button.
As for the structure of your code, I think it could be made cleaner by subclassing the tkinter widgets directly and removing some unnecessary methods. I would do something like this:
import tkinter as tk
import tkinter.filedialog as fd
class OpenSection(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.createComponents()
self.locateComponents()
def createComponents(self):
self.btnOpenFile = tk.Button(self, text="OPEN", command = self.askOpenFileNameCmd)
def locateComponents(self):
self.btnOpenFile.pack(side = "left")
def askOpenFileNameCmd(self):
path = fd.askopenfilename(initialdir="/", title="Select Your File",filetypes=
(("Excel files", "*.xlsx"), ("Excel Macro enabled files", "*.xlsm")))
class MainWindow(tk.Tk):
def __init__(self, title, dimension):
tk.Tk.__init__(self)
self.title(title)
self.geometry(dimension)
self.createComponents()
self.locateComponents()
def createComponents(self):
self.frmOpenSection = OpenSection(self)
def locateComponents(self):
self.frmOpenSection.pack(side="top", expand=0, fill="x")
app = MainWindow("tk", "400x600")
app.mainloop()
OpenSection
now subclasses tk.Frame
, so OpenSection
will work like a frame does. The initFrame
, constructFrame
and createSection
methods have all been combined into the __init__
method because they didn't really need to be separate. The button now uses the command
attribute instead of bind
and the button command function has been moved into the same class as the button so it's easier to see what's going on. MainWindow
has been cleaned up similarly.
Answered By - Henry
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.