More information in signal/slot with QPushButton - python

When I implements the function that is executed when a button is clicked, the code is like this:
self.connect(btnBrowse, SIGNAL("clicked()"), self.browseFile)
and I implement the function browseFile
def browseFile(self):
But when i am inside the method browseFile, I don't have information about the button being clicked, because I want to implement just one function browseFile for many buttons. how can I do to have more information the slot, for example to have my function looks like this:
def browseFile(self, option):
Thanks

Connect to a lambda (or use functools.partial).
Also note the use of new style syntax, which is much more readable and pythonic.
self.btnBrowse.clicked.connect(lambda: self.browseFile(option))

Sender() provides a pointer to the button that sent the event, you can then read the button text (or other associated data) to determine which button was pressed

Related

Registering multiple Tkinter listeners for an event

Is it possible to register multiple listeners for an event?
Imagine a click on a Treeview. There might be a standard binding on the <<TreeviewSelect>>, e.g.
tree.bind('<<TreeviewSelect>>', some_function)
resulting in an Entry getting changed. But what if additional Entrys are added later, each to be filled with another part of the data in the Treeview?
As far as I know, there can be only one binding per event-type per widget, i.e. not multiple <<TreeviewSelect>> functions getting bound. The following
tree.bind('<<TreeviewSelect>>', function1)
tree.bind('<<TreeviewSelect>>', function2)
...
would result in the last function being the only one getting called. Is there a way to register multiple function calls?
To run both functions on that event, you could create function3:
def function3(event=None):
function1(event)
function2(event)
and then bind the <<TreeviewSelect>> event to function3.
tree.bind("<<TreeviewSelect>>", function3)
Edit: another way.
You could also add the add=True parameter, like this:
tree.bind("<<TreeviewSelect>>", function1)
tree.bind("<<TreeviewSelect>>", function2, add=True)
This code snippet demonstrates how to use event_add to any widget for multiple access to a selected function.
Once the event is created using the <<name>> tag it can be bound to a function using the bind method.
import tkinter as tk
root = tk.Tk()
tree = ttk.Treeview(root)
tree.event_add("<<TreeViewSelect>>", "<Button-1>", "<Button-3>")
def me(event=None):
print(event.widget)
tree.bind("<<TreeViewSelect>>", me)

Tkinter Class and Button use

I am having trouble finding a way to accomplish what I want using buttons in tkinter. I am programming a multi-frame tkinter app, for myself, and each frame is a class, each class has buttons that I place on the screen in the __init__ method. I am having trouble trying to link the buttons and the command functions together.
Example:
class frameHome:
def __init__(self,parent, controller)
self.frame=tk.Frame(parent)
self.buttonOne=tk.Button(self.frame,text="Click Me") # I want to add the command here
self.buttonOne.pack()
def buttonOneClick():
print("You clicked me")
When I add the command in the tk.Button() call it says buttonOneClick not defined. One video I watched said to add the function at the top of the code. I would like to keep the function as a method of the class for organization, as well as keep init at the top of the class and was wondering if there is a way to create a reference to the function so I can have it as a method after the the init method and be able to call it in the init method, because I would like the init method to create the gui and link all widget commands for that class/frame in it.
Thank you for any time and help that you can offer
in your command did you write the command as command=buttonOneClick()? if that's the case then you should replace it with self.buttonOneClick()
The answer I needed was that I forgot the self param in the buttonOneClick(self, msg) method.

Give/get arguments in popup from "on_press"

