Search code examples
pythonpyqtpyqt5qlistview

Transition between different QListView display options (With CheckBoxes or not)


With this application, I tried to create 2 variants of the QListView view and apply different ways of working with it. The first option involves a list without Checkboxes, where the user can select several items while holding down the CTRL key:Variant 1. The second option differs visually from the first - checkboxes are present, and the selection process is also different (you do not need to use CTRL, and clicking on a specific position first selects it and then deselects it)Variant 1.

#!/usr/bin/python
# coding=utf-8

headline = """ 
###############################################################################
#                                   Program                                   #
#            a small ListView application in PyQt5 (Python 3.7)               #
###############################################################################
All comments are in two languages (Russian, English)
Все комментарии на двух языках (русский, английский)
"""

import sys
import random
from PyQt5 import QtWidgets, QtGui, QtCore, Qt

class HelloApplication(QtWidgets.QApplication):
    def __init__(self, args):
        """
            In the constructor, we do everything that is necessary to run our application, which
            creates a QApplication in the __init__ method, then adds our widgets and finally
            runs exec_loop
            В конструкторе мы делаем всё, что необходимо для запуска нашего приложения, которое
            создаёт QApplication в __init__ методе, затем добавляет наши виджеты и, наконец,
            запускает exec_loop
        """
        QtWidgets.QApplication.__init__(self,args)
        self.addWidgets()

    def addWidgets(self):

    # Create widgets
    # Создание виджетов
        self.checkCalc=0
        self.StartList=[]
        self.BaseWidget=QtWidgets.QWidget()
        self.BaseWidget.setWindowTitle('Example List')
        self.grid = QtWidgets.QGridLayout()
        self.verCombo = QtWidgets.QComboBox()
        self.listView=QtWidgets.QListView()
        self.listViewmodel = QtGui.QStandardItemModel(self.listView)
        self.listView.setModel(self.listViewmodel)

    # Setting options for widgets (placement, size)
    # Установка параметров для виджетов (размещение, размеры)
        self.listView.setModelColumn(2)
        self.grid.addWidget(self.verCombo,0,0,1,3)
        self.grid.addWidget(self.listView, 2, 0, 3, 3)

    # Setting actions for widgets
    # Установка действий для виджетов
        self.listView.clicked[QtCore.QModelIndex].connect(self.on_clicked)
        self.verCombo.activated[str].connect(self.onverComboActivated)

    # Setting statuses, texts, etc. for widgets at start
    # Установка статусов, текстов и прочего для виджетов на старте
        self.verCombo.addItem("1 - NO CKECKBOXES")
        self.verCombo.addItem("2 - WITH CKECKBOXES")
        self.verCombo.setCurrentIndex(0)

    # This piece of code determines whether multiple items can be selected on a ListView.
    # Этот кусочек кода определяет, можно ли выбирать несколько элементов на ListView.
        if self.verCombo.currentIndex() + 1 == 1:
            self.listView.setSelectionMode(
                QtWidgets.QAbstractItemView.ExtendedSelection
            )
            #self.show_hide_ckeckinlistView(FType=1)
        else:
            self.listView.setSelectionMode(
                QtWidgets.QAbstractItemView.SingleSelection
            )

        self.addrowinlistView(
            'Cookie dough',  # Must be store-bought
            'Hummus',  # Must be homemade
            'Spaghetti',  # Must be saucy
            'Dal makhani',  # Must be spicy
            'Chocolate whipped cream'  # Must be plentiful
        )

        self.BaseWidget.setLayout(self.grid)
        chechAllSelected_resulr1, chechAllSelected_resulr2, chechAllSelected_resulr3, chechAllSelected_resulr4 = self.chechAllSelected()
        self.BaseWidget.show()

    # Procedure for determining those items that are highlighted
    # The procedure should work both in the situation of the list with checkmarks, and without them
    # Процедура для определения тех элементов, которые выделены
    # Процедура должна работать как в ситуации списка с галочками, так и без них
    def chechAllSelected (self):
        SelectedList=[]
        list_of_indexes_selectedLayers=[]
        list_of_texts_selectedLayers=[]
        Items_list=[]
        #item = self.listView.itemFromIndex()
        selectedLayers = self.listView.selectedIndexes()

        # CUT FOR A SHEET WITHOUT TYPES
        # ОТЛАВЛИВАЕМ ДЛЯ ЛИСТА БЕЗ ГАЛОЧЕК
        if self.verCombo.currentIndex()+1==1:
            print ("Here when checking")
            for i in selectedLayers:
                item = self.listViewmodel.itemFromIndex(i)
                Items_list.append(item)
                list_of_indexes_selectedLayers.append(item.index().row())
            list_of_indexes_selectedLayers.sort()
            for i in range(len(list_of_indexes_selectedLayers)):
                SelectedList.append(int(list_of_indexes_selectedLayers[i]))
                item = self.listViewmodel.itemFromIndex(
                    self.listViewmodel.index(int(list_of_indexes_selectedLayers[i]), 0))
                list_of_texts_selectedLayers.append(item.text())
            print("List: ", list_of_indexes_selectedLayers, " ", list_of_texts_selectedLayers, " ", Items_list)

        # CUT FOR A SHEET WITH TIPS
        # ОТЛАВЛИВАЕМ ДЛЯ ЛИСТА С ГАЛОЧКАМИ
        else:
            for i in range(self.listViewmodel.rowCount()):
                if self.listViewmodel.item(i).checkState():
                    SelectedList.append(i)
        if len(SelectedList)==0: res_chechAllSelected=0
        if 0<len(SelectedList)<self.listViewmodel.rowCount(): res_chechAllSelected=1
        if 0<len(SelectedList) == self.listViewmodel.rowCount(): res_chechAllSelected = 2

        print ("In chechAllSelected:", len(SelectedList)," ", self.listViewmodel.rowCount()," ", res_chechAllSelected, " ", SelectedList)
        return len(SelectedList), self.listViewmodel.rowCount(), res_chechAllSelected, SelectedList


    # Function for entering values in ListView (any values, lists)
    # Функция ввода значений в ListView (любые значения, списки)
    def addrowinlistView(self,*rowsforadd):
        for i in rowsforadd:
            # Create an item with a caption
            item = QtGui.QStandardItem(i)
            # Add a checkbox to it
            #item.setCheckState(True)
            # generate a list for random selection
            # генерируем список для случайного выбора
            Chous_for_random = [0, 2] 
            if self.verCombo.currentIndex() + 1 == 1:
                #print("индекс переключателя: ",self.verCombo.currentIndex() + 1)
                # whether to tick the item
                # ставить ли галочку около элемента
                item.setCheckable(False)
                self.listViewmodel.appendRow(item)
                if random.choice(Chous_for_random)==2:
                    index = self.listViewmodel.indexFromItem(item)
                    sm = self.listView.selectionModel()
                    sm.select(index, QtCore.QItemSelectionModel.Select)
            else:
                # whether to tick the item
                # ставить ли галочку около элемента
                item.setCheckable(True)
                # set the status depending on the selected number
                # ставим статус в зависимости от выбранного числа
                item.setCheckState(random.choice(Chous_for_random))
                self.listViewmodel.appendRow(item)
            # Add the item to the model
            # Добавляем элемент в модель
            #self.listViewmodel.appendRow(item)
            #self.BaseWidget.listViewmodel.appendRow(item)

    def on_clicked(self, index):
        item = self.listViewmodel.itemFromIndex(index)
        myitem=QtWidgets.QListWidgetItem()
        #print (("on_clicked: itemIndex='{}', itemText='{}'"
        #        .format(item.index().row(), item.text())))
        if self.verCombo.currentIndex()+1==1:
            # print(item.index().row())
            pass
        else:
            print("""This position: """, int(item.index().row()))
            chechAllSelected_resulr1, chechAllSelected_resulr2, chechAllSelected_resulr3, chechAllSelected_resulr4 = self.chechAllSelected()
            self.StartList = chechAllSelected_resulr4
            if self.listViewmodel.item(item.index().row()).checkState():
                item.setCheckState(0)
                self.StartList.remove(item.index().row())
            else:
                item.setCheckState(2)
                self.StartList.append(item.index().row())
        print("Here")
        chechAllSelected_resulr1, chechAllSelected_resulr2, chechAllSelected_resulr3, chechAllSelected_resulr4 = self.chechAllSelected()
        #print("Here")
        #self.on_chechBox_click(FType=False, FClick=0, FStatus=chechAllSelected_resulr3)
        #self.chechAllSelected()
        #self.listViewmodel.removeRow(item.index().row())

    # mode switching (with / without checkmarks) with the removal of the function to remove / show checkmarks
    # перевлючение режима (с галочками / без) с вывозом функции убрать / показать галочки
    def onverComboActivated(self, text):
        self.verCombo.setCurrentText(text)
        len_SelectedList, listViewmodel_rowCount, res_chechAllSelected, SelectedLis = self.chechAllSelected()
        print ("This point: ", len_SelectedList," ", listViewmodel_rowCount," ", res_chechAllSelected," ", SelectedLis)
        self.show_hide_ckeckinlistView(
            self.verCombo.currentIndex(),
            listViewmodel_rowCount,
            SelectedLis
        )
        print(self.verCombo.currentText())

        # print(self.verCombo.currentText()," индекс = ", self.verCombo.currentIndex())
        # self.chechAllSelected ()

