Альтернатива методу setSortingEnabled(True)
У меня есть таблица QTableWidget основанная на этой базе данных, созданная с помощью PyQT5.
Мне нужно как-то отсортировывать столбцы, но при использовании self.tableWidget.setSortingEnabled(True), при сортировки чисел выходит такое:
1, 10, 100, 1000, 10000, ...
Как сделать так, чтобы все сортировалось нормально, по возрастанию/убыванию.
UI-файл, нужный для загрузки интерфейса:
import sqlite3
import sys
# from time import sleep
from PyQt5.QtCore import Qt
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QMainWindow, QTableWidgetItem
class MyWidget(QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("Project_main.ui", self)
#self.dialog_delete = uic.loadUi("Project_Delete.ui")
#self.dialog_add = uic.loadUi("Project_Add.ui")
self.setFixedSize(self.size())
self.clearButton.clicked.connect(self.clear_bd)
self.AlphabetSortButton.clicked.connect(self.alphabet_sort)
self.AntiAlphabetSortButton.clicked.connect(self.anti_alphabet_sort)
self.returnButton.clicked.connect(self.main_bd)
self.deleteButton.clicked.connect(self.delete_record)
self.addButton.clicked.connect(self.add_record)
self.SerchPushButton.clicked.connect(self.update_result)
self.con = sqlite3.connect("films_db.sqlite")
self.tableWidget.itemChanged.connect(self.item_changed)
self.modified = {}
self.titles = None
self.main_bd()
self.tableWidget.setSortingEnabled(True)
def keyPressEvent(self, event):
if event.key() == Qt.Key_Enter:
self.update_result()
def anti_alphabet_sort(self):
self.QTableWidget.sortItems(self.QtCore.Qt.AscendingOrder, 0)
def alphabet_sort(self):
self.QTableWidget.sortItems(0, self.QtCore.Qt.AscendingOrder)
def add_record(self):
# self.dialog_add.show()
pass
def delete_record(self):
# self.dialog_delete.show()
pass
def clear_bd(self):
self.tableWidget.setRowCount(0)
self.tableWidget.setColumnCount(0)
def main_bd(self):
cur = self.con.cursor()
result = cur.execute("select * from films").fetchall()
self.tableWidget.setRowCount(len(result))
self.tableWidget.setColumnCount(len(result[0]))
self.titles = [description[0] for description in cur.description]
for i, elem in enumerate(result):
for j, val in enumerate(elem):
self.tableWidget.setItem(i, j, QTableWidgetItem(str(val)))
def update_result(self):
cur = self.con.cursor()
# Получили результат запроса, который ввели в текстовое поле
result = cur.execute("SELECT * FROM films WHERE title like '%" +
(item_title := self.lineEdit_search.text()) + "%'", ).fetchall()
# Заполнили размеры таблицы
self.tableWidget.setRowCount(len(result))
# Если запись не нашлась, то не будем ничего делать
if not result:
self.statusBar().showMessage('Ничего не нашлось')
self.tableWidget.setRowCount(0)
self.tableWidget.setColumnCount(0)
return
else:
self.statusBar().showMessage(f"Нашлась запись с названием - {item_title}")
self.tableWidget.setColumnCount(len(result[0]))
self.titles = [description[0] for description in cur.description]
# Заполнили таблицу полученными элементами
for i, elem in enumerate(result):
for j, val in enumerate(elem):
self.tableWidget.setItem(i, j, QTableWidgetItem(str(val)))
self.modified = {}
def item_changed(self, item):
self.modified[self.titles[item.column()]] = item.text()
def save_results(self):
if self.modified:
cur = self.con.cursor()
que = "UPDATE films SET\n"
que += ", ".join([f"{key}='{self.modified.get(key)}'"
for key in self.modified.keys()])
que += "WHERE title = ?"
print(que)
cur.execute(que, (self.SearchPushButton.text(),))
self.con.commit()
self.modified.clear()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MyWidget()
ex.show()
sys.exit(app.exec())
Ответы (2 шт):
Я не могу проверить ваш пример, но я покажу вам возможную реализацию вашей задачи.
Класс
QStyledItemDelegateпредоставляет средства отображения и редактирования элементов данных из модели.
Обратите внимание:
- сортировка работает по любой колонке
- редактирование возможно только данные в колонке с индексом
5 - в данной реализации также выполняются манипуляции с подсветкой ячеек в зависимости от значения ее содержимого.
Попробуйте изменить данные в колонке с индексом 5 и проверьте сортировеу.
import sys
import random
from PyQt5.Qt import *
class Delegate(QStyledItemDelegate):
color_default = QColor("#aaedff")
colorChanged = pyqtSignal(int, int, int)
def __init__(self, parent=None):
QStyledItemDelegate.__init__(self, parent)
self.parent = parent
def createEditor(self, parent, options, index):
if index.column() == 5:
value = index.data()
editor = QLineEdit(parent) # !!!
return editor
def setEditorData(self, editor, index):
if index.column() == 5:
value = index.model().data(index, Qt.EditRole)
try: value = int(value)
except: value = 0
editor.setText(f'{value:>10}') # !!!
def updateEditorGeometry(self, editor, options, index):
editor.setGeometry(options.rect)
def setModelData(self, editor, model, index):
if index.column() == 5:
try: value = int(editor.text())
except: value = 0
value = f'{value:>10}'
model.setData(index, value, Qt.EditRole)
self.colorChanged.emit(index.row(), index.column(), int(value)) ############
class MyWidget(QWidget):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout(self)
self.tableWidget = QTableWidget()
self.tableWidget.setSortingEnabled(True)
self.layout.addWidget(self.tableWidget)
delegate = Delegate(self) # !!!
delegate.colorChanged.connect(self.color_changed) # !!!
self.tableWidget.setItemDelegate(delegate) # !!!
self.pb_refill = QPushButton("Refill")
self.pb_refill.clicked.connect(self.on_click_pb_refill)
self.layout.addWidget(self.pb_refill)
def color_changed(self, row, col, value):
if value > 777:
color = QColor(qrand() % 256, qrand() % 256, qrand() % 256)
self.tableWidget.item(row, col).setBackground(color)
self.tableWidget.item(row, col).setFont(QFont("Consolas", 10, QFont.Bold))
else:
self.tableWidget.item(row, col).setBackground(QColor("#fff"))
self.tableWidget.item(row, col).setFont(QFont("Consolas", 10))
@pyqtSlot()
def on_click_pb_refill(self):
self.tableWidget.clear()
self.tableWidget.setSortingEnabled(False) # !!!
rows_random = random.randint(1, 10)
self.tableWidget.setRowCount(rows_random)
self.tableWidget.setColumnCount(6)
self.tableWidget.setFont(QFont("Consolas", 10))
for row in range(rows_random):
for col in range(6):
number = random.randint(1, 1000)
self.tableWidget.setItem(row, col, QTableWidgetItem(f'{number:>10}'))
if col == 5:
item_text = int(self.tableWidget.item(row, col).text())
if item_text > 777:
color = QColor(qrand() % 256, qrand() % 256, qrand() % 256)
self.tableWidget.item(row, col).setBackground(color)
self.tableWidget.item(row, col).setFont(
QFont("Consolas", 10, QFont.Bold))
self.tableWidget.setSortingEnabled(True) # !!!
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MyWidget()
ex.resize(700, 300)
ex.show()
sys.exit(app.exec_())
Ваша проблема в том, что вы устанавливаете в качестве данных строку, а не число.
Qt довольно умный фреймворк, и в большинстве случаев хранит данные в виде QVariant, а соответственно сам знает как с ними работать.
Приведу пример как заполнить таблицу, чтобы ваш столбец сортировался как числа (и плюсом работа с датой)
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget, QTableWidget, QTableWidgetItem
from PyQt5.QtCore import QSize, Qt, QDate
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setMinimumSize(QSize(400, 400))
central_widget = QWidget(self)
self.setCentralWidget(central_widget)
grid_layout = QGridLayout()
central_widget.setLayout(grid_layout)
table = QTableWidget(self)
table.setColumnCount(4)
table.setRowCount(100)
table.setHorizontalHeaderLabels(["text", "text1", "text2", "date"])
table.setSortingEnabled(True)
for i in range(0, 100):
table.setItem(i, 0, QTableWidgetItem(str(i))) # Когда добавляете так, данные имеют тип строка
item = QTableWidgetItem()
item.setData(Qt.EditRole, str(i)) # так опять будет строка
table.setItem(i,1,item)
item = QTableWidgetItem()
item.setData(Qt.EditRole, i) # а так будет число
table.setItem(i,2,item)
# И то же касается других типов. на пример даты
item = QTableWidgetItem()
item.setData(Qt.EditRole, QDate.currentDate().addDays(i))
table.setItem(i,3,item)
table.resizeColumnsToContents()
grid_layout.addWidget(table, 0, 0) # Добавляем таблицу в сетку
if __name__ == "__main__":
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec())



