I am trying to figure out how to pass an instance of a button into it's own command. Essentially what I am trying to do is if the events of the command being called are successful, I want to then disable the button.
Here is my button code which calls a function called 'runcommand':
btn_id = Button(tab_id, text=label, anchor=W)
btn_id.configure(command=lambda command=command, logtext=logtext, btn_id=btn_id: runcommand(command, logtext, btn_id))
Once called, if conditions are met, I am trying to disable it in the 'runcommand' function:
btn_id.configure(state=DISABLED)
I'm not sure if this is possible or if I'm just going about it the wrong way.
You are already passing in a reference to the button, so
def runcommand(command, text, btn_id):
...
if (should_disable_the_button):
btn_id.configure(state=DISABLED)
Ok, this is where I fully admit I am a dumbass. I was implementing the function correctly. I have an uber complex series of 'if' conditions in the runcommand function and the disable code wasn't getting called. I designated a boolean flag to determine if the button should be disabled now. Works fine. DU...MASS!
Related
The following is the simplest code required to illustrate my question:
def function_one():
pass
def function_two():
pass
def button_clicked(function_name_as_string):
# do stuff common to all button clicks
# here...
# then respond to specific button click by converting the
# supplied function name string into an actual function which runs.
eval(function_name_as_string + "()")
button_one = Button(root,text="Run Function One",
command=lambda: button_clicked("function_one"))
button_two = Button(root,text="Run Function Two",
command=lambda: button_clicked("function_two"))
This is an attempt to make my tkinter code as compact as possible. Here, there are multiple buttons. But rather than write a function to handle each button click, I wanted a single function to handle all button clicks. In particular, that's because there are some operations I want to execute in response to any button click, before responding to the specific button click. At the same time, I wanted to eliminate any lengthy if/elif statement in the button_clicked function, which would be required for the function to know which button had been clicked, and take appropriate action.
In my solution above, when a button is clicked, the command keyword calls my button_clicked function, but also uses lambda to send the name of the function I want to run in response to the button click. The button_clicked function executes the code common to all button clicks, then uses eval to convert the supplied function name (passed as a string) into an actual function that now runs.
So the button_clicked function is not aware of which button was clicked. Rather, it is aware of what function ought to run in response to the specific button click. And this code runs perfectly.
I have never used lambda before, nor have I used eval. I came across both during a long search. But because both are new to me, I am a bit wary. My question is simply this: is the above approach correct and sound? Or are there hidden pitfalls that I may not be aware of? Thanks in advance.
I would argue it's better to pass the actual function than the function name as a string. eval rarely adds any value over other solutions, and mostly just makes the code harder to understand.
def function_one():
pass
def function_two():
pass
def button_clicked(function):
# do stuff common to all button clicks
# here...
# then respond to specific button click by calling
# the specified function
function()
button_one = Button(root,text="Run Function One",
command=lambda: button_clicked(function_one))
button_two = Button(root,text="Run Function Two",
command=lambda: button_clicked(function_two))
I'm trying to create an Undo and Redo Button inside a GUI App using PyQt5 and Python 3.7.
When the Undo and Redo Buttons are clicked, the Key Sequences "Ctrl+Z" and "Ctrl+Y" should be executed respectively. Ive superficially gone through the documentation of QShortCut and QKeySequence but they seem to be designed for detecting key sequences and not triggering them. So how do I implement these buttons?
As per eyllanesc's comment, I'm adding this to better explain what I am trying to achieve.
self.undoButton = self.findChild(QtWidgets.QPushButton, 'undoButton')
self.undoButton.clicked.connect(self.undoButtonPressed)
self.anyPlainTextEdit = self.findChild(QtWidgets.QPlainTextEdit, 'anyPlainTextEdit')
# Function to Execute Key Sequence
def undoButtonPressed(self):
# Execute Ctrl+Z Key Sequence
I'm wondering if this is even possible.
If not, should I maintain Previous and current values of the PlainTextArea in separate variables and set the value of the PlainTextArea accordingly?
You don't have to launch the shortcut to enable redo or undo, just call the slot redo() and undo() when the buttons are pressed:
self.undoButton.clicked.connect(self.anyPlainTextEdit.undo)
self.redoButton.clicked.connect(self.anyPlainTextEdit.redo)
i have a question when using the Button widget in tkinter. I am new to this.
I noticed that when we use the command in the Button widget, sometimes we call a simple function just like that and sometimes we use lambda function and then we call it. What is the difference?
For example: tk.Button(window, text = "Click Me!", command = myfunction)
tk.Button(win,text="Result",command=lambda: result(en1.get())
Cant we just use it without lambda?
THank you.
Use of lambda:
The parentheses are the main reason that the function gets executed when given as command to a Button without lambda. If the function(which you are passing to the Button as a command) has no parameters(to be passed to itself), then you can simply pass it as a command avoiding the parentheses(). And hence you don't need to use lambda in this case. Like in this Example:command=func.
So using lambda is only necessary when the function has its own parameters(to be passed to itself).Like in this Example:command=lambda:func(a,b,c)
What lambda Does:
When you have to pass arguments to the function itself you have cannot avoid parentheses().
So in the case of buttons, lambda basically delays the execution of the function until the user clicks the button, by creating another function on the spot, which does not get called until the button is actually clicked. Hence the function does not get executed, where it is given as command to the Button.
Any Questions will be answered.
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
I am working on a PyGTK GUI project, and i would like to know, is there any way to get variable value from gtk.Entry?
text=gtk.Entry(0)
text.set_activates_default(True)
port = text.get_text()
This doesn't work as, the text box is empty by default, and get_text() returns empty string, any ideas?
This doesn't work as, the text box is empty by default, and get_text() returns empty string, any ideas?
Sounds like you're looking for getting the text after some user input. In order to do this, gtk uses signals that allow you to connect a user action to some function that will do something. In your case you want this function to get the text from the input. Because you haven't described the user interaction I'll give the simplest example. If you had a button
in your GUI that, when clicked, would grab whatever is typed in the entry at that moment, you'd do this:
button = gtk.Button( 'Click Me')
button.connect( 'clicked', on_button_click )
Then, you define the on_button_click function:
def on_button_click(self, widget, data=None):
port = text.get_text()
print 'Port: %s' % port
So with the sample code above, you'd have a button that, when clicked, grabs the text from your gtk.Entry.
Check out this link for a simple example on how to use signals in pygtk
Since your text field is by default empty, get_text() would return empty string.
Add a button callback function or some other function. So whenever that function is called, you would get the string from the Entry using
text.gtk_text()
You might want to use self here. since you'll be accessing entry in some other function and not in main thread, use
self.text=gtk.Entry()
self.text.set_activates_default(True)
def foo(self,widget,event): # some callback function
port = self.text.get_text()
print port
The retrieving method is the correct one, but right after the creation, the user can't yet have typed anyting into the field.
You would have to wait for the user to actually type something into the field, and afterwards calling get_text().