Изменение названия колонок в QTableView

Пример кода, в который требуется задать свойство позволяющее изменять названия колонок.

# Импортируем соответствующие библиотеки
import sys
from PyQt5 import QtWidgets, QtCore, QtGui


class MyTableModel(QtCore.QAbstractTableModel):
    def __init__(self, data=[[]], headers=[], parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)  # Родительский конструктор

        # Атрибуты для хранения данных
        self.__data = data  # Для данных
        self.__headers = headers  # Для заголовков

    # Задаем заголовки
    def headerData(self, section, orientation, role):
        if role == QtCore.Qt.DisplayRole:  # Проверяем есть ли ячейка для отображения данных
            if orientation == QtCore.Qt.Horizontal:  # Если это загловки  столбцов

                # для ошибки index is out of range
                if section < len(self.__headers):
                    return self.__headers[section]  # То задаем список заголовков по индексу
                else:
                    return "Temporary"

            else:  # Иначе  это заголовки строк
                return section + 1  # То задаем значение section - индекс ряда

    # Задаем размеры столбцов и строк для табличного представления------------------------------------
    def rowCount(self, parent):  # Задаем количество строк для представления
        return len(self.__data)

    def columnCount(self, parent):  # Задаем количество столбцов для представления---------------------
        return len(self.__data[0])

    # Системный метод который мы перезаписываем чтобы повлиять на поведение моделей ------------------
    def data(self, index, role):
        # При двойном нажатии на ячейку элемент полностью стирается чтобы предотвратить нужно прменить метод-----------
        if role == QtCore.Qt.EditRole:
            row = index.row()
            column = index.column()
            return self.__data[row][column]  # Определяем позицию элемента в массиве
            # Возвращяем значение из массива в отображение

        # Отображение данных в представлении
        if role == QtCore.Qt.DisplayRole:
            row = index.row()  # Индекс строки
            column = index.column()  # Индекс столбца
            value = self.__data[row][column]  # Получение значения по известным индексам
            return value  # Вернуть в представление

    # Возможность редактрования данных в таблице--------------------------------------------------------
    # Для этого нужны 2 метода flags, setData
    def flags(self, index):
        return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if role == QtCore.Qt.EditRole:  # Если поле редактируемое
            row = index.row()
            column = index.column()
            new_element = value  # Новое значение
            if new_element:  # Проверка новых данных
                self.__data[row][column] = new_element  # Перезапись элемента
                return True  # Успешно

            else:
                return False  # Не успешно

        # =============================================================================#
        # INSERTING & REMOVING  ITEMS IN THE TABLE
        """ Внедрение(размещение)-INSERTING & Удаление REMOVING  элементов
            Важно запомнить что эти методы должны вызвать в себе 2 метода 
            self.beginInsertRows начать размещение 
            self.endInsertRows()
            они испускают сигнал для представления чтобы он мог корректно отобразить данные  для связи между 
            """
        # =============================================================================#

    def insertRows(self, position, rows, parent=QtCore.QModelIndex()):
        """position - куда в структуре данных будем размещать элемент
           rows - сколько рядов мы будем размещать
           parent - пока можно игнорировать, он нужен для иерархиеского представления
        """
        self.beginInsertRows(parent, position, position + rows - 1)
        """При размещении представление должно быть готовым обновить данные и параметры нужны для этого
        QtCore.QModelIndex - Пустой индекс  нужный парметр для корня 
         position - С какого элемента начать  
         position+rows-1 - последний элемент"""

        """Запускаем цикл для размещения произвольного количества элементов"""
        for i in range(rows):
            # У нас есть списковая структура данных, и внее будем все размещать при помощи .insert(2 параметра)
            # 1) Позиция(в списке) 2)Значение

            defaultValues = [i for i in range(1, 4)]  # Генерируем список от 1 до 4 [1,2,3]
            self.__data.insert(position, defaultValues)  # Внедрение в список

        self.endInsertRows()
        return True  # Если все без ошибок то возвращает истина

    # Удаление рядов в таблице=======================================================================================
    def removeRows(self, position, rows, parent=QtCore.QModelIndex()):

        self.beginRemoveRows(parent, position, position + rows - 1)  # Старт процесс удаления
        # Removing here
        for i in range(rows):
            value = self.__data[position]  # Получаем позицию ряда
            self.__data.remove(value)  # Удаляем элемент ряд

        self.endRemoveRows()  # Стоп

        return True

    # Добавление столбцов для таблицы ===================================================================================
    def insertColumns(self, position, columns, parent=QtCore.QModelIndex()):
        self.beginInsertColumns(parent, position, position + columns - 1)
        """self.beginInsertColumns(index, first, last)"""
        # index - parent
        # first - position
        # last - position + columns - 1 = view ожидает 0 образный элемент

        rowCount = len(self.__data)  # Количество рядов в нашем массиве
        for i in range(columns):  # Перебираем Столбцы

            for j in range(rowCount):  # Преребираем Строки
                self.__data[j].insert(position, "new cell")  # Внедряем данные начиная с 0 ой строки

        self.endInsertColumns()
        return True  # Если все без ошибок то добавление рядов успешны

    # Удаление  столбцов из таблицы ================================================================
    def removeColumns(self, position, columns, parent=QtCore.QModelIndex()):
        self.beginRemoveColumns(parent, position, position + columns - 1)  # Старт процесс удаления
        # Removing here

        rowCount = len(self.__data)  # Количество строк

        for i in range(columns):  # Перебираем столбцы   # 1
            for j in range(rowCount):  # Прербираем ряды # 2
                print(self.__data[j])  # ряд
                value = self.__data[j][position]

                self.__data[j].remove(value)

        self.endRemoveColumns()  # Стоп

        return True


