Python: Button widget in Tkinter - python

I have just now begun with GUI programming in Python 2.7 with Tkinter.
I want to have a button Browse, which when clicked opens the Windows File Explorer and returns the path of file selected to a variable. I wish to use that path later.
I am following the code given here. It outputs a window displaying 5 buttons, but the buttons do nothing. On clicking the first button, it doesn't open the selected file.
Likewise, on clicking the second button, the askopenfilename(self) function is called and it should return a filename. Like I mentioned, I need that filename later.
How to I get the value returned by the function into some variable for future use?

There is no point in using return inside a callback to a button. It won't return to anywhere. The way to make a callback save data is to store it in a global variable, or an instance variable if you use classes.
def fetchpath():
global filename
filename = tkFileDialog.askopenfilename(initialdir = 'E:')
FWIW (and unrelated to the question): you're making a very common mistake. In python, when you do foo=bar().baz(), foo takes the value in baz(). Thus, when you do this:
button = Button(...).pack()
button will take the value of pack() which always returns None. You should separate widget creation from widget layout if you expect to save an actual reference to the widget being created. Even if you're not, it's a good practice to separate the two.

Related

Using tkinter's button and entry widgets to update instance variable

I am trying to implement a little application that logs in a user and the user after log in can add/update/delete contents to/of a textfile. Here's a rough sketch of the code I have so far:
class admin():
def __init__(self):
self.app = Tk()
.
self.name=StringVar()
update = Button(self.app,....,command=self.update)
.
.
.
def update():
#Function to take different entries using Entry widget of tkinter in another window
anotherapp = Tk()
nameentry = Entry(anotherapp,textvariable = self.name)
submitbutton = Button(anotherapp,....,command=submit)
.
.
def submit():
#Opens a file and adds entries to a textfile.
namevar = self.name.get()
# code to append to file
To explain the above, I have a class admin. Creating an instance of this class would open a window with buttons that say create, update, delete and so on. On clicking one of the buttons, the respective functions (defined in the same class) would be called (I use lambda: in case the function has arguments, but so far, it doesn't).
So in the code I've mentioned, say I click on the Update button, it should call the update function which opens another window and takes the text that has to be updated in the text file (via the Entry widget). So according to the code it'll update the value of name. On clicking submit, the function submit uses .get() to get the string value of name, and appends it to the text file.
The code executes with no error but it DOES NOT read the input from the user. Blank lines get appended to my textfile when I click on the submit button.
Now I don't understand why this isn't working. The name variable is defined in init and can be updated by the functions of the same class. I have tried a lot of things to make this work, including adding parameters in the button commands, defining name elsewhere, etc. Even though I've solved the error, I get the same result: the file gets appended with blank lines. I've also tried to make name a class variable but that doesn't work since it is declared using StringVar() which needs it to be part of a tkinter window. I think I've also tried nesting submit function inside the update function, but I don't know why that didn't work out or if I hadn't implemented it correctly.
I don't know if it has to do with the working of tkinter's StringVar() and .get() function.
I can't think of any other way to implement the situation I have at hand. I am open to taking suggestions on changing the structure of the code, as long as it is not something major major and manages to achieve the functionality that I've described.
I am sorry if I've missed something basic, cause I've only started trying out OOP in python recently. And thanks in advance for any help.

More on passing arguments to tkinter button command

I have a number of test files in a single directory. I'm trying to write a GUI to allow me to select and run one of them.
So, I have a loop that scans the directory and creates buttons:
for fnm in glob.glob ('Run*.py'):
tstName = fnm[3:-3] # Discard fixed part of filename
btn = Button (self, text=tstName,
command=lambda: self.test(tstName))
btn.grid (row=rowNum, column=0, pady=2)
rowNum += 1
This creates my GUI correctly, with buttons labelled say, A and B but when I press on the button labelled A it passes B to the test method.
I've looked around and found this question How can I pass arguments to Tkinter button's callback command? but the answer doesn't go on to use the same variable name, with a different value, to configure another widget. (In fact, by tying the variable name to the widget name it almost implies that the technique won't work in this case, as I've found.)
I'm very new to Python, but am quite familiar with creating this kind of GUI using Tcl/TK and I recognise this problem - the value of tstName is being passed when I press the button, but I want it to pass the value the variable had when I created it. I know how I'd fix that in Tcl/Tk - I'd define a command string using [list] at creation time which would capture the value of the variable.
How do I do the same in Python?
You need to bind the current value of tstName at the time you define the button. The way you're doing it, the value of tstName will whatever it is at the time you press the button.
To bind the value at the time that you create the button, use the value of tstName as the default value of a keyword parameter to the lambda, like so:
btn = Button(..., command=lambda t=tstName: self.test(t))

Python Tkinter: Changing other button's text from event handler of one button

I have the following problem when using tkinter to create a very simple window containing a matrix of buttons: When one of the buttons is clicked, the event handler changes the text of that button using the configure method on the button widget. This works. But I also want to change the text in one of the other buttons, which does not work. The method I use is that on creating the button, I store the object returned by the Button method before I use the grid geometry manager to place it. This object looks like ".123456789L" when printed and seems to be a pointer to the widget. I also use configure on this to change the button text. But somehow it seems to be wrong, because it works sometimes, and most of the times not. There's unfortunately no error message, just nothing happens when calling configure. I checked and it seems to be the correct pointer to the widget. Do I have to use a special way to affect a widget other that the one that called the event handler? These are the relevant parts of the code:
# CREATING THE BUTTONS:
buttons={} # global
for i in range(3):
for j in range(3):
button = Tkinter.Button(self,text='foo')
buttons[button]=(i,j)
button.grid(column=j,row=i)
button.bind( "<Button-1>", self.OnButtonClick )
# CHANGING BUTTONS:
def find_button(i,j):
"""Return the pointer to the other button to be changed when a button has been clicked."""
for button,key in buttons.items():
if key==(i,j): return button
def OnButtonClick(self,event):
print "You clicked the button",buttons[event.widget]
i,j=buttons[event.widget]
old_button=find_button(i,j) # This is simplified, I don't actually pass i,j, but other values. But I checked this and it returns the reference to the correct button. But this simplified version works the same way, just assume a different button that the one pressed would be returned.
old_button.configure(text = 'blabla') # THIS DOES NOT WORK
event.widget.configure(text = 'something') # THIS WORKS
I have the same problem and i solve it with:
buttons[button]=(i,j,button)
and in the function OnButtonClicK:
i,j,old_button=buttons[event.widget]
old_button.configure(text = 'blabla') # THIS DOES NOT WORK

getting the label value of a button in Gtk

Am learning Gtk. I wanted to build a calculator, in which i want to display the number pressed , in the textbox. I have completed it, by calling different functions for different buttons clicked, and appending the value in the textbox with the value of the button pressed. Using python 2.7.3
Is there a way to obtain the label value of the button pressed so that i can use a single function instead of 10 functions from 0 to 9?
Thanks in advance
Button callbacks include the widget itself, and you can also pass data. See here.
instead of reading the label of the GtkButton, which is pretty much error prone, you should associate the value represented by the button to the button instance itself, e.g.:
button = Gtk.Button(label='1')
button._value = 1
# add button to the container
button.connect('clicked', on_button_clicked)
button = Gtk.Button(label='2')
button._value = 2
# add button to the container
button.connect('clicked', on_button_clicked)
and then read the value from the button instance inside the signal handler, e.g.:
def on_button_clicked(button):
print 'you pressed the button of value: %d' % (button._value)
GtkWidget instances in Python are Python object, and thus behave like any other Python object.

cursor gone in PyQT

I have a window containing multiple QRowWidgets, which are custom widgets defined by me. These QRowWidgets contain QLineEdits and other standard widgets. To show or hide certain parts of a QRowWidget, I overdefined the focusInEvent() methodes of all the widgets within it. It works perfectly, when I click on the QRowWidget, the hidden elements appear.
The weird thing is that the blinking cursor line hovewer doesn't appear in the QLineEdits within the custom widgets. I can select them both by a mouse click or with Tab, and a glow effect indicates that the QLineEdit is selected in it, I can select a text in it, or start typing at any location wherever I clicked, but the cursor never appears and it's quite annoying.
My 1st thought was that it is a bug on Mac, but I have the same experience on SuSe Linux.
I'm using python 2.7 and PyQt4.
This is in the __init__() of the QRowWidget:
for i in self.findChildren(QWidget):
i.focusInEvent = self.focusInEvent
And then this is the own focusInEvent():
def focusInEvent(self, event):
if self.pself.focusedLine:
self.pself.focusedLine.setStyleSheet("color: #666;")
self.pself.focusedLine.desc.hide()
self.pself.focusedLine.closebutton.hide()
self.setStyleSheet("color: #000;")
self.desc.show()
self.closebutton.show()
self.pself.focusedLine = self
I suspect you do not make a call to the original focusInEvent() when you override it. Your function should look something like:
def focusInEvent(self,...):
QParent.focusInEvent(self,...)
# the rest of your code
where QParent is the nearest base class for your widgets is.
Either that, or make sure you call focusInEvent() on your QLineEdit widgets as part of your function.
Given the comments, it sounds like you are dynamically reassigning the focusInEvent function on the insantiatations in your custom widget. I would either make a derived class for each of the widgets you use that just overrides focusInEvent as above, or include a line like
type(self).focusInEvent(self,..)
in you function.

Categories

Resources