QStandardItemModel class

1. Main classes:
QStandardItemModel class

(1) Function: A standard data model class based on item data. It usually forms a Model/View structure with QTableView to realize the management of general two-dimensional data. Each item is an object of the QStandardItem class, which is used to store the item's data, font format, alignment and other data of various roles.

QTableView class
(1) function: two-dimensional data table view component, with multiple rows and multiple columns, each basic display unit is a cell, after setting a data model of the QStandardItemModel class through the setModel() function, a cell Display is an item in the QStandardItemModel data model.

QItemSelectionModel
(1) function: the class used to track the cell selection state of the view component. When a cell or multiple cells are selected on the QTableView component, the model index of the selected cell can be obtained through QItemSelectionModel, which is the cell The selection operation provides convenience.

Three types of relationships:
QStandardItemModel is a data model class; QItemSelectionModel needs to set a QStandardItemModel object as a data model; QTableView is an interface view component, which needs to set a QStandardItemModel object as a data model. To achieve convenient item selection operations, you also need to set A QItemSelectionModel class object as the item selection model.

Test case:
Take the following software interface as an example;
insert image description here
test the following functions:
1. Open a plain text file, which is a regular two-dimensional data file, obtain the data of the table header and each row and column through string processing, and import a QStandardItemModel data model.
2. Edit and modify the data of the data model, you can insert rows, add rows, delete rows, and you can directly modify the data content of cells in the QTableView view component.
3. You can set the data of different roles of an item in the data model, set the text alignment, whether it is bold, etc.
4. Obtain the current cell on the view component and the range of the selected cell through QItemSelectionModel, and operate on the selected cell.
5. Display the data content of the data model into the QPlainTextEdit component, display the content of the data model, and check whether the modification made on the view component is synchronized with the data model.
6. Save the modified model data as a text file.

Use of QStandardItemModel
1. Interface initialization
Copy and create the project template mainWindowApp, and the form file is MainWindow.ui.
The key lies in the creation of data models and selection models, as well as the association with view components, the association of signals and slots, and so on.

import sys,os
from PyQt5.QtWidgets import  (QApplication, QMainWindow,
                   QLabel, QAbstractItemView, QFileDialog)
from PyQt5.QtCore import  Qt, pyqtSlot,QItemSelectionModel, QModelIndex
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from ui_MainWindow import Ui_MainWindow

class QmyMainWindow(QMainWindow): 
    def __init__(self, parent=None):
      super().__init__(parent)    #调用父类构造函数,创建窗体
      self.ui = Ui_MainWindow()     #创建UI对象
      self.ui.setupUi(self)       #构造UI界面
      self.setCentralWidget(self.ui.splitter)

      self.__ColCount = 6  #列数=6
      self.itemModel = QStandardItemModel(5,self.__ColCount,self)# 数据模型,10行6列

      self.selectionModel = QItemSelectionModel(self.itemModel) #Item选择模型
      self.selectionModel.currentChanged.connect(self.do_curChanged)

      self.__lastColumnTitle="测井取样"
      self.__lastColumnFlags=(Qt.ItemIsSelectable
                              | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)

      ##tableView设置
      self.ui.tableView.setModel(self.itemModel) #设置数据模型
      self.ui.tableView.setSelectionModel(self.selectionModel)    #设置选择模型

      oneOrMore=QAbstractItemView.ExtendedSelection
      self.ui.tableView.setSelectionMode(oneOrMore) #可多选

      itemOrRow=QAbstractItemView.SelectItems
      self.ui.tableView.setSelectionBehavior(itemOrRow)   #单元格选择
      
      self.ui.tableView.verticalHeader().setDefaultSectionSize(22)#缺省行高
      self.ui.tableView.setAlternatingRowColors(True)   #交替行颜色

      self.ui.tableView.setEnabled(False)  #先禁用tableView
      self.__buildStatusBar()

Create the data model (QStandardItemModel) and selection model (QItemSelectionModel) in the constructor
1. Specify the number of rows and columns of the data model when creating the QStandardItemModel object;
2. Create the QItemSelectionModel object with the QStandardItemModel object as a parameter, so that the data model and the selection model are established 3.
The constructor also associates the currentChanged() signal of the QItemSelectionModel object with the custom slot function do_curChanged();
4. Set the data model and selection model for the interface component, and call setModel(QStandardItemModel) to establish a connection with setSelectionModel(QItemSelectionModel) .
5. To set the selection mode, call the function setSelectionMode (mode enumeration)
6. To create a status bar, call the private function __buildStatusBar()