#  Мое окно -----------------------------------------------------------------------------------
class MyWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        # данные
        data = [
            ["value", "value", "value"],
            ["value", "value", "value"]
        ]
        # Заголовки
        headers = ["col1", "col2", "col3", ]

        #  Табличное представление
        self.TableView = QtWidgets.QTableView()
        self.TableView.show()

        # Объект из класса MyTableModel============================================
        self.model = MyTableModel(data, headers)

        # Добавление строк=========================================================
        self.model.insertRows(0, 1)
        """1) позиция (индекс ряда) начало удаления
           2)Количество рядов(строк) для добавления"""

        # Удаление строк(рядов) и==============================================
        # self.model.removeRows(0, 1)
        """1) позиция (индекс ряда) начало удаления
           2)Количество рядов(строк) для удаления"""

        # Применяем метод добавление столбцов ==============================================
        self.model.insertColumns(0, 1)

        # Применяем метод удаления столбцов ==============================================
        self.model.removeColumns(0, 1)

        # Кладем модель в представление=============================================

        self.modelheader = QtGui.QStandardItemModel()


# Приложение
app = QtWidgets.QApplication(sys.argv)
win = MyWindow()
sys.exit(app.exec_())

введите сюда описание изображения


Ответы (1 шт):

Автор решения: S. Nick

Если вам действительно нужна помощь, пожалуйста:

  • опишите что вы хотите сделать;
  • что вы попробовали и что у вас не получилось;
  • обязательно приложите минимально-воспроизводимый пример, который демонстрирует вашу проблему.
  • этим вы сэкономите не только свое время, но и время желающих вам помочь.

Как вариант, я предоставлю для вас пример, который показывает, что это возможно.

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.Qt  import *


