Python PyQt6 ListWidget [duplicate] - python

I'm stuck using myItem.hide() method every time I need to remove Item from QListWidget list. Hiding an item instead of deleting/removing makes things unnecessary complex. I would appreciate if you show me how to delete Item from ListWidget permanently.
from PyQt4 import QtGui, QtCore
class MyApp(object):
def __init__(self):
super(MyApp, self).__init__()
self.mainWidget = QtGui.QWidget()
self.mainLayout = QtGui.QVBoxLayout()
self.mainWidget.setLayout(self.mainLayout)
self.hLayout = QtGui.QHBoxLayout()
self.mainLayout.insertLayout(0, self.hLayout)
self.listA=QtGui.QListWidget()
for i in range(3):
self.listA.addItem('Item '+str(i))
self.hLayout.addWidget(self.listA)
self.buttonGroupbox = QtGui.QGroupBox()
self.buttonlayout = QtGui.QVBoxLayout()
self.buttonGroupbox.setLayout(self.buttonlayout)
okButton = QtGui.QPushButton('Remove Selected')
okButton.clicked.connect(self.removeSel)
self.buttonlayout.addWidget(okButton)
self.mainLayout.addWidget(self.buttonGroupbox)
self.mainWidget.show()
sys.exit(app.exec_())
def removeSel(self):
listItems=self.listA.selectedItems()
if not listItems: return
for item in listItems:
print type(item), dir(item)

I don't know why but removeItemWidget don't work as expected. You have to use take item instead:
def removeSel(self):
listItems=self.listA.selectedItems()
if not listItems: return
for item in listItems:
self.listA.takeItem(self.listA.row(item))

Posting here an example showing how to implement same approach but now applied to QTreeWidget which a bit more involved than QListWidget.
from PyQt4 import QtGui, QtCore
class MyApp(object):
def __init__(self):
super(MyApp, self).__init__()
self.mainWidget = QtGui.QWidget()
self.mainLayout = QtGui.QVBoxLayout()
self.mainWidget.setLayout(self.mainLayout)
self.hLayout = QtGui.QHBoxLayout()
self.mainLayout.insertLayout(0, self.hLayout)
self.listA=QtGui.QTreeWidget()
self.listA.setColumnCount(3)
self.listA.setHeaderLabels(['Checkbox','Name','Data'])
for i in range(3):
item=QtGui.QTreeWidgetItem()
item.setCheckState(0,QtCore.Qt.Checked)
item.setText(1, 'Item '+str(i))
item.setData(2, QtCore.Qt.UserRole, id(item) )
item.setText(2, str(id(item) ) )
self.listA.addTopLevelItem(item)
self.hLayout.addWidget(self.listA)
self.buttonGroupbox = QtGui.QGroupBox()
self.buttonlayout = QtGui.QVBoxLayout()
self.buttonGroupbox.setLayout(self.buttonlayout)
okButton = QtGui.QPushButton('Remove Selected')
okButton.clicked.connect(self.removeSel)
self.buttonlayout.addWidget(okButton)
getDataButton = QtGui.QPushButton('Get Items Data')
getDataButton.clicked.connect(self.getItemsData)
self.buttonlayout.addWidget(getDataButton)
self.mainLayout.addWidget(self.buttonGroupbox)
self.mainWidget.show()
sys.exit(app.exec_())
def removeSel(self):
listItems=self.listA.selectedItems()
if not listItems: return
for item in listItems:
itemIndex=self.listA.indexOfTopLevelItem(item)
self.listA.takeTopLevelItem(itemIndex)
print '\n\t Number of items remaining', self.listA.topLevelItemCount()
def getItemsData(self):
for i in range(self.listA.topLevelItemCount()):
item=self.listA.topLevelItem(i)
itmData=item.data(2, QtCore.Qt.UserRole)
itemId=itmData.toPyObject()
print '\n\t Item Id Stored as Item Data:', itemId, 'Item Checkbox State:', item.checkState(0)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
MyApp()

A ListWidget is a list of ListWidgetItems. A ListWidgetItems can be assigned a custom widget to override the default, so removeItemWidget() only removes the custom widget. Hence the need for takeItem, which pops the item from the list and returns it (similar to how a python list works)

