Im trying to add right-click functionality to items in a list widget in PyQt4 using Python. Id like a pop up context menu to show that has buttons and when clicked should perform some function.
How do I get a context menu to pop up when right clicking on each of the items?
I have come up with a pretty simple way of doing this and works perfectly. In the ControlMainWindow class add the following to initialise the Context menu policy as CustomeContextMenu where listWidget_extractedmeters will be the name of your QListWidget:
self.listWidget_extractedmeters.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.listWidget_extractedmeters.connect(self.listWidget_extractedmeters,QtCore.SIGNAL("customContextMenuRequested(QPoint)" ), self.listItemRightClicked)
Then in the ControlMainwindow class the following functions allow you to add context menu items and to call a funtion that performs some functionality:
def listItemRightClicked(self, QPos):
self.listMenu= QtGui.QMenu()
menu_item = self.listMenu.addAction("Remove Item")
self.connect(menu_item, QtCore.SIGNAL("triggered()"), self.menuItemClicked)
parentPosition = self.listWidget_extractedmeters.mapToGlobal(QtCore.QPoint(0, 0))
self.listMenu.move(parentPosition + QPos)
self.listMenu.show()
def menuItemClicked(self):
currentItemName=str(self.listWidget_extractedmeters.currentItem().text() )
print(currentItemName)
Related
I have two buttons (Eg. A andB) which do the same things (based on user selection). So when you select something, then click the button, the selection's name will be input into the line-edit for the button. For example, if I click on buttonA, the input will be to lineEditA.
Currently I have created a signal function as follows:
def _connections_setup(self):
self.btnA.clicked.connect(self.get_sel_nameA)
self.btnB.clicked.connect(self.get_sel_nameB)
def get_sel_nameA(self):
sel_name = get_name_from_sel()
self.line_editA.setText(sel_name)
def get_sel_nameB(self):
sel_name = get_name_from_sel()
self.line_editA.setText(sel_name)
"""
def get_sel_name(self):
# Returns me a blank
button = self.sender()
print button.objectName()
# My objective here would be, if btnA is clicked, the sel_name will be inputted into lineEditA. Likewise for btnB
"""
Instead of creating two similar functions, how can I determine which button was clicked and have the selection's name to be input correctly into the line-edit?
I tried using self.sender() (see get_sel_name()) but it does not seems to return me the button name.
The sender() function only works in slots directly connected to signals. So your code needs to look something like this:
def _connections_setup(self):
self.btnA.clicked.connect(self.get_sel_name)
self.btnB.clicked.connect(self.get_sel_name)
def get_sel_name(self):
button = self.sender()
name = button.objectName()
if button is self.btnA:
self.line_editA.setText(name)
elif button is self.btnB:
self.line_editB.setText(name)
I got a menu opening when right clicking on a table, I'd like to get the action name I clicked on. The thing is that I create actions in a loop. Basically each action add the right clicked item to a file (a playlist). So in order to add the item I need to know where.
def menu(self, event):
self.menu_table = QtWidgets.QMenu(self.tableWidget)
self.submenu = QtWidgets.QMenu("Add to a playlist")
list = os.listdir("playlists")
for i in list:
self.submenu.addAction(i)
self.submenu.triggered.connect(MyFunction(ItemClicked))
self.menu_table.addMenu(self.submenu)
self.menu_table.exec_(self.tableWidget.mapToGlobal(event))
Your context menu handler should look like this:
def menu(self, pos):
menu = QtWidgets.QMenu()
submenu = menu.addMenu("Add to a playlist")
for filename in os.listdir("playlists"):
submenu.addAction(filename)
action = menu.exec_(self.mapToGlobal(pos))
if action is not None:
print(action.text())
MyFunction(action)
As mentioned, the menu's exec call returns the selected action. What would probably be easiest for you is to use QAction.setData to store the information you need into each action. It's a QVariant, so you can store practically anything. Then, in the result of the "exec" call, you use the selected action's QAction.data to get the value back out. (Sorry if my syntax isn't right...I don't know much Python.)
I'm developing an application using the Qt Designer and PyQt4, I need to make several screens where each screen I capture user-specific data, for that I need to implement a next button and a back button similar to
where the current screen closes and the following opens when the user clicks next or if he clicks back, the screen closes and opens the previous screen, I made an example with only the next buttons and back to exemplify, if I was not clear:
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Frm(QWidget):
def __init__(self, parent = None):
super(Frm, self).__init__(parent)
next = QPushButton('Next >', self)
back = QPushButton('< Back', self)
hbox = QHBoxLayout()
hbox.addWidget(back)
hbox.addWidget(next)
self.setLayout(hbox)
if __name__ == '__main__':
import sys
root = QApplication(sys.argv)
app = Frm(None)
app.show()
root.exec_()
In short: How do I implement a function that calls another screen and close the current at the click of a button?
First about a misconception: you do usually not create/show one screen (window) and close another, you usually only exchange the content of a wizard-like dialog window upon actions like pressing the buttons. The window is alive the whole time until the multiple page task is finished.
So I take it your question is really about:
How to exchange a widget in a layout?
Since you may still use PyQt4 which does not yet have QLayout.replaceWidget, it's best to just use methods removeWidget and addWidget of QLayout and since addWidget adds a widget to the end of the layout items list, I prefer a dedicated layout just for the interchangeable content of your wizard (see also: How to add an Item to the specific index in the layout).
Example code using PyQt5 but easily transferrable to PyQt4. Only the next button is implemented.
from PyQt5 import QtWidgets
class MyWizard(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# vertical layout, wraps content layout and buttons layout
vertical_layout = QtWidgets.QVBoxLayout()
self.setLayout(vertical_layout)
# content widget and layout
self.content_layout = QtWidgets.QVBoxLayout() # could be almost any layout actually
self.content = QtWidgets.QLabel('Page1') # customize with your content
self.content_layout.addWidget(self.content)
vertical_layout.addLayout(self.content_layout)
# back, forward buttons wraped in horizontal layout
button_layout = QtWidgets.QHBoxLayout()
button_layout.addStretch()
back_button = QtWidgets.QPushButton('Back')
back_button.clicked.connect(self.back_button_clicked)
button_layout.addWidget(back_button)
forward_button = QtWidgets.QPushButton('Forward')
forward_button.clicked.connect(self.forward_button_clicked)
button_layout.addWidget(forward_button)
vertical_layout.addLayout(button_layout)
def back_button_clicked(self):
"""
The back button is clicked.
"""
pass
def forward_button_clicked(self):
"""
The forward button is clicked.
"""
# remove old content
self.content_layout.removeWidget(self.content)
self.content.deleteLater()
# create new content
self.content = QtWidgets.QLabel('Another Page')
# add new content
self.content_layout.addWidget(self.content)
app = QtWidgets.QApplication([])
wizard = MyWizard()
wizard.setWindowTitle('MyWizard Example')
wizard.setFixedSize(600, 400)
wizard.show()
app.exec_()
And it looks like:
However, as already written in the comment by Marius, there is quite extensive support for such dialogs in Qt using QWizard. So I strongly recommend to use that instead. The example above is only to demonstrate the ability of inserting and removing widgets in layouts.
You should definitely use QWizard for such problems!
There is a QWizard class that allows you to create wizards in Qt and PyQt. It implements all the functionality you want, and lots more. All you do is design your pages by extending QWizardPage, and add them to the wizard. This is much simpler than doing the whole thing from scratch as you propose.
Old question but missing example with existing API
You don't need to create all structure of an Wizard by yourself. Qt (and PyQt) already provides a class called QWizard.
Basic example:
wizard = QtWidgets.QWizard()
page1 = QtWidgets.QWizardPage()
page1.setTitle('Page 1 is best!')
page1.setSubTitle('1111111111')
lineEdit = QtWidgets.QLineEdit()
hLayout1 = QtWidgets.QHBoxLayout(page1)
hLayout1.addWidget(lineEdit)
wizard.addPage(page1)
Complete example and some explanation:
https://www.youtube.com/watch?v=kTJ1QULxXjg
https://impatientprogrammer.net/2018/07/06/pyside-pyqt-qwizard-in-3-minutes/
I am making an app for ubuntu 12.04.What i want to do is add an option to the menubar which appear when we right click on some select option.
To make it more clear-
In Normally when we select some text and right click there appear some option like cut copy pasteI want to add another option how can i do it.
When clicked the option would just have to execute another application and send the selected data to that applicaion.
I would be using Glade with python for development.
you should know some basics about glade and gtk first. the following is just notes:
1-On glade you can use the menu button to create menu.
2-Right click on it an dchoose "edit ..."
3-from the window you can add items.(the right part display the name and type of the menu item , the left part display the properties of the selected item, the lower part display the signals which could connected to the menu item)
4- now connect the menu item with the function which do what you want (When clicked the option would just have to execute another application and send the selected data to that applicaion.)
5- go to your code. get the menu as usual .
self.menu = self.builder.get_object("menu")
6- to popup the menu on right click on an object, you should connect that object with the function ahich execute the menu ( assuming that its name is :on_button_press ) :
def on_button_press(self, treeview, event):
if event.button == 3:
x = int(event.x)
y = int(event.y)
time = event.time
pthinfo = treeview.get_path_at_pos(x, y)
if pthinfo is not None:
path, col, cellx, celly = pthinfo
treeview.grab_focus()
treeview.set_cursor( path, col, 0)
self.popupmenu.popup( None, None, None, event.button, time)
return True
In my ongoing effort to learn more about python, I am trying to add a right click event to my mp3 manager program. What currently works is that it shows the menu and all of the options. What is not working is the functions selected from the menu are not executing as I think they should be. Much of this code was taken from a 'how to' on another site.
Here are the right click menu options
menu_titles = ["Remove Selection from list",
"Delete Selection from system",
"Move Selection",
"Copy Selection",
"Print Selection"]
menu_title_by_id = {}
for title in menu_titles:
menu_title_by_id[ wxNewId() ] = title
The code that is run when the right click event happens
def RightClickCb( self, event ):
# record what was clicked
self.list_item_clicked = right_click_context = event.GetText()
### 2. Launcher creates wxMenu. ###
menu = wxMenu()
for (id,title) in menu_title_by_id.items():
### 3. Launcher packs menu with Append. ###
menu.Append( id, title )
### 4. Launcher registers menu handlers with EVT_MENU, on the menu. ###
EVT_MENU( menu, id, self.MenuSelectionCb )
### 5. Launcher displays menu with call to PopupMenu, invoked on the source component, passing event's GetPoint. ###
self.MainPanel.PopupMenu( menu, event.GetPoint() )
menu.Destroy() # destroy to avoid mem leak
def MenuSelectionCb( self, event ):
# do something
operation = menu_title_by_id[ event.GetId() ]
target = self.list_item_clicked
print 'Perform "%(operation)s" on "%(target)s."' % vars()
What I expect to get when I do a right-click and then select one of the options in the menu is the output
Perform "Print Selection" on "<data about the selection here>"
What I am getting is
Perform "Print Selection" on "."
How do I get the data from the item I have selected as part of my right click event?
Maybe you should use event.GetString() in place of event.GetText()
See here
Your code seems outdated tho, binding to events should be done like this:
menu.Bind(wx.EVT_MENU, self.MenuSelectionCb, id=id)
moreover if you bind all ids to the same function you can just bind once for all ids:
menu.Bind(wx.EVT_MENU, self.MenuSelectionCb)
You can find a solution under Python: Right click on objectlistview not showing item name selected where the use of objectlistview's GetSelectedObject() method is proposed instead.