I'm adding a contextmenu to a QTableWidget dynamically:
playlistContenxt = QAction("Add to %s" % (currentItem.text()), self.musicTable)
playlistContenxt.setData(currentData)
self.connect(playlistContenxt, SIGNAL("triggered()"), self.addToPlaylistAction)
self.musicTable.addAction(playlistContenxt)
currentItem.text() is a playlist name thats being fetched from db, as you can see only one function (addToPlaylistAction) receives all triggers from different actions. On my addToPlaylistAction function, how do I determine which menu has been clicked?
The correct way is to use signal mapper: You can assign data to each of the senders and get a signal with that data.
You can use QAction.setData to set some data, so that the slot knows which playlist to add to. Then from the slot you can call self.sender() to get the action that triggered the signal, and use action.data() to get the data back.
Related
I currently have the following QLineEdit:
self.lineEdit_15.setText(_translate("Dialog", "email"))
I am trying to update it with the following QPushButton:
self.pushButton_5.setText(_translate("Dialog", "update"))
Ideally, I'd like to get user data and store it as a variable. Any thoughts?
You need to have a look at signals and slots in PyQt.
For example, when a button is clicked it triggers a clicked signal that you can connect to a slot. This slot can do the stuff you need
self.pushButton_5.clicked.connect(self.mySlotFunction)
#Slot that stores lineEdit text in myVar string
def mySlotFunction():
myVar = self.lineEdit_15.text()
I have an object of type QListWidget where the user can select 0 or more items.
If nothing is selected, how can i trigger an event that would call a function?
I know that you can detect clicking on a specific item by using:
QListWidget.itemClicked.connect(self.item_click)
Is there something similar for when nothing is selected at all? (or in other words, the QListWidget is clear)
Thanks!
Generally, you would connect to the itemSelectionChanged signal and then check whether anything is selected.
self.listwidget.itemSelectionChanged.connect(self.on_selection_changed)
def on_selection_changed(self):
if not self.listwidget.selectedItems():
# Do Stuff Here
self.nothing_selected_function()
But that will only catch events where something was selected and then the user deselected everything. If nothing was ever selected, it's not going to trigger this signal (like the first time you build the list, and nothing is selected). You'd have to call the slot manually in that case.
self.listwidget = ... # Code that builds and populates list widget
# Call this manually the first time.
self.on_selection_changed()
But part of your question is ambiguous. Why do you want to know when something is "not selected"? What about when a new item is added to the list? Should it trigger your "not selected" function since the list has changed, but there still isn't anything selected?
I want to create a client frontend in pygtk for my Django project. My general idea is to have one main window, and everytime the user has an action that must change the screen to unload previous widgets and load the new ones. E.g if i have a login page, after user logs in he is presented with a customer screen. I want the new screen to be placed on the same main window, kinda like a page stack, but without the "back" functionality. My first thought was to create a function for every screen, a show_login, a show_customers_screen, etc. Is this a good choice or should i try a better one. And a second question, related to the first. Can i create callbacks inside a function?
e.g
This would be a method of MainWindow
def create_login(self):
....creating widgets here
#UnboundLocalError: local variable 'clear_clb' referenced before assignment
btnlogin.connect('clicked', clear_clb, data=None)
def clear_clb(widget, data=None):
..log in process
I know why i get the error. The thing is that the fields i want this func to clear are local in create_login. Is this the right approach?
Define the clear_clb symbol before referencing it:
def create_login(self):
# create widgets
def clear_clb(widget, data=None):
# log in process
btnlogin.connect('clicked', clear_clb, data=None)
However, the more usual, and in my opinion more readable, way of doing this is to save references to your widgets as attributes of self:
def create_login(self):
# create widgets
self.btnlogin = gtk.Button(...
self.btnlogin.connect('clicked', clear_clb)
def clear_clb(self, widget, data=None):
# log in process
I am trying to replace a widget for another. I am using a StackedWidget. I have the following.
First, I register add some widgets to the StackedWidget:
self.stackedWidget.addWidget(w1)
self.stackedWidget.addWidget(w2)
self.stackedWidget.addWidget(w3)
The I bind the click of a button of w1:
QObject.connect(w1.pushButton,SIGNAL("clicked()"),self.stackedWidget,SLOT(self.stackedWidget.setCurrentWidget(w2)))
For Slot I have also tried "setCurrentIndex". I checked if the signal is being received, and it is ok.
Finally, I show w1.
self.stackedWidget.setCurrentWidget(w1)
Although the "clicked()" signal is received when the button of w1 is pressed, the widget w2 never appears in the StackedWidget.
UPDATE:
I am doing
QObject.connect(w1.pushButton,SIGNAL("clicked()"),self.stackedWidget,SLOT('w1Clicked()'))
as suggested; however, I get
Object::connect: No such slot QStackedWidget::w1Clicked()
Object::connect: (sender name: 'pushButton')
Object::connect: (receiver name: 'stackedWidget')
I guess I have to create the slot "w1Clicked" somehow, but I am using the designer I can't figure it out.
I have one Main Window with the StackedWidget and separate forms with the buttons, so I don't see how to make the connection or create slots.
Also, I discovered that the problem with the way I was doing:
QObject.connect(w1.pushButton,SIGNAL("clicked()"),self.stackedWidget,SLOT(self.stackedWidget.setCurrentWidget(w2)))
is that "self.stackedWidget.setCurrentWidget(w2)" gets executed immediately, it does not wait for the signal! That's why w2 was never shown.
Still I have no idea.
Your connect call is wrong. You can't define what values are going to be passed to your slot when you make the connection. Instead you need to create your own slot and handle the signal as you desire (apologies if my python syntax is off):
QObject.connect(w1.pushButton,SIGNAL("clicked()"),self,SLOT("w1Clicked()"))
def w1Clicked(self):
self.stackedWidget.setCurrentWidget(w2)
Finally, it worked this way:
w1.pushButton.clicked.connect(self.w1Clicked)
At least the signal is received and the method is called correctly.
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.