class HeaderView(QtWidgets.QHeaderView):
    def __init__(self, parent):
        super(HeaderView, self).__init__(QtCore.Qt.Horizontal, parent)

        self.m_labels = []
        self.sectionResized.connect(self.adjustPositions)
        self.sectionCountChanged.connect(self.onSectionCountChanged)
        self.parent().horizontalScrollBar().valueChanged.connect(self.adjustPositions)

    @QtCore.pyqtSlot()
    def onSectionCountChanged(self):
        while self.m_labels:
            label = self.m_labels.pop()
            label.deleteLater()
        for i in range(self.count()):
            label = QtWidgets.QLineEdit(self) 
            label.setStyleSheet("QLineEdit { color: red; font-size: 12px; }")
            self.m_labels.append(label)
            self.update_data()
            self.adjustPositions()

    def setModel(self, model):
        super(HeaderView, self).setModel(model)
        if self.model() is not None:
            self.model().headerDataChanged.connect(self.update_data)

    def update_data(self):
        option = QtWidgets.QStyleOptionHeader()
        self.initStyleOption(option)
        for i, label in enumerate(self.m_labels):
            text = self.model().headerData(
                i, self.orientation(), QtCore.Qt.DisplayRole
            )
            label.setText(str(text))
            pal = label.palette()
            bc = self.model().headerData(
                i, self.orientation(), QtCore.Qt.BackgroundRole
            )
            if bc is None:
                bc = option.palette.brush(QtGui.QPalette.Window)
            pal.setBrush(QtGui.QPalette.Window, bc)

            fc = self.model().headerData(
                i, self.orientation(), QtCore.Qt.ForegroundRole
            )
            if fc is None:
                fc = option.palette.brush(QtGui.QPalette.ButtonText)
            pal.setBrush(QtGui.QPalette.ButtonText, fc)

            label.setPalette(pal)

            textAlignment = self.model().headerData(
                i, self.orientation(), QtCore.Qt.TextAlignmentRole
            )
            if textAlignment is None:
                textAlignment = self.defaultAlignment()
            label.setAlignment(textAlignment)

    def updateGeometries(self):
        super(HeaderView, self).updateGeometries()
        self.adjustPositions()

    @QtCore.pyqtSlot()
    def adjustPositions(self):
        for index, label in enumerate(self.m_labels):
            geom = QtCore.QRect(
                self.sectionViewportPosition(index),
                0,
                self.sectionSize(index),
                self.height(),
            )
            geom.adjust(2, 0, -2, 0)
            label.setGeometry(geom)


class Widget(QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)

        self.tableView = QTableView()

        self.model = QStandardItemModel(4, 4);

        header = HeaderView(self.tableView)
        self.tableView.setHorizontalHeader(header)
        header_labels = ['Heading 1','Heading 2','Heading 3','Heading 4']
        self.model.setHorizontalHeaderLabels(header_labels)        

        for row in range(4):
            for column in range(4):
                item = QStandardItem("row {}, column {} ".format(row, column))
                self.model.setItem(row, column, item)

        self.tableView.setModel(self.model)

        lay = QGridLayout(self)
        lay.addWidget(self.tableView) 


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    w = Widget()
    w.resize(500, 300)
    w.show()
    sys.exit(app.exec_())

введите сюда описание изображения


Update

Выше пример кода, в который требуется задать свойство позволяющее изменять названия колонок.

import sys
from PyQt5 import QtWidgets, QtCore, QtGui


class HeaderView(QtWidgets.QHeaderView):
    def __init__(self, parent):
        super(HeaderView, self).__init__(QtCore.Qt.Horizontal, parent)

        self.m_labels = []
        self.sectionResized.connect(self.adjustPositions)
        self.sectionCountChanged.connect(self.onSectionCountChanged)
        self.parent().horizontalScrollBar().valueChanged.connect(self.adjustPositions)

    @QtCore.pyqtSlot()
    def onSectionCountChanged(self):
        while self.m_labels:
            label = self.m_labels.pop()
            label.deleteLater()
        for i in range(self.count()):
            label = QtWidgets.QLineEdit(self) 
            label.setStyleSheet("QLineEdit { color: red; font-size: 12px; }")
            self.m_labels.append(label)
            self.update_data()
            self.adjustPositions()

    def setModel(self, model):
        super(HeaderView, self).setModel(model)
        if self.model() is not None:
            self.model().headerDataChanged.connect(self.update_data)

    def update_data(self):
        option = QtWidgets.QStyleOptionHeader()
        self.initStyleOption(option)
        for i, label in enumerate(self.m_labels):
            text = self.model().headerData(
                i, self.orientation(), QtCore.Qt.DisplayRole
            )
            label.setText(str(text))
            pal = label.palette()
            bc = self.model().headerData(
                i, self.orientation(), QtCore.Qt.BackgroundRole
            )
            if bc is None:
                bc = option.palette.brush(QtGui.QPalette.Window)
            pal.setBrush(QtGui.QPalette.Window, bc)

            fc = self.model().headerData(
                i, self.orientation(), QtCore.Qt.ForegroundRole
            )
            if fc is None:
                fc = option.palette.brush(QtGui.QPalette.ButtonText)
            pal.setBrush(QtGui.QPalette.ButtonText, fc)

            label.setPalette(pal)

            textAlignment = self.model().headerData(
                i, self.orientation(), QtCore.Qt.TextAlignmentRole
            )
            if textAlignment is None:
                textAlignment = self.defaultAlignment()
            label.setAlignment(textAlignment)

    def updateGeometries(self):
        super(HeaderView, self).updateGeometries()
        self.adjustPositions()

    @QtCore.pyqtSlot()
    def adjustPositions(self):
        for index, label in enumerate(self.m_labels):
            geom = QtCore.QRect(
                self.sectionViewportPosition(index),
                0,
                self.sectionSize(index),
                self.height(),
            )
            geom.adjust(2, 0, -2, 0)
            label.setGeometry(geom)