Pardon me for my simple question, but I don't understand some thing.
I want to give a few arguments from button which is located in popup window in one method to another method.
Example:
.py code
class GeneralForm(TabbedPanel):
def EDIT(self,D):
box1=BoxLayout(orientation='vertical')
t1=TextInput(text=GeneralForm.PARSE(self,D))
b2=Button(text='Save')
b3=Button(text='Cancel')
box2=BoxLayout()
box2.add_widget(b2)
box2.add_widget(b3)
box1.add_widget(t1)
box1.add_widget(box2)
popup = Popup(content=box1,auto_dismiss=False,size_hint=(.75,.75),title='Edit')
b2.bind(on_press=self.SAVE_EDIT) <====== There is a problem
b3.bind(on_press=popup.dismiss)
popup.open()
def SAVE_EDIT(self,instance):
!!! DOING SOMETHING !!!
https://s3.amazonaws.com/xasan/snapshot/stack1.png
What I want:
In method "EDIT" I have text input "t1". After changing text in this text input I press button "b2" which calls method SAVE_EDIT with two arguments.
So, I want to give the third agrument to "SAVE_EDIT" method which will return an edited text in t1.
Something like this:
.py code
class GeneralForm(TabbedPanel):
def EDIT(self,D):
box1=BoxLayout(orientation='vertical')
t1=TextInput(text=GeneralForm.PARSE(self,D))
b2=Button(text='Save')
b3=Button(text='Cancel')
box2=BoxLayout()
box2.add_widget(b2)
box2.add_widget(b3)
box1.add_widget(t1)
box1.add_widget(box2)
popup = Popup(content=box1,auto_dismiss=False,size_hint=(.75,.75),title='Edit')
b2.bind(on_press=self.SAVE_EDIT(t1.txt)) <====== There is a problem
b3.bind(on_press=popup.dismiss)
popup.open()
def SAVE_EDIT(self,instance,TEXT): <====== There is a problem
!!! DOING SOMETHING with TEXT!!!
Step-by-step:
Popen window was opened with some text in the text input.
We edited text, deleted something or added.
We are clicking on button "Save"(b2) and all text in txt input(t1) push to method "SAVE_EDIT" where we save,parse or do something else
with this text.
Thanks in advance.
You could use lambda:
on_press=lambda instance, text=t1.txt: self.SAVE_EDIT(instance, TEXT=text)
Or functools.partial():
on_press=partial(self.SAVE_EDIT, TEXT=t1.txt)
Both variants use t1.txt at the time of the bind call i.e., the value may be obsolete by the time you press the button.
To use the current most recent value:
on_press=lambda instance: self.SAVE_EDIT(instance, TEXT=t1.txt)
In this case, t1.txt is called each time the callback is invoked.

Handling events from file menu

I am trying to code a program with a regular file menu. (e.g. File, Edit, View, etc).
I want the action they take in that menu to update my status bar (a label).
The problem is, the way I have it setup now, I believe it's executing the command and then trying to take the result as what it should do.
Currently a menu item is defined like so:
fileMenu.add_command(label="Insert", command=self.statusUpdater(statusLabel,"Insert Triggered")
And the function statusUpdater is defined as such:
def statusUpdater(self,status,commandName):
status.config(text=commandName)
status.update_idletasks()
So the problem is, right at the start of the program, the status changes to "Insert Triggered". What I want is for that to only happy once I have actually clicked "Insert"
From hints I've seen elsewhere it seems like I need some way to pass and handle the event of Insert being clicked.
Could someone supply a generic and basic function that does what I ask? I think the problem lies in the () attached to the command function, but I don't know any other way to pass arguments.
All i need is a function that is called on the click event, and knows which fileMenu command triggered it.
Thanks!
Commands take a reference to a function. You can se a lambda if you want to pass it arguments:
...command=lambda l=statusLabel, self.statusUpdater(l, "Insert Triggered"))

PyQt sending parameter to slot when connecting to a signal

I have a taskbar menu that when clicked is connected to a slot that gets the trigger event. Now the problem is that I want to know which menu item was clicked, but I don't know how to send that information to the function connected to. Here is the used to connect the action to the function:
QtCore.QObject.connect(menuAction, 'triggered()', menuClickedFunc)
I know that some events return a value, but triggered() doesn't. So how do I make this happen? Do I have to make my own signal?
Use a lambda
Here's an example from the PyQt book:
self.connect(button3, SIGNAL("clicked()"),
lambda who="Three": self.anyButton(who))
By the way, you can also use functools.partial, but I find the lambda method simpler and clearer.
As already mentioned here you can use the lambda function to pass extra arguments to the method you want to execute.
In this example you can pass a string obj to the function AddControl() invoked when the button is pressed.
# Create the build button with its caption
self.build_button = QPushButton('&Build Greeting', self)
# Connect the button's clicked signal to AddControl
self.build_button.clicked.connect(lambda: self.AddControl('fooData'))
def AddControl(self, name):
print name
Source: snip2code - Using Lambda Function To Pass Extra Argument in PyQt4
use functools.partial
otherwise you will find you cannot pass arguments dynamically when script is running, if you use lambda.
I'd also like to add that you can use the sender method if you just need to find out what widget sent the signal. For example:
def menuClickedFunc(self):
# The sender object:
sender = self.sender()
# The sender object's name:
senderName = sender.objectName()
print senderName
In general, you should have each menu item connected to a different slot, and have each slot handle the functionality only for it's own menu item. For example, if you have menu items like "save", "close", "open", you ought to make a separate slot for each, not try to have a single slot with a case statement in it.
If you don't want to do it that way, you could use the QObject::sender() function to get a pointer to the sender (ie: the object that emitted the signal). I'd like to hear a bit more about what you're trying to accomplish, though.

Categories