2. Import data from text files
Some data are saved in plain text format, they have a fixed number of columns, and each column is an item of data, which actually constitutes a two-dimensional data table.
insert image description here
The following is the slot function code for "open file":

##  ==========由connectSlotsByName() 自动连接的槽函数==================        
   @pyqtSlot()  ##“打开文件”
   def on_actOpen_triggered(self):  
   ##        curPath=QDir.currentPath() #获取当前路径
      curPath=os.getcwd()   #获取当前路径
      
      filename,flt=QFileDialog.getOpenFileName(self,"打开一个文件",curPath,
                  "井斜数据文件(*.txt);;所有文件(*.*)")
      if (filename==""):
         return

      self.LabCurFile.setText("当前文件:"+filename)
      self.ui.plainTextEdit.clear()

      aFile=open(filename,'r')
      allLines=aFile.readlines()  #读取所有行,list类型,每行末尾带有 \n
      aFile.close()

      for strLine in allLines:
         self.ui.plainTextEdit.appendPlainText(strLine.strip())

      self.__iniModelFromStringList(allLines)  
      self.ui.tableView.setEnabled(True)  #tableView可用
      self.ui.actAppend.setEnabled(True)  #更新Actions的enable属性
      self.ui.actInsert.setEnabled(True)
      self.ui.actDelete.setEnabled(True)
      self.ui.actSave.setEnabled(True)
      self.ui.actModelData.setEnabled(True)

1. The os module uses the getcwd() function to obtain the current working path ;
2. The QFileDialog class opens the file dialog box through getOpenFileName() to select a file and returns two variables, which are the selected file name (filename) and file filter (flt ) .
3. Open the file Use Python's built-in file opening function open() to open the file in read-only mode, and use the readlines() function to read all the text into a string list at one time. Each line of the list has a newline character \n.
4. Traversing the list, extracting each line for display appendPlainText()
5. The __iniModelFromStringList() function is a private function, which initializes the data model according to the read text content.
The code of the __iniModelFromStringList() function is as follows:

def __iniModelFromStringList(self,allLines):  ##从字符串列表构建模型
      rowCnt=len(allLines) #文本行数,第1行是标题
      self.itemModel.setRowCount(rowCnt-1) #实际数据行数

      headerText=allLines[0].strip() #第1行是表头,去掉末尾的换行符 "\n"
      headerList=headerText.split("\t")      #转换为字符串列表
      self.itemModel.setHorizontalHeaderLabels(headerList)  #设置表头标题

      self.__lastColumnTitle=headerList[len(headerList)-1] # 最后一列表头的标题,即“测井取样”

      lastColNo=self.__ColCount-1  #最后一列的列号
      for i in range(rowCnt-1):  
         lineText=allLines[i+1].strip()  #一行的文字,\t分隔
         strList=lineText.split("\t")    #分割为字符串列表 
         for j in range(self.__ColCount-1):  #不含最后一列
            item=QStandardItem(strList[j])
            self.itemModel.setItem(i,j,item)  #设置模型的item
             
         item=QStandardItem(self.__lastColumnTitle)  #最后一列
         item.setFlags(self.__lastColumnFlags)
         item.setCheckable(True)
         if (strList[lastColNo]=="0"):
            item.setCheckState(Qt.Unchecked)
         else:
            item.setCheckState(Qt.Checked)

         self.itemModel.setItem(i,lastColNo,item) #设置最后一列的item

1. The parameter allLines is a string list composed of all lines of the text file, and each line is a string of allLines list. The first line is the header text, and the data from the second line.
2. len (list) function : to obtain the number of elements in the list, that is, the number of each line of the original text
3. setRowCount (row number) function : to set the list
4. Get the header string headerText from allLines, and then use The str.split() function splits a string into a string list headerList
5. The setHorizontalHeaderLabels (list) function of the QStandardItemModel class : and set it as the header title of the data model
6. QStandardItemModel saves the item data in the form of a two-dimensional table, Each item is a QStandardItem object, and each item corresponds to a cell of the QTableView. The item data can not only store the displayed text, but also store the data of other roles.
7. The last column of the data file is a logical data, which provides a check box when it is displayed on the interface component tableView. This function is called by calling QStandardItem setCheckable(True) function implementation.
8. The setFlags(ItemFlags) function of QStandardItemSome flags of the item can be set, and ItemFlags is a combination of values ​​of the enumeration type Qt.ItemFlag. A private variable self.__lastColumnFlags is defined in the constructor of QmyMainWindow to set the flag of the last column.

