Уведомления

Группа в Telegram: @pythonsu
  • Начало
  • » GUI
  • » PyQT4 | Ломаются индексы в QTableWidget после сортировки [RSS Feed]

#1 Янв. 5, 2019 13:40:57

Kyrym
Зарегистрирован: 2016-12-28
Сообщения: 225
Репутация: +  3  -
Профиль   Отправить e-mail  

PyQT4 | Ломаются индексы в QTableWidget после сортировки

Есть таблица QTableWidget с данными.
Выполняя клик по строке таблицы, получаю индекс строки, а данные строки появляются в полях формы. Если я сделаю сортировку по нажатию на заголовки столбцов, то кликая по таблице, индексы строк будут левые, и в поля соответственно вставляются не те данные.
Я читал, то в такой ситуации помогает следующий метод:
перед вставкой строки в таблицу делать “self.table.setSortingEnabled(False)”, а после “self.table.setSortingEnabled(True)”. Однако в таком случае, сортировка работает вообще не пойми как.

 # Python 3
# -*- coding: utf-8 -*-
import sys, copy, pickle, os
from PyQt4 import QtCore, QtGui
from PyQt4.QtGui import (QWidget, qApp, QAction, QApplication, QHBoxLayout, QVBoxLayout,
                             QGridLayout, QLabel, QLineEdit, QTextEdit, QPushButton, QComboBox,
                             QCheckBox, QRadioButton, QFrame, QScrollArea, QTabWidget, QSizePolicy,
                             QGroupBox, QFileDialog)