if __name__ == "__main__":
    app = HelloApplication(sys.argv)
    sys.exit(app.exec_())

Solution

  • QAbstractItemView Class

    selectionMode : SelectionMode

    This property holds which selection mode the view operates in This property controls whether the user can select one or many items and, in many-item selections, whether the selection must be a continuous range of items.


    QAbstractItemView::ExtendedSelection

    When the user selects an item in the usual way, the selection is cleared and the new item selected. However, if the user presses the Ctrl key when clicking on an item, the clicked item gets toggled and all other items are left untouched. If the user presses the Shift key while clicking on an item, all items between the current item and the clicked item are selected or unselected, depending on the state of the clicked item. Multiple items can be selected by dragging the mouse over them.

    Try it:

    headline = """ 
    ###############################################################################
    #                                    Program                                  #
    #                     a small ListView application in PyQt                    #
    ###############################################################################
    """
    
    import sys
    import random
    from PyQt5 import QtWidgets, QtGui, QtCore                    #  , Qt
    
    class HelloApplication(QtWidgets.QWidget):                    #QApplication):
        def __init__(self):
            super().__init__()
            self.addWidgets()
    
        def addWidgets(self):
            self.checkCalc  = 0
            self.StartList  = []
    #        self.BaseWidget = QtWidgets.QWidget()
            self.setWindowTitle('Example List')
            
            self.grid = QtWidgets.QGridLayout()
            self.verCombo = QtWidgets.QComboBox()
            self.listView = QtWidgets.QListView()
            
    # +++   
            self.listView.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)     # +++
            
            self.listViewmodel = QtGui.QStandardItemModel(self.listView)
            self.listView.setModel(self.listViewmodel)
    
            self.listView.setModelColumn(2)
            self.grid.addWidget(self.verCombo, 0, 0, 1, 3)
            self.grid.addWidget(self.listView, 2, 0, 3, 3)
    
            self.listView.clicked[QtCore.QModelIndex].connect(self.on_clicked)
            self.verCombo.activated[str].connect(self.onverComboActivated)
    
            self.verCombo.addItem("1 - NO edit CKECKBOXES")
            self.verCombo.addItem("2 - WITH edit CKECKBOXES")
            self.verCombo.setCurrentIndex(0)
    
            self.addrowinlistView(
                'Cookie dough',            # Must be store-bought
                'Hummus',                  # Must be homemade
                'Spaghetti',               # Must be saucy
                'Dal makhani',             # Must be spicy
                'Chocolate whipped cream'  # Must be plentiful
            )
    
            self.setLayout(self.grid)
            
            chechAllSelected_resulr1, \
            chechAllSelected_resulr2, \
            chechAllSelected_resulr3, \
            chechAllSelected_resulr4 = self.chechAllSelected()
    
    
        def chechAllSelected (self):
            SelectedList = []
            list_of_indexes_selectedLayers = []
            list_of_texts_selectedLayers = []
            Items_list = []
            #item = self.listView.itemFromIndex()
            selectedLayers = self.listView.selectedIndexes()
    
            if self.verCombo.currentIndex()+1 == 1:
                print ("Here for check")
                for i in selectedLayers:
                    item = self.listViewmodel.itemFromIndex(i)
                    Items_list.append(item)
                    list_of_indexes_selectedLayers.append(item.index().row())
                list_of_indexes_selectedLayers.sort()
                for i in range(len(list_of_indexes_selectedLayers)):
                    SelectedList.append(int(list_of_indexes_selectedLayers[i]))
                    item = self.listViewmodel.itemFromIndex(
                        self.listViewmodel.index(int(list_of_indexes_selectedLayers[i]), 0))
                    list_of_texts_selectedLayers.append(item.text())
                print("List: ", list_of_indexes_selectedLayers, " ", list_of_texts_selectedLayers, " ", Items_list)
    
            else:
                for i in range(self.listViewmodel.rowCount()):
                    if self.listViewmodel.item(i).checkState():
                        SelectedList.append(i)
            if len(SelectedList)==0:                                 res_chechAllSelected = 0
            if 0<len(SelectedList)<self.listViewmodel.rowCount():    res_chechAllSelected = 1
            if 0<len(SelectedList) == self.listViewmodel.rowCount(): res_chechAllSelected = 2
    
            print ("В модуле chechAllSelected:", len(SelectedList)," ", self.listViewmodel.rowCount()," ", res_chechAllSelected, " ", SelectedList)
    
            return len(SelectedList), self.listViewmodel.rowCount(), res_chechAllSelected, SelectedList
    
    
        def addrowinlistView(self, *rowsforadd):
            for i in rowsforadd:
                # Create an item with a caption
                item = QtGui.QStandardItem(i)
                # Add a checkbox to it
               
                item.setCheckState(True)                                               # +
                
                Chous_for_random = [0, 2]
                if self.verCombo.currentIndex() + 1 == 1:
                    #print("индекс переключателя: ",self.verCombo.currentIndex() + 1)
                    item.setCheckable(False)
                    self.listViewmodel.appendRow(item)
                    if random.choice(Chous_for_random)==2:
                        index = self.listViewmodel.indexFromItem(item)
                        sm = self.listView.selectionModel()
                        sm.select(index, QtCore.QItemSelectionModel.Select)
                else:
                    item.setCheckable(True)
                    item.setCheckState(random.choice(Chous_for_random))
                    self.listViewmodel.appendRow(item)
                    # Add the item to the model
                #self.listViewmodel.appendRow(item)
                #self.BaseWidget.listViewmodel.appendRow(item)
    
        def on_clicked(self, index):
            item   = self.listViewmodel.itemFromIndex(index)
            print(f"\nitem={item.text()}, index={index.row()}\n" )
            myitem = QtWidgets.QListWidgetItem()
            #print (("on_clicked: itemIndex='{}', itemText='{}'"
            #        .format(item.index().row(), item.text())))
            if self.verCombo.currentIndex()+1 == 1:
                # print(item.index().row())
                pass
            else:
                print("This position: ", int(item.index().row()))
                chechAllSelected_resulr1, chechAllSelected_resulr2, chechAllSelected_resulr3, chechAllSelected_resulr4 = self.chechAllSelected()
                self.StartList = chechAllSelected_resulr4
                if self.listViewmodel.item(item.index().row()).checkState():
                    item.setCheckState(0)
                    self.StartList.remove(item.index().row())
                else:
                    item.setCheckState(2)
                    self.StartList.append(item.index().row())
            print("Now here")
            chechAllSelected_resulr1, chechAllSelected_resulr2, chechAllSelected_resulr3, chechAllSelected_resulr4 = self.chechAllSelected()
            #print("Now here")
            #self.on_chechBox_click(FType=False, FClick=0, FStatus=chechAllSelected_resulr3)
            #self.chechAllSelected()
            #self.listViewmodel.removeRow(item.index().row())
    
        def onverComboActivated(self, text):
            self.verCombo.setCurrentText(text)
            len_SelectedList, listViewmodel_rowCount, res_chechAllSelected, SelectedLis = self.chechAllSelected()
            print ("\nFor print: \n\tlen_SelectedList = {}; \n\tlistViewmodel_rowCount = {};\
                    \n\tres_chechAllSelected = {}; \n\tSelectedLis = {}" 
                   "".format(len_SelectedList, listViewmodel_rowCount, res_chechAllSelected, SelectedLis))
    
    # ?        self.show_hide_ckeckinlistView(
    #            self.verCombo.currentIndex(),
    #            listViewmodel_rowCount,
    #            SelectedLis
    #        )
            
            print(self.verCombo.currentText())
    
            # print(self.verCombo.currentText()," индекс = ", self.verCombo.currentIndex())
            # self.chechAllSelected ()
    
        """ ??????????????????????????????????????????????????
        def on_clicked(self, index):
            item = self.listViewmodel.itemFromIndex(index)
            myitem=QtWidgets.QListWidgetItem()
            #print (("on_clicked: itemIndex='{}', itemText='{}'"
            #        .format(item.index().row(), item.text())))
            if self.verCombo.currentIndex()+1==1:
                # print(item.index().row())
                pass
            else:
                print("This position: ", int(item.index().row()))
                chechAllSelected_resulr1, chechAllSelected_resulr2, chechAllSelected_resulr3, chechAllSelected_resulr4 = self.chechAllSelected()
                self.StartList = chechAllSelected_resulr4
                if self.listViewmodel.item(item.index().row()).checkState():
                    item.setCheckState(0)
                    self.StartList.remove(item.index().row())
                else:
                    item.setCheckState(2)
                    self.StartList.append(item.index().row())
            print("Now here")
            #chechAllSelected_resulr1, chechAllSelected_resulr2, chechAllSelected_resulr3, chechAllSelected_resulr4 = self.chechAllSelected()
            print("Now here")
            #self.on_chechBox_click(FType=False, FClick=0, FStatus=chechAllSelected_resulr3)
            #self.chechAllSelected()
            #self.listViewmodel.removeRow(item.index().row())
        """
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        w = HelloApplication()
        w.show()
        sys.exit(app.exec_())
    

    enter image description here

    enter image description here