wetbalfred wetbalfred - 1 year ago 82
Python Question

Python: How to set a variable to the result of command function in tkinter Button

So here is my problem that I just cant figure out and cant seem to find information to help me understand what is happening. So I set source equal to the button that calls a function called openDirectory which is really just a smaller way to call os.path.join and os.path.normalize on the askopendirectory function from tkinter.filedialog. The problem is that source is always a number and I cant figure out why it is not the path I have chosen in the openDirectory function. I have also tried placing the code inside openDirectory directly in the command of the button and it still does the same thing.

Steps to reproduce:

  1. Run this code (written using python 3.5)

  2. Select a path using the source button

  3. Hit the button at the bottom right corner which should show the path in a messagebox

  4. Notice that the messagebox shows a big number instead of the path.

How can I get the path to store in the source variable so I can access it at any time?

import os
from functions import *
from tkinter import *
from tkinter import messagebox
from tkinter import filedialog

class FileMover(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent

def openDirectory(listfiles, recursive):
destination = os.path.join(os.path.normpath(filedialog.askdirectory()), "")
return destination

def initUI(self):
self.parent.title("File Mover")

recursiveCheck = bool
previewCheck = bool

# source button and label. source should equal the path selected in openDirecotry
source = Button(self, text="Source Directory", command=lambda:openDirectory(recursiveCheck))
sourceLabel = Label(self, text="Select a Source Directory...")
sourcemsg = Button(self, text="Source Variable", command=lambda:messagebox.askokcancel(self, source))

# check box used to tell open directory either true or false to recurse the source dir
recursiveLabel = Label(self, text="Recursive ")
recursive = Checkbutton(self, onvalue=True, offvalue=False, variable=recursiveCheck)

# destination button and label. source should equal the path selected in openDirecotry
destination = Button(self, text="Target Directory ", command=lambda:openDirectory(False))
destinationLabel = Label(self, text="Select a Target Directory...")

# not implemented yet
previewLabel = Label(self, text="Preview ")
preview = Checkbutton(self, onvalue=True, offvalue=False, variable=previewCheck)

source.grid(row=0, column=0, columnspan=2)
sourceLabel.grid(row=0, column=2)
recursiveLabel.grid(row=1, column=1)
recursive.grid(row=1, column=2, sticky=W)
destination.grid(row=2, column=0, columnspan=2)
destinationLabel.grid(row=2, column=2)
previewLabel.grid(row=4, column=6)
preview.grid(row=4, column=7, sticky=W)
# just for debugging to show source directory on demand
sourcemsg.grid(row=5, column=8)

def main():
root = Tk()
ex = FileMover(root)

if __name__ == '__main__':

Answer Source

Buttons do not work that way. When a function serves as a button's callback and the function is called by using the button, there's nowhere to return to. There isn't really a sensible way to make that work. If it worked the way you are guessing it does, you would lose the reference to the button! You don't want that.

Instead, simply save it as an instance variable:

def openDirectory(self, recursive):
    self.destination = os.path.join(os.path.normpath(filedialog.askdirectory()), "")

Note that your openDirectory method had listfiles referring to the instance itself, while the other methods use the traditional self - I've changed it to use self so you don't have to deal with listfiles.destination = ....

sourcemsg = Button(self, text="Source Variable", command=lambda:messagebox.askokcancel('Window Title', self.destination))

Note that I've changed the arguments to messagebox.askokcancel to the string 'Window Title' and the reference self.destination, so instead of the window's title being a reference to the frame (it's supposed to be a string for the window's title) it's an actual string, and instead of the message's text being a reference to a button (it's supposed to be a string for the message's text) it's the string you saved in openDirectory.