from PyQt4.QtGui import (QTableWidget, QHeaderView, QAbstractItemView, QTableWidgetItem)
from PyQt4.QtGui import QIcon, QPixmap, QPalette, QTextCursor, QBrush, QColor
from PyQt4.QtCore import QSize
PyQT = 4
# ЦВЕТА ПОЛЕЙ
sss_vivod = ("background-color: #456173; color: #f2f2f0; font: 10pt 'Courier New'")
sss = ("background-color: #456173; color: #f2f2f0; font: 10pt 'Arial'")
sss_err = ("background-color: #456173; color: #ff6161; font: bold 10pt 'Courier New'")
# ПУТИ
path_to_script = os.path.dirname(os.path.abspath(__file__))
sys.path.append(path_to_script)
path_to_file_db = os.path.join(path_to_script, 'database5.pkl')
# ГРАФИКА
class Window(QWidget): 
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        
        self.setMinimumSize(400, 600) # Ширина и высота окна
        self.resize(600, 800) # шир / выс окна
        self.setWindowTitle('QTableWidget') # Заголовок
        self.setWindowIcon(QIcon('icon.png')) # Иконка   
        
        # ПЕРЕМЕННЫЕ
        self.db_tb = []
        self.read_db()
        
        self.columnName = ["Первый", "Второй", "Третий", "Четвёртый"] # заголовки табл
        self.rowCount = len(self.db_tb) # число строк
        self.columnCount = len(self.columnName) # число столбцов
        self.rowHeight = 20 # высота строки            
        # БЛОК РАЗМЕТКИ
        vbox_os = QVBoxLayout() # Создали объект вертикальный контейнер
        grid = QGridLayout() # создание сетки
        grid.setSpacing(5)
        # >>> ИСХОДНЫЕ ДАННЫЕ
        self.pole_1 = QLineEdit('')
        self.pole_1.setStyleSheet(sss)
        grid.addWidget(self.pole_1, 0,0)
        # ---
        self.pole_2 = QLineEdit('')
        self.pole_2.setStyleSheet(sss)
        grid.addWidget(self.pole_2, 0,1)
        # ---
        self.pole_3 = QLineEdit('')
        self.pole_3.setStyleSheet(sss)
        grid.addWidget(self.pole_3, 0,2)
        # ---
        self.pole_4 = QLineEdit('')
        self.pole_4.setStyleSheet(sss)
        grid.addWidget(self.pole_4, 0,3)
        # ---
        self.button_prnt = QPushButton('Принт ДБ')     
        self.button_prnt.clicked.connect(self.on_prnt)
        grid.addWidget(self.button_prnt, 1,0)
        # ---
        self.button_add = QPushButton('Добавить в табл.')     
        self.button_add.clicked.connect(self.on_add_row)
        grid.addWidget(self.button_add, 1,1)
        # ---
        self.button_del_row = QPushButton('Удалить стр')
        self.button_del_row.clicked.connect(self.on_del_row)
        grid.addWidget(self.button_del_row, 1,2)
        # ---
        self.button_save_db = QPushButton('Сохранить БД')     
        self.button_save_db.clicked.connect(self.save_in_file)
        grid.addWidget(self.button_save_db, 1,3)
        # --- ---
        self.button_edit_row = QPushButton('Редактировать стр')     
        self.button_edit_row.clicked.connect(self.on_edit_row)
        grid.addWidget(self.button_edit_row, 2,0)
        # ---
        self.button_save_row = QPushButton('Сохранить стр')     
        self.button_save_row.clicked.connect(self.on_save_row)
        grid.addWidget(self.button_save_row, 2,1)
        # ---
        self.button_up_row = QPushButton('Вверх стр')     
        self.button_up_row.clicked.connect(self.on_up_row)
        grid.addWidget(self.button_up_row, 2,2)
        # ---
        self.button_down_row = QPushButton('Вниз стр')     
        self.button_down_row.clicked.connect(self.on_down_row)
        grid.addWidget(self.button_down_row, 2,3)
        self.polya = [self.pole_1,self.pole_2,self.pole_3,self.pole_4]
        # >>> КОНЕЦ: ИСХОДНЫЕ ДАННЫЕ
        vbox_os.addLayout(grid)
        # ---
        self.table = QTableWidget() # Таблица
        vbox_os.addWidget(self.table) # Таблица 1                        
        # ---
        self.lbl_status = QLabel('')
        self.lbl_status.setStyleSheet(sss_err)
        vbox_os.addWidget(self.lbl_status)
        # ---
        self.pole_vivod = QTextEdit()
        self.pole_vivod.setStyleSheet(sss_vivod)
        #vbox_os.addWidget(self.pole_vivod)
        # ---
        
        self.setLayout(vbox_os) # установка рабочей области
    
    # АВТОЗАПУСК
        self.createTable(self.columnName, self.rowCount, self.columnCount, self.rowHeight)        
    def read_db(self):
        try: # если файл существует
            with open(path_to_file_db, 'rb') as F: # открываем файл
                try:
                    self.db_tb = pickle.load(F) # читаем содержимое в переменную
                except EOFError: # если файл пустой
                    self.db_tb = []
        except FileNotFoundError: # если файл не существует
            F = open(path_to_file_db, 'wb') # создаём пустой файл 
            F.close()
            self.db_tb = [] # в файле нет данных
    def createTable(self, columnName, rowCount, columnCount, rowHeight):
        # создание таблицы
        '''создаем строки и столбцы в таблице
        columnName - подписи шапки таблицы
        rowCount - количество строк таблицы
        columnCount - количество столбцов таблицы
        rowHeight - высота строки'''
        
        # Режим растяжения таблицы по вертикали и горизонтали
        if PyQT == 4:
            self.table.verticalHeader().setResizeMode(QtGui.QHeaderView.Fixed)
            self.table.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
        elif PyQT == 5:
            self.table.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
            self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        
        # Режим выделения. Выделяем только строки. Выделяем только одну строку.
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        
        # Стилизуем шапку таблицы
        #self.table.horizontalHeader().setStyleSheet("QHeaderView::section{font-weight:bold; color:#46647F; height:26px}");
                
        # self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) # Запрет редактирования таблицы
        self.table.setEditTriggers(QAbstractItemView.CurrentChanged) # выделение элемента
        self.table.setEditTriggers(QAbstractItemView.DoubleClicked)
        
        self.table.setRowCount(rowCount) # Устанавливаем количество строк
        self.table.setColumnCount(columnCount) # Устанавливаем количество столбцов
        self.table.setSortingEnabled(True) # сортировка - клик по заголовку столбца
                
        i = 0 # формируем подписи шапки:
        for name in columnName:
            item = QTableWidgetItem()
            item.setText(name)
            self.table.setHorizontalHeaderItem(i,item)
            i+=1
            
        # Устанавливаем высоту строк
        for i in range(0, rowCount):
            self.table.setRowHeight(i, rowHeight)
            
        self.table.setColumnWidth(2, 50)
        
        # СИГНАЛЫ
        self.table.itemClicked.connect(self.on_edit_row)
        # АВТОЗАПУСК
        self.on_start_tb()
    
    # ЛОГИКА
    
    def on_start_tb(self):
        #print('start  ',self.db_tb)
        self.table.blockSignals(1) # блокировка сигналов (True)
        for i in range(0,self.rowCount): # вставить базу данных в таблицу
            for j in range(0,self.columnCount):
                self.db_in_cell_tabl(i,j)
        self.table.blockSignals(False) # отмена блокировки сигналов
        
    def on_add_row (self): # добавить строку в базу
        # сбор данных для 1 строки
        db_tb_i = dict(zip(self.columnName, [polya.text() for polya in self.polya]))
        # конец: сбор данных 
        
        # -------
        category = db_tb_i["Первый"]
        # список категории + новая в конец:
        lst_category = list(self.db_tb[i]["Первый"] for i in range(len(self.db_tb)))
        #print('lst_category =',lst_category)
        
        # если база пуста
        if len(self.db_tb) == 0:
            row_index = 0
        
        # если такой категории ещё нет
        elif lst_category.count(category) == 0:
            # новую категорию в конец:
            lst_category.append(category)
            # сортируем список
            lst_category_sort = copy.deepcopy(lst_category)
            lst_category_sort.sort()
            #print('lst_category_sort =',lst_category_sort)
            # находим индекс добавленной категории после сортировки:
            row_index = lst_category_sort.index(category)
        
        # если такая категория уже есть:
        else:
            # индекс первого элемента нужной категории:
            row_1_index = lst_category.index(category)
            # число вхождений данной категории в базе:
            n_cat = lst_category.count(category)
            row_index = row_1_index + n_cat 
        # ----
        self.db_tb.insert(row_index, db_tb_i)
        self.rowCount += 1
        #self.table.setSortingEnabled(False)
        self.table.insertRow(row_index)
        self.paste_row(row_index) # строка / текст
       
        #self.on_cart_clear()
        self.on_status(1)
        self.table.scrollTo(self.table.model().index(row_index,0), 3)
        self.table.selectRow(row_index)
        #self.table.setSortingEnabled(True)
        
    def paste_row(self, row): # БД должна быть уже обновлена
        #print('paste_row')
        self.table.blockSignals(True) # блокировка сигналов        
        self.table.setRowHeight(row, self.rowHeight) # высота строки
        for j in range(0,self.columnCount): # в таблицу вставляем значения
            self.db_in_cell_tabl(row,j)
        self.table.blockSignals(False) # отмена блокировки сигналов
         
     
    def db_in_cell_tabl(self, i,j): # из базы данных в ячейку
        #print('db_in_cell_tabl',' i=',i,' j=',j)
        item = QTableWidgetItem()
        #item.setText(str(self.db_tb[i][self.columnName[j]]))
        item.setText(str(self.db_tb[i].setdefault(self.columnName[j],'')))
        #print('self.db_tb[i][self.columnName[j]] =',self.db_tb[i][self.columnName[j]])
        self.table.setItem(i,j,item)
        if j > 0 and j != 5 and j != 6:
            item.setTextAlignment(20)
        
    def on_status(self, x=None):
        if x == 1: # не сохр
            self.lbl_status.setStyleSheet("background-color: #c84361")
        else: # сохр
            self.lbl_status.setStyleSheet("background-color: #33927e")
    def on_up_row (self): # перемещение строки вверх
        pass
            
    def on_down_row (self): # перемещение строки вниз
        pass
   
    def on_del_row (self):
        row_index = self.table.currentRow() # индекс выделенной строки
        del self.db_tb[row_index] # удалить строку в базе
        self.table.removeRow(row_index) # удалить строку в таблице
        self.rowCount -= 1
        self.pole_n_row.setText(str(self.rowCount))
        self.on_status(1)
    def on_edit_row(self): # правка строки в полях ввода
        row_index = self.table.currentRow() # индекс выделенной строки
        db_tb_i = self.db_tb[row_index]
        
        for i in range(0,len(self.polya)): # вставить строку из таблицы в поля
            self.polya[i].setText(db_tb_i[self.columnName[i]])
    def on_save_row(self): # изм строку в полях отправить в таблицу
        # сбор данных для 1 строки
        db_tb_i = dict(zip(columnName, [polya.text() for polya in self.polya]))
        # конец: сбор данных
        
        row_index = self.table.currentRow() # индекс выделенной строки
        self.db_tb[row_index].update(db_tb_i) # обновление словаря
        self.paste_row(row_index,db_tb_i)
        self.clear_polya()
        self.on_status(1)
    def save_in_file(self): # сохранить базу в файл
        with open(path_to_file_db, 'wb') as f:
            pickle.dump(self.db_tb, f)
        self.on_status(0)
    def clear_polya(self): # очистить поля ввода
        for i in range(0,len(self.polya)):
            self.polya[i].clear()
    def on_prnt(self): # вывод БД в Shell и в поле вывода
        for i in range(0,len(self.db_tb)):
            print(i,':',self.db_tb[i],sep='')