class MyTableModel(QtCore.QAbstractTableModel):
    def __init__(self, data=[[]], headers=[], parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)  # Родительский конструктор

        # Атрибуты для хранения данных
        self.__data = data  # Для данных
        self.__headers = headers  # Для заголовков

    # Задаем заголовки
    def headerData(self, section, orientation, role):
        if role == QtCore.Qt.DisplayRole:  # Проверяем есть ли ячейка для отображения данных
            if orientation == QtCore.Qt.Horizontal:  # Если это загловки  столбцов

                # для ошибки index is out of range
                if section < len(self.__headers):
                    return self.__headers[section]  # То задаем список заголовков по индексу
                else:
                    return "Temporary"

            else:  # Иначе  это заголовки строк
                return section + 1  # То задаем значение section - индекс ряда

    # Задаем размеры столбцов и строк для табличного представления----------------------
    def rowCount(self, parent):  # Задаем количество строк для представления
        return len(self.__data)

    def columnCount(self, parent):  # Задаем количество столбцов для представления-------
        return len(self.__data[0])

    # Системный метод который мы перезаписываем чтобы повлиять на поведение моделей -----
    def data(self, index, role):
        # При двойном нажатии на ячейку элемент полностью стирается чтобы предотвратить нужно прменить метод
        if role == QtCore.Qt.EditRole:
            row = index.row()
            column = index.column()
            return self.__data[row][column]  # Определяем позицию элемента в массиве
            # Возвращяем значение из массива в отображение

        # Отображение данных в представлении
        if role == QtCore.Qt.DisplayRole:
            row = index.row()  # Индекс строки
            column = index.column()  # Индекс столбца
            value = self.__data[row][column]  # Получение значения по известным индексам
            return value  # Вернуть в представление

    # Возможность редактрования данных в таблице-------------------------------
    # Для этого нужны 2 метода flags, setData
    def flags(self, index):
        return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if role == QtCore.Qt.EditRole:  # Если поле редактируемое
            row = index.row()
            column = index.column()
            new_element = value  # Новое значение
            if new_element:  # Проверка новых данных
                self.__data[row][column] = new_element  # Перезапись элемента
                return True  # Успешно

            else:
                return False  # Не успешно

        # ====================================================================
        # INSERTING & REMOVING  ITEMS IN THE TABLE
        """ Внедрение(размещение)-INSERTING & Удаление REMOVING  элементов
            Важно запомнить что эти методы должны вызвать в себе 2 метода 
            self.beginInsertRows начать размещение 
            self.endInsertRows()
            они испускают сигнал для представления чтобы он мог корректно отобразить данные  для связи между 
            """
        # ==================================================================== 

    def insertRows(self, position, rows, parent=QtCore.QModelIndex()):
        """position - куда в структуре данных будем размещать элемент
           rows - сколько рядов мы будем размещать
           parent - пока можно игнорировать, он нужен для иерархиеского представления
        """
        self.beginInsertRows(parent, position, position + rows - 1)
        """При размещении представление должно быть готовым обновить данные и параметры нужны для этого
        QtCore.QModelIndex - Пустой индекс  нужный парметр для корня 
         position - С какого элемента начать  
         position+rows-1 - последний элемент"""

        """Запускаем цикл для размещения произвольного количества элементов"""
        for i in range(rows):
            # У нас есть списковая структура данных, и внее будем все размещать при помощи .insert(2 параметра)
            # 1) Позиция(в списке) 2)Значение

            defaultValues = [i for i in range(1, 4)]  # Генерируем список от 1 до 4 [1,2,3]
            self.__data.insert(position, defaultValues)  # Внедрение в список

        self.endInsertRows()
        return True  # Если все без ошибок то возвращает истина

    # Удаление рядов в таблице================================================
    def removeRows(self, position, rows, parent=QtCore.QModelIndex()):

        self.beginRemoveRows(parent, position, position + rows - 1)  # Старт процесс удаления
        # Removing here
        for i in range(rows):
            value = self.__data[position]  # Получаем позицию ряда
            self.__data.remove(value)  # Удаляем элемент ряд

        self.endRemoveRows()  # Стоп

        return True

    # Добавление столбцов для таблицы ========================================
    def insertColumns(self, position, columns, parent=QtCore.QModelIndex()):
        self.beginInsertColumns(parent, position, position + columns - 1)
        """self.beginInsertColumns(index, first, last)"""
        # index - parent
        # first - position
        # last - position + columns - 1 = view ожидает 0 образный элемент

        rowCount = len(self.__data)  # Количество рядов в нашем массиве
        for i in range(columns):  # Перебираем Столбцы

            for j in range(rowCount):  # Преребираем Строки
                self.__data[j].insert(position, "new cell")  # Внедряем данные начиная с 0 ой строки

        self.endInsertColumns()
        return True  # Если все без ошибок то добавление рядов успешны

    # Удаление  столбцов из таблицы ==========================================
    def removeColumns(self, position, columns, parent=QtCore.QModelIndex()):
        self.beginRemoveColumns(parent, position, position + columns - 1)  # Старт процесс удаления
        # Removing here

        rowCount = len(self.__data)  # Количество строк

        for i in range(columns):  # Перебираем столбцы   # 1
            for j in range(rowCount):  # Прербираем ряды # 2
                print(self.__data[j])  # ряд
                value = self.__data[j][position]

                self.__data[j].remove(value)

        self.endRemoveColumns()  # Стоп

        return True


