PDA

View Full Version : PyQt5 - Fail to display QTableWidgetItem data if previous cell have same value?



Saelyth
16th August 2017, 19:50
Hm, I just stumbled into an issue that I don't know how to address. Somehow my QtableWidget won't show the data of 2 specific columns if the data on both is the same.
Please check the next screenshot to see what I meant. There shouldn't be invisible values on the 2nd column at all.
12559
The first row values I doublechecked multiple times and it's "No No", but it only shows first one.
Also doublechecked the 3rd row, the value there is "SÃ* SÃ*", but yet again second one is invisible.
This is the big picture in case you need to check:
12560

I fail to see why this happens.

Qt Creator pyuic5 generated code:

self.tablaBuscador = QtWidgets.QTableWidget(self.tab_buscador)
self.tablaBuscador.setGeometry(QtCore.QRect(10, 40, 941, 341))
self.tablaBuscador.setStyleSheet("")
self.tablaBuscador.setColumnCount(0)
self.tablaBuscador.setObjectName("tablaBuscador")
self.tablaBuscador.setRowCount(0)
self.tablaBuscador.verticalHeader().setDefaultSect ionSize(25)
self.tablaBuscador.setSortingEnabled(True)

This is the code where I create the table columns and headers:

def creatabla_buscador(self):
# Add columns and give them a header name
nombres_de_columnas = ["Fecha Entrada", "Proveedor", "Fecha Factura", "Importe",
"Cód. Factura", "Pagada", "Contabilizada", "Observaciones"]
self.tablaBuscador.setColumnCount(len(nombres_de_c olumnas))
self.tablaBuscador.setHorizontalHeaderLabels(nombr es_de_columnas)
# Adjust the size to fit perfectly
header = self.tablaBuscador.horizontalHeader()
for i in nombres_de_columnas:
if i == "Observaciones":
header.setSectionResizeMode(nombres_de_columnas.in dex(i), QtWidgets.QHeaderView.Stretch)
else:
header.setSectionResizeMode(nombres_de_columnas.in dex(i), QtWidgets.QHeaderView.ResizeToContents)
# Connect what happens when you click on any cell
self.tablaBuscador.cellClicked.connect(self.tablab uscador_alclickearceldas)

And this is the code I use to create rows filled with data requested from Sqlite3

def rellenatabla_buscador(self):
# Destroy all table data in order to replace it
self.tablaBuscador.setRowCount(0)
# Find the information
registros = utilidades_db.buscatodoslosregistros("Recibos",
"SELECT Fechaentrada, Proveedor, Fechafactura, "
"Importefactura, Codigofacturadelproveedor, Pagada, "
"Contabilizar, Observaciones FROM FacturasRecibidas "
"WHERE Proveedor LIKE ?",
(self.comboBuscador_proveedor.currentText(),), True)
# Order them by index 0
registros = utilidades.ordena_registros_por(registros, 0)
# Create the new rows and add the items
for registro in registros:
self.tablaBuscador.insertRow(self.tablaBuscador.ro wCount())
fila = self.tablaBuscador.rowCount() - 1
for dato in registro:
registroitem = QtWidgets.QTableWidgetItem(utilidades.ensure_its_s tr(dato))
registroitem.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
registroitem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
self.tablaBuscador.setItem(fila, registro.index(dato), registroitem)

And I fire them together upon selecting a value on the QComboBox above it, no weird stuff in between:

self.creatabla_buscador()
self.rellenatabla_buscador()

Notes:
Explaining possibly confusing functions.
ensure_its_str = It just check if the data proved is a string. If not, it converts that data as a string: str(data)
buscatodoslosregistros = Just a wrapper for "connect to database, use cursors, disconnect to database".
ordena_registros_por = It just re-order the list of items on an specific index.

Saelyth
17th August 2017, 03:45
I can't edit main post O,o.

So more data and tests: Assuming we have only 1 record:
['03/08/2017', 'Otras nuevas facturas', '16/08/2017', 333333, '11123', 'No', 'No', 'No']
The last 2 columns will appear as invisible, because they share the same value.

