PySide6 - Delete row in table

Hi
How to remove a row from table(QTableView)?

This is my files
orcamento.ui (I use QT Designer to build part of the my GUI)
ui_orcamento
main.py

orcamento_calcada.csv

After press a button and read CSV file, I need choose what row in table I’ll delete.

I try use model code from page 320 martins’s book.

I miss something in this fucntion remove_item_from_table.

import sys
from PySide6 import QtCore, QtGui, QtWidgets
from PySide6.QtCore import Qt, QPersistentModelIndex
from PySide6.QtWidgets import QMessageBox
from ui_orcamento import Ui_mw_orcamento

import pandas as pd


class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        self._data = data

    def data(self, index, role):
        if role == Qt.DisplayRole:
            return self._data[index.row()][index.column()]
    
    
    def rowCount(self, index):
        # The length of the outer list.
        return len(self._data)
    
    def columnCount(self, index):
        # The following takes the first sub-list, and returns
        # the length (only works if all rows are an equal length)
        return len(self._data[0])


class MainWindow(QtWidgets.QMainWindow, Ui_mw_orcamento):

    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.show()
        
        self.cb_obras.addItems(['Selecione Um Tipo de Obra','ARQUIBANCADA','CALÇADA','DRENAGEM',
                                'ESCADARIA','MURO','PAVIMENTAÇÃO','PRAÇA'])
        self.cb_tipo_obra.addItems(['Reforma', 'Contrução'])
        self.cb_param_calcada.addItems(['...','Meio-Fio', 'Ladrilhio', 'Concreto Polido'])
        #self.cb_param_unidade.addItems(['...','m', 'm²', 'm³'])

        self.cb_obras.setCurrentIndex(0)
        # Connect the currentIndexChanged signal of cb_obras to the changePage slot
        self.cb_obras.currentIndexChanged.connect(self.changePage)
        self.st_parametro_obras.setCurrentIndex(0)

        self.cb_param_calcada.currentIndexChanged.connect(self.auto_complete_und) 
    
        # Connect the button signal to add data to the table
        self.pb_executar.clicked.connect(self.add_item_to_table)

        self.pb_dt_frame.setEnabled(False)
        self.pb_dt_frame.clicked.connect(self.load_data_from_csv)

        # Create a table of Descriptions
        self.tbv_details_calcada

        # Remove item from table
        self.pb_rm_item.clicked.connect(self.remove_item_from_table)

        

    def auto_complete_und(self):
        # Get the current text of cb_param_calcada
        selected_calcada = self.cb_param_calcada.currentText()

        # Clear the current items in cb_param_unidade
        self.cb_param_unidade.clear()

        # Define a dictionary mapping calcada types to their units
        calcada_units = {
            'Meio-Fio': ['m'],
            'Ladrilhio': ['m²'],
            'Concreto Polido': ['m³']
        }

        # Check if the selected calcada type is in the dictionary
        if selected_calcada in calcada_units:
            # Add the corresponding units to cb_param_unidade
            self.cb_param_unidade.addItems(calcada_units[selected_calcada])
            self.le_valor.setFocus()

        # Connect the currentIndexChanged signal of cb_param_calcada to the auto_complete_und slot
        #self.cb_param_calcada.currentIndexChanged.connect(self.auto_complete_und)


    def changePage(self, index):
        # Get the selected item from the combo box
        selected_item = self.cb_obras.currentText()

        # Create a mapping of item names to page names
        page_mapping = {
            'Selecione Um Tipo de Obra':0,
            'ARQUIBANCADA':1,
            'CALÇADA':2,
            'DRENAGEM':3,
            'ESCADARIA':4,
            'MURO':5,
            'PAVIMENTAÇÃO':6,
            'PRAÇA':7
        }

        # Get the page index from the mapping
        page_index = page_mapping.get(selected_item)

        # If a page index was found, show that page
        if page_index is not None:
            self.st_parametro_obras.setCurrentIndex(page_index)


    def add_item_to_table(self):
        #Check if fields are filled
        if self.cb_param_calcada.currentText() == '...' or self.cb_param_unidade.currentText() == '...' or self.le_valor.text() == '':
            # Show a message box to inform the user to fill in all fields
            QMessageBox.warning(self, 'Campos Vazios', 'Favor preencher todos os campos.')
            return

        # Get the values from the controls
        param_calcada = self.cb_param_calcada.currentText()
        param_unidade = self.cb_param_unidade.currentText()
        valor = self.le_valor.text()

        # Add the values to the table
        new_row = (param_calcada, valor, param_unidade)
        # Get the current row count
        current_row_count = self.tb_parametro_calcada.rowCount()
        # Insert a new row at the end
        self.tb_parametro_calcada.insertRow(current_row_count)

        # Set the values for the new row
        for column, data in enumerate(new_row):
            self.tb_parametro_calcada.setItem(current_row_count, column, QtWidgets.QTableWidgetItem(str(data)))

        # Resize the columns to fit the contents
        self.tb_parametro_calcada.resizeColumnsToContents()

        # Clean the controls
        self.cb_param_calcada.setCurrentIndex(0)
        self.cb_param_unidade.setCurrentIndex(0)
        self.le_valor.clear()


        tt_linhas = self.tb_parametro_calcada.rowCount()
        if tt_linhas == 3:
            self.pb_dt_frame.setEnabled(True)
        
        
    def get_table_data_as_dataframe(self):
        # Get the number of rows and columns in the table
        num_rows = self.tb_parametro_calcada.rowCount()
        num_cols = self.tb_parametro_calcada.columnCount()
        # Create an empty list to store the data
        data = []
        # Iterate through the rows and columns of the table
        for row in range(num_rows):
            row_data = []
            for col in range(num_cols):
                # Get the item from the table
                item = self.tb_parametro_calcada.item(row, col)

                # If the item exists, get its text
                if item is not None:
                    row_data.append(item.text())
                else:
                    # If the item is empty, add an empty string
                    row_data.append("")
            # Append the row data to the list
            data.append(row_data)
        # Create a Pandas DataFrame from the data
        df = pd.DataFrame(data, columns=[self.tb_parametro_calcada.horizontalHeaderItem(col).text() for col in range(num_cols)])
        print(df)
        # Return the DataFrame
        #return df

    def load_data_from_csv(self):
        # Read data from CSV file
        csv_df = pd.read_csv('orcamento_calcada.csv')

        # Check that the table view has a model set
        if self.tbv_details_calcada.model() is None:
            # Create a new model and set it for the table view
            self.model = TableModel(csv_df.values.tolist())
            self.tbv_details_calcada.setModel(self.model)

        # Get the model from the table view
        model = self.tbv_details_calcada.model()

        # Create an index object for the root of the model
        index = QtCore.QModelIndex()

        # Insert data into table
        for index, row in csv_df.iterrows():
            new_row = model.rowCount(index)  # Pass the index argument
            model.insertRow(new_row)

        # Resize columns to fit contents
        self.tbv_details_calcada.resizeColumnsToContents()

    def remove_item_from_table(self):

        # Get the selected rows
        if self.tbv_details_calcada.selectionModel().hasSelection():
            print("entrando na parte de deleção de linha")
            indexs = [QPersistentModelIndex(index) for index in self.tbv_details_calcada.selectionModel().selectedRows()]
            for index in indexs:
                self.tbv_details_calcada.model().removeRow(index.row())
                print("Deletando a linha", index.row())
        else:
            print("Nenhuma linha selecionada")



app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
app.exec()

Hi @alexandre welcome to the forum.

The QAbstractTableModlel doesn’t have a built in implementation for removeRow() so you need to implement this yourself. See QAbstractTableModel Class | Qt Core 6.7.1 for details.

Since your data structure is a list of lists, this is fairly easy to do. Add the following method on your custom model implementation.

def removeRow(self, row):
    self.beginRemoveRows(QModelIndex(), row, row)
    del self._data[row]
    self.endRemoveRows()

The beginRemoveRows call (and end..) are needed to notify the view of the change.

Hi @martin, work like charm.
Thank you!!