#  Мое окно ------------------------------------------------------------------
class MyWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        # данные
        data = [
            ["value", "value", "value"],
            ["value", "value", "value"]
        ]
        # Заголовки
        headers = ["col1", "col2", "col3", ]

        #  Табличное представление
        self.tableView = QtWidgets.QTableView()
# -        self.tableView.show()

# + vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
        header = HeaderView(self.tableView)
        self.tableView.setHorizontalHeader(header)
#        header_labels = ['Heading 1','Heading 2','Heading 3']
        self.model = MyTableModel(data, headers)
# + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^       

        # Объект из класса MyTableModel=======================================
#        self.model = MyTableModel(data, headers)

        # Добавление строк====================================================
        self.model.insertRows(0, 1)
        """1) позиция (индекс ряда) начало удаления
           2)Количество рядов(строк) для добавления"""

        # Удаление строк(рядов) и==============================================
        # self.model.removeRows(0, 1)
        """1) позиция (индекс ряда) начало удаления
           2)Количество рядов(строк) для удаления"""

        # Применяем метод добавление столбцов ================================
        self.model.insertColumns(0, 1)

        # Применяем метод удаления столбцов ==================================
        self.model.removeColumns(0, 1)

        # Кладем модель в представление=======================================
# ?        self.modelheader = QtGui.QStandardItemModel()        

# + vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
        self.tableView.setModel(self.model)
        lay = QtWidgets.QGridLayout(self)
        lay.addWidget(self.tableView) 
# + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^       


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    win = MyWindow()
    win.show()                                                                  # +++
    sys.exit(app.exec_())

введите сюда описание изображения

→ Ссылка