With the next example, column 3 appears empty... because 16/08/2017 is also the data in column 1.
['16/08/2017', 'Otras nuevas facturas', '16/08/2017', 333333, '11123', 'No', 'Yadda', 'Test']

Per row, it somehow only shows the first value if there is duplicated data. Why?

Apparently this problem has been here for years: https://stackoverflow.com/questions/19704130/inserting-empty-rows-into-table-due-to-duplicate-items

ChrisW67
17th August 2017, 08:39
Did you see this in the QTableWidget docs?


If you want to enable sorting in your table widget, do so after you have populated it with items, otherwise sorting may interfere with the insertion order (see setItem() for details).


Try disabling sorting before the load, loading,and then enabling sorting.

Saelyth
17th August 2017, 16:32
I actually saw it, but it didn't specified "sorting won't let you add duplicated items to the same row" so I didn't tried to change.

Now I tried the next code but the same behaviour still happens. Repeated data won't show:

self.tablaBuscador.setSortingEnabled(False)
self.tablaBuscador.setItem(...)
self.tablaBuscador.setSortingEnabled(True)

I even tried to disable sorting entirely and use a non-sorted table, but yet if there is repeated data like "something", "something", "something", the last one won't appear, instead an empty editable cell is inserted.

Edit: Recorded video with my crap phone just to make clear the issue: https://twitter.com/Saelyth/status/898196447425855488

Edit 2: Someone as newbie as me would expect a "enableDuplicates" setting, because I don't understand why a row can't have 2-3 cells with the same exact data. By default it should allow it, and only disable it if we specifically want.

Saelyth
18th August 2017, 04:31
Stubborn me want to keep you guys informed of my newbie research advances.

Test Script for python where you can see the bug (easier for you to execute and see yourself than me trying to explain in english):

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QAction, QTableWidget,QTableWidgetItem,QVBoxLayout
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot, Qt

class App(QWidget):

def __init__(self):
super().__init__()
self.title = 'PyQt5 table - pythonspot.com'
self.left = 200
self.top = 200
self.width = 800
self.height = 200
self.initUI()

def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)

self.createTable()

# Add box layout, add table to box layout and add box layout to widget
self.layout = QVBoxLayout()
self.layout.addWidget(self.tableWidget)
self.setLayout(self.layout)

# Show widget
self.show()

def createTable(self):
# Create table
self.tableWidget = QTableWidget()
self.tableWidget.setRowCount(2)
self.tableWidget.setColumnCount(6)
self.tableWidget.setHorizontalHeaderLabels(["algo", "algo", "algo", "algo", "algo", "algo"])
registros = ["Celda", "Celda", "Celda", "Celda", "Celda", "Celda"]
# BUGGED ROW
for dato in registros:
registroitem = QTableWidgetItem(dato)
self.tableWidget.setItem(0, registros.index(dato), QTableWidgetItem(registroitem))
# NON BUGGED ROW
self.tableWidget.setItem(1,0, QTableWidgetItem("Celda"))
self.tableWidget.setItem(1,1, QTableWidgetItem("Celda"))
self.tableWidget.setItem(1,2, QTableWidgetItem("Celda"))
self.tableWidget.setItem(1,3, QTableWidgetItem("Celda"))
self.tableWidget.setItem(1,4, QTableWidgetItem("Celda"))
self.tableWidget.setItem(1,5, QTableWidgetItem("Celda"))

if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())

Which pretty much says (your bug is on the loop). I still don't know what causes it but getting closer :D. Any hint?

Edit + FIX: I am retard.... it actually seems that it was a python noob fail all this time. registros.index(dato) was always returning the first index if it's a duplicated (0). I've been coding on python 4 years and never realized about this, hence I though it was a Qt issue.

Fix: replace "for dato in registros:" and add "for index, dato in enumerate(registro):" instead.

My apologies guys, thread can be closed.

d_stranz
18th August 2017, 17:48
registros.index(dato) was always returning the first index if it's a duplicated (0).

Sort of makes sense though - if you are asking to look up something by value, and that value is duplicated, how should it know you want the second one and not the first? The only way to give that information is with a second argument to index() that tells it where to start, something like index( value, startIndex ).