3. Data modification
When the interface component tableView is set to editable, double-click a cell to modify its content. For a column that uses a check box, change the check status of the check box to modify the data of the associated item of the cell.

Data modification is for the data model. After the data model is modified, it will be displayed in the tableview.
Such as adding rows, inserting rows, deleting rows.

   @pyqtSlot()   ##在最后添加一行
   def on_actAppend_triggered(self):   
      itemlist=[]    # QStandardItem 对象列表
      for i in range(self.__ColCount-1):  #不包括最后一列
         item=QStandardItem("0")
         itemlist.append(item)
         
      item=QStandardItem(self.__lastColumnTitle) #最后一列
      item.setCheckable(True)
      item.setFlags(self.__lastColumnFlags)
      itemlist.append(item)

      self.itemModel.appendRow(itemlist)  #添加一行
      curIndex=self.itemModel.index(self.itemModel.rowCount()-1,0)
      self.selectionModel.clearSelection()
      self.selectionModel.setCurrentIndex(curIndex,QItemSelectionModel.Select)

   @pyqtSlot()  ##插入一行
   def on_actInsert_triggered(self):   
      itemlist=[]  #  QStandardItem 对象列表
      for i in range(self.__ColCount-1): #不包括最后一列
         item=QStandardItem("0")
         itemlist.append(item)
         
      item=QStandardItem(self.__lastColumnTitle) #最后一列
      item.setFlags(self.__lastColumnFlags)
      item.setCheckable(True)
      item.setCheckState(Qt.Checked)
      itemlist.append(item)

      curIndex=self.selectionModel.currentIndex(); #获取当前选中项的模型索引
      self.itemModel.insertRow(curIndex.row(),itemlist);  #在当前行的前面插入一行
      self.selectionModel.clearSelection()
      self.selectionModel.setCurrentIndex(curIndex,QItemSelectionModel.Select)
        

   @pyqtSlot()   ##删除当前行
   def on_actDelete_triggered(self): 
      curIndex=self.selectionModel.currentIndex()  #获取当前选择单元格的模型索引
      self.itemModel.removeRow(curIndex.row())     #删除当前行

(1) Adding a line
is equivalent to adding an initialized item to the last line of the list, which can be 0 or checked. Each item in the last line forms an itemlist, use the appendRow() function of QStandardItemModel to add a line at the end of the data model
function prototype appendRow(self, items)

The parameter items is a list of QStandardItem type, and an object of QStandardItem type needs to be created for each item of the added row, and then passed to the appendRow() function.

To get the model index of a cell in QStandardItemModel, use its index() function . In the program, get the model index of the cell by passing its row and column numbers.

To select an item through the program, use the corresponding method of the selection model QItemSelectionModel, and the selection operation will be reflected in the associated interface component tableView in time. The **clearSelection() and setCurrentIndex()** functions of the QItemSelectionModel class are used here to complete the functions of clearing the selection and setting the first column of the newly inserted row to be selected.
(2) Insert Row
The function of the "Insert Row" button is to insert a row before the current row, and its implementation code is similar to that of "Add Row".

Use the insertRow() function of QStandardItemModel to insert a row
function prototype insertRow(self, row, items)

The parameter row is a row number, which means to insert a row before the row of this row number. If the row is equal to or greater than the total number of rows, a row will be added at the end. items is a list of type QStandardItem.
(3) Delete Row
The function of the "Delete Row" button is to delete the current row. First, get the model index of the current cell from the selection model, and then get the row number from the model index, and call the removeRow(row) function to delete the specified row .

4. Cell format setting
Each item in the item data model is a QStandardItem object. QStandardItem provides some interface functions to set the font, background color, foreground color, text alignment, icon, etc. of each item.

