QT QItemSelectionModel игнорировать столбцы?
Я пытаюсь ограничить выбор дерева для определенного столбца.
Я интенсивно использую делегатов для создания пользовательских поведений для каждого элемента в столбце, редакторов и т. Д. Я надеялся, что смогу как-то сделать это из делегата, заблокировав событие или что-то подобное. Проблема, я думаю, мне нужно было бы создать полностью индивидуальное решение, которое имитирует расширенный выбор.
Тем не менее, после долгих поисков и очень немногих примеров, звучит так, как будто я хочу пользовательскую QItemSelectionModel в моем древовидном представлении. Это предположение верно?
Как создать пользовательский QItemSelectionModel, который будет использовать расширенный режим выбора, но позволит мне игнорировать или отменять выбор, если он не находится в определенном столбце. Другими словами, нажатие на другой столбец не должно изменять выбор (не должен выделять или отменять выбор)
Я знаю, как добавить модель выбора, когда она у меня есть. Я прошу помощи в реализации производного класса (если это не может быть сделано с подключенным сигналом).
Я использую Python, но оценил бы любую помощь.
Спасибо,
[РЕДАКТИРОВАТЬ:] Я нашел эти похожие вопросы: http://lists.qt.nokia.com/pipermail/qt-interest/2010-September/027647.html
"Подкласс QItemSelectionModel и переопределение обоих методов выбора имеют желаемое поведение. Просто игнорируйте части диапазонов со столбцом> 0. ... Или, может быть, просто переопределите flags(), чтобы сделать элемент недоступным для выбора. Я не знаю, если это будет иметь какие-либо побочные эффекты."
Я попытался переопределить флаги на моем QTreeWidgetItem, но он никогда не вызывался:
def flags(self, index):
print index.column()
return super(DDOutlinerBaseItem, self).flags(index)
2 ответа
Следующая настройка должна работать, в теории.
Приведенное выше решение может использовать два отдельных метода и декораторы @pyqtSlot для устранения неоднозначности имен перегруженных методов:
@pyqtSlot(QModelIndex, QItemSelectionModel.SelectionFlags)
def select(self, index, command):
# ...
@pyqtSlot(QItemSelection, QItemSelectionModel.SelectionFlags)
def select(self, selection, command):
#...
Это избавляет от необходимости проверять экземпляры определенных классов в реализациях метода.
Первая интересная вещь заключается в том, что, поскольку Python не может перегрузить метод, кажется, что мой метод select просто вызывается дважды, по одному разу для каждого типа в аргументе 0. Вот пример, иллюстрирующий это, а также основные настройки. Дерево моего QTreeWidget называется "деревом" (self.tree
)
# in __init__ of my QTreeWidget:
sel_model = ColumnSelectionModel(self.tree.model())
self.tree.setSelectionModel(sel_model)
class ColumnSelectionModel(QtGui.QItemSelectionModel):
def select(self, selection, selectionFlags):
"""
Runs both QItemSelectionModel.select methods::
1. select(QtCore.QModelIndex, QItemSelectionModel.SelectionFlags)
2. select(QtGui.QItemSelection, QItemSelectionModel.SelectionFlags)
The first seems to run on mouse down and mouse up.
The second seems to run on mouse down, up and drag
"""
print("select(%s, %s)" % (type(selection), type(selectionFlags)))
if isinstance(selection, QtGui.QItemSelection):
infos = []
for index in selection.indexes():
infos.append(("index=%s row=%s column=%s"
% (index, index.row(), index.column())))
print ", ".join(infos)
elif isinstance(selection, QtCore.QModelIndex):
index = selection
print("index=%s row=%s column=%s" % (index, index.row(), index.column()))
else:
raise Exception("Unexpected type for arg 0: '%s'" % type(selection))
super(ColumnSelectionModel, self).select(selection, selectionFlags)
Похоже, это решает мою проблему:
class ColumnSelectionModel(QtGui.QItemSelectionModel):
def __init__(self, model):
super(ColumnSelectionModel, self).__init__(model)
self.selectable_columns = [0]
""" Set the columns that are allowed to be selected """
def select(self, selection, selectionFlags):
"""
Ignores any selection changes if an item is not in one of the columns
in the self.selectable_columns list.
Is run by both QItemSelectionModel.select methods::
1. select(QtCore.QModelIndex, QItemSelectionModel.SelectionFlags)
2. select(QtGui.QItemSelection, QItemSelectionModel.SelectionFlags)
The first seems to run on mouse down and mouse up.
The second seems to run on mouse down, up and drag
"""
if isinstance(selection, QtGui.QItemSelection):
# This is the overload with the QItemSelection passed to arg 0
# Loop over all the items and if any are not in selectable_columns
# ignore this event. This works because it is run for every change
# so the offending selection index will always be the newest
indexes = selection.indexes()
for i in xrange(len(indexes)):
index = indexes[i]
if not index.column() in self.selectable_columns:
return
elif isinstance(selection, QtCore.QModelIndex):
# This is the overload with the QModelIndex passed to arg 0
# If this index isn't in selectable_columns, just ignore this event
index = selection
if not index.column() in self.selectable_columns:
return
else: # Just in case
raise Exception("Unexpected type for arg 0: '%s'" % type(selection))
# Fall through. Select as normal
super(ColumnSelectionModel, self).select(selection, selectionFlags)
В моей последней реализации я планирую делегировать решение моей системе делегатов, что делает этот универсальный и теоретически способным динамически игнорировать любой индекс, который я хочу.