python - La ordenación de QTableView falla después de setHorizontalHeader()
model-view-controller pyqt (1)
Me encuentro con un problema extraño con PySide QTableView
s después de haber configurado una nueva instancia de setHorizontalHeader()
través de setHorizontalHeader()
. Específicamente, parece que la capacidad de clasificación de la vista está rota / no se puede invocar más.
Preguntas
- ¿Por qué se rompe la clasificación después de establecer una nueva vista de encabezado?
- ¿Por qué los métodos de monopatching en la instancia de vista de encabezado solo funcionan después de establecer un nuevo encabezado a través de
setHorizontalHeader()
? (Consultewrap_size_hint()
en el código de demostración). - Al iniciar sesión en los elementos
QHeaderView
de la vista de tabla, ¿por qué siempre hay 2 instancias deQHeaderView
? - ¿Qué están haciendo realmente los métodos
initialize()
enQHeaderView
? ¿Podrían ser útiles aquí de alguna manera? Los documentos no son tan útiles .
Código de demostración (gist)
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function, division
import logging
import sys
from PySide import QtCore
from PySide import QtGui
# configure logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
def wrap_size_hint(func):
"""Monkeypatch virtual method to increase sizeHint.
Notes:
Strangely this does not work when when no custom header is set on the
table view.
"""
def wrapped(*args, **kwargs):
"""Just extend sizeHint to increase height."""
size = func(*args, **kwargs) # QSize
height_increase = 60
height = size.height() + height_increase
size.setHeight(height)
return size
return wrapped
class CustomHeaderView(QtGui.QHeaderView):
"""CustomHeaderView"""
class TestWidget(QtGui.QWidget):
def __init__(self, use_custom_headerview=True, *args, **kwargs):
super(TestWidget, self).__init__(*args, **kwargs)
self.logger = logging.getLogger(type(self).__name__)
QtGui.QVBoxLayout(self)
self.setup_mvc(use_custom_headerview)
self.update_model()
self.log_children(self.view)
def setup_mvc(self, use_custom_headerview):
layout = self.layout()
# model
header_labels = "One Two Three Four Five".split()
self.model = QtGui.QStandardItemModel()
self.model.setHorizontalHeaderLabels(header_labels)
# proxymodel
self.proxymodel = QtGui.QSortFilterProxyModel()
self.proxymodel.setDynamicSortFilter(True)
self.proxymodel.setSourceModel(self.model)
# view
self.view = QtGui.QTableView()
if (use_custom_headerview is True):
self.view.setHorizontalHeader(CustomHeaderView(QtCore.Qt.Horizontal))
self.view.setSortingEnabled(True)
self.view.setModel(self.proxymodel)
# monkeypatch sizeHint to increase size
headerview = self.view.horizontalHeader()
headerview.sizeHint = wrap_size_hint(headerview.sizeHint)
layout.addWidget(self.view)
def update_model(self):
for row in range(50):
items = []
for column in range(self.model.columnCount()):
text = "{0} {1}".format(row, column)
item = QtGui.QStandardItem()
item.setEditable(True)
item.setData(text, QtCore.Qt.DisplayRole)
items.append(item)
self.model.appendRow(items)
def log_children(self, widget, tab=-1):
tab += 1
msg = "{0}{0}: {1}".format("--"*tab, type(widget).__name__, widget)
self.logger.info(msg)
for child in widget.children():
self.log_children(child, tab)
if (__name__ == "__main__"):
app = QtGui.QApplication(sys.argv)
# widget_sorting_fails
widget_sorting_fails = TestWidget(use_custom_headerview=True)
widget_sorting_fails.setWindowTitle("Custom headerview")
widget_sorting_fails.show()
logger.info("-"*100)
# widget_sorting_succeeds
widget_sorting_succeeds = TestWidget(use_custom_headerview=False)
widget_sorting_succeeds.setWindowTitle("No custom headerview")
widget_sorting_succeeds.show()
# start event loop
sys.exit(app.exec_())
Ok, descubrí que setClickable(True)
hará el truco. Parece estar QTableView
forma predeterminada en las vistas de encabezado de QTableView
, pero no en instancias creadas manualmente.