Related

Update PyQt menu

I am trying to dynamically update a menu with new items when I add new items via the form into Qsettings. For example, if you open my code and click the button and then click "new" it will open a QLineEdit with a button. When the button is clicked the list data gets stored via Qsettings.
I'd like to be able to update the menu somehow to show the items without restarting. I tried some things like calling repaint and update in a few areas with no luck.
Here is my code, I slimmed it down the best that I could for the example.
import functools
import sys
from PyQt5 import QtCore
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QWidget, QPushButton, QHBoxLayout, \
QVBoxLayout, QLineEdit,QApplication, QWidgetAction, QTextBrowser, QAction, QMenu
class MainWindow(QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.layout = QHBoxLayout()
self.menu_action = QAction(QIcon("icon.png"),"New", self)
self.menu_btn = QPushButton()
self.menu = MyMenu("Menu", self.menu_btn)
self.add_menu = self.menu.addMenu(QIcon("icon.png"), "Menu")
self.add_menu.addAction(self.menu_action)
self.menu_btn.setMenu(self.menu)
self.textBox = QTextBrowser(self)
action = QWidgetAction(self.menu_btn)
action.setDefaultWidget(self.textBox)
self.menu_btn.menu().addAction(action)
settings = QtCore.QSettings('test_org', 'my_app')
self.new_items = settings.value('new_item', [])
print('%s' % self.new_items)
for item in self.new_items:
self.create_action = QAction(QIcon("icon.png"), item[0], self)
self.create_action.setData(item)
self.add_menu.addAction(self.create_action)
self.create_action.triggered.connect(functools.partial(self.menu_clicked, self.create_action))
self.layout.addWidget(self.menu_btn)
self.setLayout(self.layout)
self.menu_action.triggered.connect(self.open_window)
def open_window(self):
self.create_menu_item = Create_Menu_Item()
self.create_menu_item.show()
def menu_clicked(self, item):
itmData = item.data()
print(itmData)
class Create_Menu_Item(QWidget):
def __init__(self, parent=None):
super(Create_Menu_Item, self).__init__(parent)
self.resize(200, 195)
self.layout = QVBoxLayout()
self.form = QLineEdit()
self.btn = QPushButton()
self.layout.addWidget(self.form)
self.layout.addWidget(self.btn)
self.btn.clicked.connect(self.save_new_item)
self.setLayout(self.layout)
def save_new_item(self):
settings = QtCore.QSettings('test_org', 'my_app')
self.new_item = settings.value('new_item', [])
self.new_item.append([self.form.text()])
settings.setValue('new_item', self.new_item)
print(self.new_item)
print('saved!')
class MyMenu(QMenu):
def event(self,event):
if event.type() == QtCore.QEvent.Show:
self.move(self.parent().mapToGlobal(QtCore.QPoint(0,0))-QtCore.QPoint(0,self.height()))
return super(MyMenu,self).event(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
Anyone have any ideas? Thanks.
You can create a for loop to access the list.
Bare in mind it is a list of lists so a nested for loop is neccessary
def save_new_item(self):
settings = QtCore.QSettings('test_org', 'my_app')
self.new_item = settings.value('new_item', [])
self.new_item.append([self.form.text()])
settings.setValue('new_item', self.new_item)
print(self.new_item)
print('saved!')
# Add new menu items..
for x in self.new_item:
for y in x:
print(y)
The above will keep adding the WHOLE list of items every time you add a new item..
To just add the newest item, this is all you need (the last item added to the list)
w.add_menu.addAction(self.new_item[0][-1])
so
def save_new_item(self):
settings = QtCore.QSettings('test_org', 'my_app')
self.new_item = settings.value('new_item', [])
self.new_item.append([self.form.text()])
settings.setValue('new_item', self.new_item)
print(self.new_item)
print('saved!')
#ADD last item in the list
w.add_menu.addAction(self.new_item[0][-1])

Pyqt4 Qcombobox signal is not firing upon user input but it does when done with .setCurrentIndex

The QComboBox currentIndexChanged Signal is not firing when a new item is selected from user. But it does fire when .setCurrentIndex is used within the code. (line 91 and 92).
I have a QTabWidget. In tab1 I have a Qvbox into which three Qhboxes are added. Each Qhbox is from the class Kaskade and contains two widgets, a QCombobox and a QstackedWidget. Depending of the current Index of the QCombobox the QstackWidget will either show a QLCD number or a Qspinbox.
If the user changes the QCombobox index in the GUI the currentIndexChanged Signal is not emitted, although the QCombobox shows the new item.
What am I missing? Any kind of help is appreciated.
This is my test code
# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
import sys
class Kaskade(QtGui.QWidget):
def __init__(self,sp,sp_min,sp_max, parent = None):
super(Kaskade, self).__init__(parent)
self._sp=sp
self._sp_min=sp_min
self._sp_max=sp_max
self.sp()
self.hbox_gen()
def mode_changed(self,i):
print "Mode has changed to", i
self.sp_stack.setCurrentIndex(i)
def sp(self):
self.sp_stack=QtGui.QStackedWidget(self)
self.sp1 = QtGui.QWidget()
self.sp2 = QtGui.QWidget()
self.sp1UI()
self.sp2UI()
self.sp_stack.addWidget(self.sp1)
self.sp_stack.addWidget(self.sp2)
def sp1UI(self):
self.sp1_layout=QtGui.QHBoxLayout()
self.sp1_lcd=QtGui.QLCDNumber(self)
self.sp1_layout.addWidget(self.sp1_lcd)
#self.sp1.connect(lcd_pv.display)
self.sp1.setLayout(self.sp1_layout)
def sp2UI(self):
self.sp2_layout=QtGui.QHBoxLayout()
self.sp2_spinBox=QtGui.QSpinBox()
self.sp2_spinBox.setRange(self._sp_min,self._sp_max)
self.sp2_spinBox.setValue(self._sp)
self.sp2_layout.addWidget(self.sp2_spinBox)
self.sp2.setLayout(self.sp2_layout)
def hbox_gen(self):
self.mode=QtGui.QComboBox(self)
self.mode.addItem("OFF")
self.mode.addItem("ON")
self.mode.currentIndexChanged.connect(self.mode_changed)
self.hbox = QtGui.QHBoxLayout()
self.hbox.addWidget(self.mode)
self.hbox.addWidget(self.sp_stack)
class tabdemo(QtGui.QTabWidget):
def __init__(self, parent = None):
super(tabdemo, self).__init__(parent)
self.tab1 = QtGui.QWidget()
self.tab2 = QtGui.QWidget()
self.tab3 = QtGui.QWidget()
self.addTab(self.tab1,"Tab 1")
self.addTab(self.tab2,"Tab 2")
self.addTab(self.tab3,"Tab 3")
self.tab1UI()
self.tab2UI()
self.tab3UI()
self.setWindowTitle("Heizung")
def tab1UI(self):
K1=Kaskade(28,5,40)
K2=Kaskade(30,5,40)
K3=Kaskade(35,5,40)
K1.mode.setCurrentIndex(1)
K3.mode.setCurrentIndex(1)
vbox = QtGui.QVBoxLayout()
vbox.addLayout(K1.hbox)
vbox.addLayout(K2.hbox)
vbox.addLayout(K3.hbox)
self.tab1.setLayout(vbox)
self.setTabText(1,"Tab1")
def tab2UI(self):
self.setTabText(1,"Tab2")
def tab3UI(self):
self.setTabText(2,"Tab3")
def main():
app = QtGui.QApplication(sys.argv)
ex = tabdemo()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You must add Kaskade to vbox in Tab 1, not the layout. In addition we must do self.hbox layout of Kaskade:
class Kaskade(QtGui.QWidget):
[...]
def hbox_gen(self):
[...]
self.hbox = QtGui.QHBoxLayout(self)
[...]
class tabdemo(QtGui.QTabWidget):
[...]
def tab1UI(self):
[...]
vbox = QtGui.QVBoxLayout()
vbox.addWidget(K1)
vbox.addWidget(K2)
vbox.addWidget(K3)
self.tab1.setLayout(vbox)
[...]

Add custom items to QListWidget

How can I add customized items to a QListWidget with a background color that I choose, and add a bottom border to each item, like this draft example in the picture below.
This is the code that I wrote:
from PyQt5 import QtWidgets, QtGui
import sys
class CustomListHead(QtWidgets.QWidget):
def __init__(self):
super(CustomListHead, self).__init__()
self.project_title = QtWidgets.QLabel("Today")
self.set_ui()
def set_ui(self):
grid_box = QtWidgets.QGridLayout()
grid_box.addWidget(self.project_title, 0, 0)
self.setLayout(grid_box)
self.show()
class CustomListItem(QtWidgets.QWidget):
def __init__(self):
super(CustomListItem, self).__init__()
self.project_title = QtWidgets.QLabel("Learn Python")
self.task_title = QtWidgets.QLabel("Learn more about forms, models and include")
self.set_ui()
def set_ui(self):
grid_box = QtWidgets.QGridLayout()
grid_box.addWidget(self.project_title, 0, 0)
grid_box.addWidget(self.task_title, 1, 0)
self.setLayout(grid_box)
self.show()
class MainWindowUI(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindowUI, self).__init__()
self.list_widget = QtWidgets.QListWidget()
self.set_ui()
def set_ui(self):
custom_head_item = CustomListHead()
item = QtWidgets.QListWidgetItem(self.list_widget)
item.setSizeHint(custom_head_item.sizeHint())
self.list_widget.setItemWidget(item, custom_head_item)
self.list_widget.addItem(item)
custom_item = CustomListItem()
item = QtWidgets.QListWidgetItem(self.list_widget)
item.setSizeHint(custom_item.sizeHint())
self.list_widget.addItem(item)
self.list_widget.setItemWidget(item, custom_item)
vertical_layout = QtWidgets.QVBoxLayout()
vertical_layout.addWidget(self.list_widget)
widget = QtWidgets.QWidget()
widget.setLayout(vertical_layout)
self.setCentralWidget(widget)
self.show()
app = QtWidgets.QApplication(sys.argv)
ui = MainWindowUI()
sys.exit(app.exec_())
I see you have QListWidgetItem with you.
From documentation you can customize each widget item, customize it and add to your listwidget:
The appearance of the text can be customized with setFont(), setForeground(), and setBackground(). Text in list items can be aligned using the setTextAlignment() function. Tooltips, status tips and "What's This?" help can be added to list items with setToolTip(), setStatusTip(), an
d setWhatsThis().
http://doc.qt.io/qt-5/qlistwidgetitem.html#details

Accessing QComboBox index values

I have a comboxbox which contains 2 items - Method01, Method02
How can I tell my code to execute Method01Func when Method01 is selected, likewise for Method02 too?
self.connect(self.exportCombo, SIGNAL('currentIndexChanged(int)'), self.Method01Func)
I tried to code it in something similar when accessing in a list - [0],[1]... but I was bumped with errors
One way to do it is to make use of the userData parameter when calling addItem(), and pass in a reference to the function you want that item to call.
Here's a simple example:
import sys
from PyQt4 import QtCore, QtGui
def Method01Func():
print 'method 1'
def Method02Func():
print 'method 2'
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
widget = QtGui.QWidget()
self.combo = QtGui.QComboBox()
self.combo.addItem('Method 1', Method01Func)
self.combo.addItem('Method 2', Method02Func)
self.combo.currentIndexChanged.connect(self.execute_method)
layout = QtGui.QVBoxLayout(widget)
layout.addWidget(self.combo)
self.setCentralWidget(widget)
#QtCore.pyqtSlot(int)
def execute_method(self, index):
method = self.combo.itemData(index).toPyObject()
method()
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
alternatively You can send the current items text with the signal:
self.exportCombo.currentIndexChanged[str].connect(self.execute_method)
and check it in the slot:
def execute_method(self, text):
(self.Method01Func() if text == 'Method01' else self.Method02Func())

Enable a single selection between 2 Lists

I am encountering this problem, and I hope someone can help me.
I am trying to create a situation where there are 2 QListWidgets, List01 and List02 for example, and they contains the following.
List01 = [T01, T02, T03]
List02 = [P01, P02, P03]
I wanted the user to select an item (T01) in List01, and hence in List02, no selection (highlighting) of any items will be conducted, meaning to say if the user hovers over to List02 and selects an item (P02), the selection in List01 will be gone and it will be the item (P02) selected in List02.
Currently, I am getting the problem, where my program is able to select an item in the 2 lists and I am not sure how to perform the above.
Could someone kindly guide me?
Many thanks in advance
OK here is an example code of how could you do what you want, it's very basic but you can get the idea within the functions f and g, hope it works:
import PyQt4.QtGui as gui
app = gui.QApplication([])
w = gui.QWidget()
l = gui.QHBoxLayout(w)
w.setLayout(l)
lis1 = gui.QListWidget()
lis2 = gui.QListWidget()
lis1.addItems(["1","2","3"])
lis2.addItems(["4","5","6"])
def f():
lis2.itemSelectionChanged.disconnect(g)
for item in lis2.selectedItems():
lis2.setItemSelected(item,False)
lis2.itemSelectionChanged.connect(g)
def g():
lis1.itemSelectionChanged.disconnect(f)
for item in lis1.selectedItems():
lis1.setItemSelected(item,False)
lis1.itemSelectionChanged.connect(f)
print dir(lis1.itemSelectionChanged)
lis1.itemSelectionChanged.connect(f)
lis2.itemSelectionChanged.connect(g)
l.addWidget(lis1)
l.addWidget(lis2)
w.show()
app.exec_()
Connect the itemSelectionChanged() signal from one QListWidget to the clearSelection slot of the other.
Example generated with QtDesigner:
# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(214, 158)
self.gridLayout = QtGui.QGridLayout(Form)
self.gridLayout.setObjectName("gridLayout")
self.listWidget = QtGui.QListWidget(Form)
self.listWidget.setObjectName("listWidget")
item = QtGui.QListWidgetItem()
item.setText("T01")
self.listWidget.addItem(item)
item = QtGui.QListWidgetItem()
item.setText("T02")
self.listWidget.addItem(item)
item = QtGui.QListWidgetItem()
item.setText("T03")
self.listWidget.addItem(item)
self.gridLayout.addWidget(self.listWidget, 0, 0, 1, 1)
self.listWidget_2 = QtGui.QListWidget(Form)
self.listWidget_2.setObjectName("listWidget_2")
item = QtGui.QListWidgetItem()
item.setText("P01")
self.listWidget_2.addItem(item)
item = QtGui.QListWidgetItem()
item.setText("P02")
self.listWidget_2.addItem(item)
item = QtGui.QListWidgetItem()
item.setText("P03")
self.listWidget_2.addItem(item)
self.gridLayout.addWidget(self.listWidget_2, 0, 1, 1, 1)
# This are the important lines.
QtCore.QObject.connect(self.listWidget, QtCore.SIGNAL("itemSelectionChanged()"), self.listWidget_2.clearSelection)
QtCore.QObject.connect(self.listWidget_2, QtCore.SIGNAL("itemSelectionChanged()"), self.listWidget.clearSelection)
QtCore.QMetaObject.connectSlotsByName(Form)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
Form = QtGui.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
You can take example on this code:
from PyQt4 import QtCore, QtGui
import sys
app = QtGui.QApplication(sys.argv)
class MyApp(QtGui.QDialog):
def __init__(self):
super(MyApp, self).__init__()
layout = QtGui.QHBoxLayout()
qlist1 = QtGui.QListWidget()
qlist1.addItems(["elem1","elem2","elem3"])
layout.addWidget(qlist1)
qlist2 = QtGui.QListWidget()
qlist2.addItems(["elem4","elem5","elem6"])
layout.addWidget(qlist2)
# This dict will be used when a list is clicked
# to clear the selection of the other list
self.list_dict = {}
self.list_dict[qlist1] = qlist2
self.list_dict[qlist2] = qlist1
qlist1.clicked.connect(self.list_clicked)
qlist2.clicked.connect(self.list_clicked)
self.setLayout(layout)
self.show()
def list_clicked(self):
self.list_dict[self.sender()].clearSelection()
myApp = MyApp()
sys.exit(app.exec_())

Categories