How to set a variable to the result of command function of a tkinter Button?
<p>So here is my problem that I just can't figure out and can't seem to find information to help me understand what is happening. So I set <code>source</code> equal to the button that calls a function called <code>openDirectory</code> which is really just a short-cut to call <code>os.path.join()</code> and <code>os.path.normalize()</code> on the <code>askopendirectory</code> function from <code>tkinter.filedialog</code>. </p>

<p>The problem is that the <code>source</code> is always a number and I can't figure out why it is not the path I have chosen in the <code>openDirectory</code> function. I have also tried placing the code inside <code>openDirectory</code> directly in the command of the button, and it still does the same thing.</p>

<p>Steps to reproduce:</p>

<ol>
<li>Run this code (written using python 3.5)</li>
<li>Select a path using the source button</li>
<li>Hit the button at the bottom right corner which should show the path in a <code>messagebox</code></li>
<li>Notice that the <code>messagebox</code> shows a big number instead of the path.</li>
</ol>

<p>How can I get the path stored in the source variable so I can access it at any time?</p>

<pre><code>#!/usr/bin/python
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
        self.initUI()

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

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

        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)
    root.mainloop()

if __name__ == '__main__':
    main()
</code></pre>

<p>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.</p>

<p>Instead, simply save it as an instance variable:</p>

<pre><code>def openDirectory(self, recursive):
    self.destination = os.path.join(os.path.normpath(filedialog.askdirectory()), "")
</code></pre>

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

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

<p>Note that I've changed the arguments to <code>messagebox.askokcancel</code> to the string <code>'Window Title'</code> and the reference <code>self.destination</code>, 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 <code>openDirectory</code>.</p>

python python-3.x button tkinter