This example illustrates the formatting of the item data model with text alignment, bold settings.

   def  __setCellAlignment(self, align=Qt.AlignHCenter):
      if (not self.selectionModel.hasSelection()): #没有选择的项
         return
      selectedIndex=self.selectionModel.selectedIndexes()  #模型索引列表
      count=len(selectedIndex)
      for i in range(count):
         index=selectedIndex[i]  #获取其中的一个模型索引
         item=self.itemModel.itemFromIndex(index)    #获取一个单元格的项数据对象
         item.setTextAlignment(align) #设置文字对齐方式
   
   @pyqtSlot()    ##左对齐
   def on_actAlignLeft_triggered(self):  
      self.__setCellAlignment(Qt.AlignLeft | Qt.AlignVCenter)

   @pyqtSlot()    ##中间对齐
   def on_actAlignCenter_triggered(self):  
      self.__setCellAlignment(Qt.AlignHCenter| Qt.AlignVCenter)
        
   @pyqtSlot()    ##右对齐
   def on_actAlignRight_triggered(self):   
      self.__setCellAlignment(Qt.AlignRight | Qt.AlignVCenter)

   @pyqtSlot(bool)   ##字体Bold
   def on_actFontBold_triggered(self,checked):
      if (not self.selectionModel.hasSelection()): #没有选择的项
         return
      selectedIndex=self.selectionModel.selectedIndexes()   #模型索引列表
      count=len(selectedIndex)
      for i in range(count):
         index=selectedIndex[i]     #获取其中的一个模型索引
         item=self.itemModel.itemFromIndex(index)    #获取一个单元格的项数据对象
         font=item.font()
         font.setBold(checked)
         item.setFont(font)

The codes of the three Actions that set the alignment all call the custom **private function __setCellAlignment()** in which the following two functions of QItemSelectionModel are used.

hasSelection() function : returns a bool value indicating whether there is a selected cell.

selectedIndexes() function : returns a list whose elements are of type QModelIndex, including the model indexes of all selected cells. When the interface component tableView is set to multi-selection, multiple cells can be selected.

Use the itemFromIndex(index) function of the QStandardItemModel class to return the QStandardItem object whose model index is index.

5. Save the data as a file.
The data modification on the view component will be automatically updated to the data model. Click the "Model Data" button on the toolbar to display the data content of the data model in the PlainTextEdit component on the right side of the form

   @pyqtSlot()    ##模型数据显示到plainTextEdit里
   def on_actModelData_triggered(self):  
      self.ui.plainTextEdit.clear()
      lineStr=""
      for i in range(self.itemModel.columnCount()-1):  #表头,不含最后一列
         item=self.itemModel.horizontalHeaderItem(i)
         lineStr=lineStr+item.text()+"\t"
      item=self.itemModel.horizontalHeaderItem(self.__ColCount-1) #最后一列
      lineStr=lineStr+item.text()   #表头文字字符串
      self.ui.plainTextEdit.appendPlainText(lineStr)

      for i in range(self.itemModel.rowCount()):
         lineStr=""
         for j in range(self.itemModel.columnCount()-1): #不包括最后一列
            item=self.itemModel.item(i,j)
            lineStr=lineStr+item.text()+"\t"
         item=self.itemModel.item(i,self.__ColCount-1) #最后一列
         if (item.checkState()==Qt.Checked):
            lineStr=lineStr+"1"
         else:
            lineStr=lineStr+"0"
         self.ui.plainTextEdit.appendPlainText(lineStr)

This mainly involves the reading of the header title of the item data model, and the reading of the item data content line by line.

The horizontalHeaderItem() function of QStandardItemModel returns a data item object of the row header, and its function prototype is:

horizontalHeaderItem(self, colNo) -> QStandardItem

The parameter colNo is the column number, and the return value is a QStandardItem object.

The header titles read are separated by **Tab key (/t)** to form a string, which is added to plainTextEdit for display.

The item() function of QStandardItemModel returns the data item in the work area according to the row number and column number, and its function prototype is:

item(self, rowNo, colNo: int = 0) -> QStandardItem

rowNo is the row number, colNo is the column number, and the return value is a QStandardItem object.

The "Save File" button on the toolbar can save the data of the data model as a text file, and the implementation code is as follows:

   @pyqtSlot()  ##保存文件
   def on_actSave_triggered(self): 
##      curPath=QDir.currentPath() #获取当前路径
      curPath=os.getcwd()   #获取当前路径     
      filename,flt=QFileDialog.getSaveFileName(self,"保存文件",curPath,
                  "井斜数据文件(*.txt);;所有文件(*.*)")
      if (filename==""):
         return

      self.on_actModelData_triggered()  #更新数据到plainTextEdit

      aFile=open(filename,'w')  #以写方式打开
      aFile.write(self.ui.plainTextEdit.toPlainText())
      aFile.close()

Here, the slot function on_actModelData_triggered() is first called to display the content of the data model in the component plainTextEdit, and then the **toPlainText()** of QPlainTextEdit is used to export all its content as text and write it into a file.

Guess you like

Origin blog.csdn.net/qq_35412059/article/details/126497192