# КОНЕЦ
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window() # создаёт экземпляр окна из класса
    window.move(40, 20) # сдвиг окна от верхнего левого угла экрана
    pal = window.palette()
    pal.setBrush(QPalette.Window, QBrush(QColor("#222831")))
    window.setPalette(pal) # передаёт изменёный цвет окну
    window.show() # запускает окно
    sys.exit(app.exec_())


Отредактировано Kyrym (Янв. 5, 2019 14:17:29)

Прикреплённый файлы:
attachment Снимок экрана от 2019-01-05 14-26-15.png (31,5 KБ)

Офлайн

#2 Янв. 5, 2019 14:08:56

Kyrym
Зарегистрирован: 2016-12-28
Сообщения: 225
Репутация: +  3  -
Профиль   Отправить e-mail  

PyQT4 | Ломаются индексы в QTableWidget после сортировки

Файл с базой данных

Прикреплённый файлы:
attachment database5.pkl (574 байта)

Офлайн

#3 Янв. 5, 2019 17:11:08

rami
Зарегистрирован: 2018-01-08
Сообщения: 278
Репутация: +  71  -
Профиль   Отправить e-mail  

PyQT4 | Ломаются индексы в QTableWidget после сортировки

Попробуйте изменить функцию:

     def on_edit_row(self): # правка строки в полях ввода
        db_tb_i = self.table.selectedItems() #выделенная строка
        for i in range(len(self.polya)): # вставить строку из таблицы в поля
            self.polya[i].setText(db_tb_i[i].text())

Офлайн

#4 Янв. 5, 2019 17:48:33

Kyrym
Зарегистрирован: 2016-12-28
Сообщения: 225
Репутация: +  3  -
Профиль   Отправить e-mail  

PyQT4 | Ломаются индексы в QTableWidget после сортировки

rami
Попробуйте изменить функцию:
Это хорошее предложение, однако, этот вариант не подходит: выложенная программа - тестовая, на самом деле, у меня в базе данных есть информация, которая отсутствует в таблице, а выводить её нужно. Я вижу два решения своей задачи: получение правильного индекса, либо использование идентификаторов в колонке таблице, по которым я буду точно находить индекс в базе данных. Как сделать второй вариант, я знаю, но хочу применять первый.

Офлайн

  • Начало
  • » GUI
  • » PyQT4 | Ломаются индексы в QTableWidget после сортировки[RSS Feed]

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version