How to make QListWidget items editable
Asked Answered
A

1

5

I am new to PyQt. I first made a dialog in Qt Designer, and implemented simple add, delete, up, down operations in a QListWidget. All my operations except edit worked a charm, so I did a lot of searching about how to make items editable, but results were not satisfactory. I was able to edit by using openPersistentEditor and closePersistentEditor, but the way it behaved was not what I wanted. I simply want the items to be editable when double-clicked or when the edit button is pressed, like in a normal gui.

My Qt Designer code is:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'myDialog.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(358, 226)
        self.widget = QtWidgets.QWidget(Dialog)
        self.widget.setGeometry(QtCore.QRect(10, 10, 341, 201))
        self.widget.setObjectName("widget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.mylist = QtWidgets.QListWidget(self.widget)
        self.mylist.setObjectName("mylist")
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.mylist.addItem(item)
        self.horizontalLayout.addWidget(self.mylist)
        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")
        self.add = QtWidgets.QPushButton(self.widget)
        self.add.setObjectName("add")
        self.verticalLayout.addWidget(self.add)
        self.edit = QtWidgets.QPushButton(self.widget)
        self.edit.setObjectName("edit")
        self.verticalLayout.addWidget(self.edit)
        self.remove = QtWidgets.QPushButton(self.widget)
        self.remove.setObjectName("remove")
        self.verticalLayout.addWidget(self.remove)
        self.up = QtWidgets.QPushButton(self.widget)
        self.up.setObjectName("up")
        self.verticalLayout.addWidget(self.up)
        self.down = QtWidgets.QPushButton(self.widget)
        self.down.setObjectName("down")
        self.verticalLayout.addWidget(self.down)
        self.sort = QtWidgets.QPushButton(self.widget)
        self.sort.setObjectName("sort")
        self.verticalLayout.addWidget(self.sort)
        self.closebtn = QtWidgets.QPushButton(self.widget)
        self.closebtn.setObjectName("closebtn")
        self.verticalLayout.addWidget(self.closebtn)
        self.horizontalLayout.addLayout(self.verticalLayout)

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        __sortingEnabled = self.mylist.isSortingEnabled()
        self.mylist.setSortingEnabled(False)
        item = self.mylist.item(0)
        item.setText(_translate("Dialog", "guawa"))
        item = self.mylist.item(1)
        item.setText(_translate("Dialog", "kivy"))
        item = self.mylist.item(2)
        item.setText(_translate("Dialog", "grapes"))
        item = self.mylist.item(3)
        item.setText(_translate("Dialog", "mausami"))
        item = self.mylist.item(4)
        item.setText(_translate("Dialog", "watermelon"))
        item = self.mylist.item(5)
        item.setText(_translate("Dialog", "apple"))
        item = self.mylist.item(6)
        item.setText(_translate("Dialog", "chikoo"))
        item = self.mylist.item(7)
        item.setText(_translate("Dialog", "kiwi "))
        item = self.mylist.item(8)
        item.setText(_translate("Dialog", "lemon"))
        item = self.mylist.item(9)
        item.setText(_translate("Dialog", "mango"))
        item = self.mylist.item(10)
        item.setText(_translate("Dialog", "orange"))
        item = self.mylist.item(11)
        item.setText(_translate("Dialog", "pineapple"))
        item = self.mylist.item(12)
        item.setText(_translate("Dialog", "banana"))
        self.mylist.setSortingEnabled(__sortingEnabled)
        self.add.setText(_translate("Dialog", "&Add"))
        self.edit.setText(_translate("Dialog", "&Edit"))
        self.remove.setText(_translate("Dialog", "&Remove"))
        self.up.setText(_translate("Dialog", "&Up"))
        self.down.setText(_translate("Dialog", "&Down"))
        self.sort.setText(_translate("Dialog", "&Sort"))
        self.closebtn.setText(_translate("Dialog", "&Close"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())

and my functioning code is:

from PyQt5 import QtWidgets, QtCore, QtGui
import sys, time
from PyQt5.QtCore import Qt
import myDialog
from myDialog import Ui_Dialog
class window(QtWidgets.QDialog):
    def __init__(self):
        super(window,self).__init__()

        #####SETTING BASE DIALOG####
        self.dialogClass=Ui_Dialog()
        self.dialogClass.setupUi(self)

        ####building singla and slots####
        self.build_connection()
        #################################


        self.show()

    def build_connection(self):
        self.dialogClass.add.clicked.connect(self.ask_input)
        self.dialogClass.edit.clicked.connect(self.edit_current)
        self.dialogClass.remove.clicked.connect(self.delete_current)
        self.dialogClass.closebtn.clicked.connect(self.close)
        self.dialogClass.down.clicked.connect(self.go_down)
        self.dialogClass.up.clicked.connect(self.go_up)
        self.dialogClass.sort.clicked.connect(self.sort_list)


    def ask_input(self):
        pass

    def sort_list(self):
        self.dialogClass.mylist.sortItems()

    def go_down(self):
        rowno=self.dialogClass.mylist.currentRow()
        val=self.dialogClass.mylist.takeItem(self.dialogClass.mylist.currentRow())
        if val:
            self.dialogClass.mylist.insertItem(rowno+1,val.text())
            self.dialogClass.mylist.setCurrentRow(rowno+1)

    def go_up(self):
        rowno=self.dialogClass.mylist.currentRow()
        val=self.dialogClass.mylist.takeItem(self.dialogClass.mylist.currentRow())
        if val:
            self.dialogClass.mylist.insertItem(rowno-1,val.text())
            self.dialogClass.mylist.setCurrentRow(rowno-1)

    def close_edit(self,item):
        try:
            val=self.dialogClass.mylist.item(self.dialogClass.mylist.currentRow())
            self.dialogClass.mylist.closePersistentEditor(val)
        except Exception as E:
            print(E)

    def edit_current(self):
        val=self.dialogClass.mylist.item(self.dialogClass.mylist.currentRow())
        try:
            self.dialogClass.mylist.openPersistentEditor(val)
            self.dialogClass.mylist.currentTextChanged.connect(self.close_edit)
        except Exception as E:
            print(E)
#        print(dir(val))

    def delete_current(self):
        val=self.dialogClass.mylist.takeItem(self.dialogClass.mylist.currentRow())
        if val:
            print(val.text())




app=QtWidgets.QApplication([])
ex=window()
sys.exit(app.exec_())

#time.sleep(5)

I am trying to make simple edit button that enables editing in currentSelection.Thats it

Antipas answered 24/12, 2017 at 17:48 Comment(0)
L
13

You need to set the item-flags to make the items editable. You can do that in your code like this:

class window(QtWidgets.QDialog):
    def __init__(self):
        ...
        listwidget = self.dialogClass.mylist
        for index in range(listwidget.count()):
            item = listwidget.item(index)
            item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
        ...

The flags can also be set in Qt Designer. Use the following steps to do that:

  1. double-click the list-widget to show the Edit List Widget dialog
  2. in the dialog, select an item and click the Properties button
  3. scroll down to the bottom of the properties list
  4. check the checkbox for the Editable flag

To start editing an item from code, you can use a method like this:

def edit_current(self):
    index = self.dialogClass.mylist.currentIndex()
    if index.isValid():
        item = self.dialogClass.mylist.itemFromIndex(index)
        if not item.isSelected():
            item.setSelected(True)
        self.dialogClass.mylist.edit(index)
Lists answered 24/12, 2017 at 20:33 Comment(9)
thanks alot for this.But I am also trying to achieve the exact same effect on pressing edit button as well :)Antipas
@NimishBansal. I have added some more example code.Lists
What does item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)? I can see it makes the item editable, but what's with the | in the middle?Longmire
It is bitwise OR. So the Qt.ItemIsEditable flag is being added to the existing flags.Lists
@Lists You sure? Googling brought me this answer which would considering PyCharm lists the first param as UnionLongmire
@MattM. Yes, of course I'm sure. This is very common and basic programming stuff. See the item flags docs for how qt uses them. The answer you linked to is specific to python sets, whereas flags are integers. In python, all the operators can be reimplemented to provide different functionality that is relevant to the type. See also the accepted answer to the question you linked to.Lists
@Lists So why not use a +?Longmire
@MattM. Because e.g. (2 + 2) == 4, but (2 | 2) == 2. Bitwise arithmatic switches individual bits on and off, which is why they are so useful as flags. It means that several options can be combined within a single integer value. The basics are explained in this tutorial and this answer.Lists
@Lists YOU SAVED MY LIFE! THANK YOU!Paynim

© 2022 - 2024 — McMap. All rights reserved.