Привет всем.
Есть у меня класс TreeComboBox, как можно понять из названия в QComboBox у меня находится QTreeView.
Проблема в том, что я никак не могу получить порядковый номер элемента в QTreeView, для автоматического выбора при выделении в моей модели.
С помощью idx.row() я могу получить, но если у элемента уровень вложенности например 2, то получается ерунда.
А как вы определяете порядковый номер элемента в дереве? Всмысле что это значит? Т.е. какой порядковый номер должен быть у первого элемента вложенности 2 например?
Забыла сказать, что QTreeView всегда находится в состоянии expandAll.
Порядковый номер хочу определять визуально так же как и в QComboBox.
Например
1 Item 1
2 |-item 2
3 |-item 3
4 |-item 4
5 |-item 5
6 |-item 6
7 |-item 7
8 Item 8
9 |-item 9
Пока только приходит в голову, обход всех элементов рекурсивно с их дочерними элементами и присвоением номера.poluna, расскажи поподробнее, какие действия хочешь совершить ? Для идентификации элемента вроде достаточно методов parent и data индекса
ну, и да, если хочешь такую сквозную нумерацию сделать - необходимо реализовать у элемента метод навроде GetMyNumber() , где произойдёт рекурсивный вызов метода родителя в том числе
Так как мой класс производен TreeComboBox от QComboBox, то мне нужно хотя бы переопределить функции: currentIndex, setCurrentIndex и currentText.
Это нужно например для ситуации, когда мне нужно добавить пользователя в группу, выбрав группу в дереве, нажав кнопку добавить и в появившемся диалоге добавления пользователя будет выбрана группа (выделенная ранее) и ...
poluna, не совсем понимаю участия комбы в этом процессе . В классе дерева обрабатываешь contextMenuEvent , там определяешь, какой элемент модели дерева щёлкнули (viewport() , indexAt() ) . По индексу модели отыскивается элемент
Мне просто нужен комбобокс с деревом!
Всё есть, но есть нюансы, из-за которых пока грустно
И я о том же!
Видимо я не так выражаюсь.
poluna, у меня обычно есть "внемодельное" дерево - источник, по которому модель пересобирается. Контейнер обычно на основе QMap<>
struct s_item
{
s_item* m_parent;
QVector<s_item*> m_children;
...
};
s_item* m_root;
QMap<s_item*,s_item*> m_tree;
Теперь я поняла тебя.
Вариант неплох, и вроде как даже проще в реализации.
Всё, вопрос пока снимаю. Знаю как реализовывать!
combo->setRootModelIndex(idx.parent())
combo->setCurrentIndex(idx.row())
lanz, да можно и в модели хранить, но я так не люблю делать, это же неудобно ))
lanz, оно, вообще говоря, так и происходит - противоречий нету, но некоторые операции по своему контейнеру удобнее производить
А в данном случае твой вариант лучше будет, конечно )
А по моему Алексей1153 предложил хороший способ, я сам подобным же пользуюсь.
Есть список (QList) или дерево(QMap), которое откуда-то загружается и которое отображается в модели. Очень удобно добавлять, редактировать, удалять. А модель это же абстракция и она не должна по идее хранить данные, как и вид.
lanz, выше сказано
lanz, если в комбобоксе стандартными средствами можно показать дерево, то твой метод подойдет, но я не смогла.
Как я поняла для показа дерева в комбобокс нужно переопределять класс, я сделала так:
#! /usr/bin/python
# -*- coding: UTF-8 -*-
from PyQt4 import QtCore, QtGui
class TreeComboBox(QtGui.QComboBox):
def __init__(self, parent=None):
super(QtGui.QComboBox, self).__init__(parent)
self._skipNextHide = False
self._treeView = QtGui.QTreeView(self)
self.setView(self._treeView)
self._treeView.header().hide()
self._treeView.viewport().installEventFilter(self)
def eventFilter( self, object, event):
if event.type() == QtCore.QEvent.MouseButtonPress and object == self.view().viewport():
index = self.view().indexAt(event.pos())
if not self.view().visualRect(index).contains(event.pos()):
self._skipNextHide = True
return False
def showPopup(self):
self.setRootModelIndex(QtCore.QModelIndex())
self._treeView.expandAll()
QtGui.QComboBox.showPopup(self)
def hidePopup(self):
self.setRootModelIndex(self.view().currentIndex().parent())
self.setCurrentIndex(self.view().currentIndex().row())
if self._skipNextHide:
self._skipNextHide = False
else:
QtGui.QComboBox.hidePopup(self)
если я не права, то буду только рада, сразу куча проблем исчезнет! poluna, ну у меня ваш код вроде работает как надо, ЧЯДНТ?
Немножко поменял hidePopup, чтобы он сразу все не корячил:
def hidePopup(self):
if self._skipNextHide:
self._skipNextHide = False
else:
self.setRootModelIndex(self.view().currentIndex().parent())
self.setCurrentIndex(self.view().currentIndex().row())
QtGui.QComboBox.hidePopup(self)
Все, поняла, все работает!
Выкладываю работающий пример, так же на python:
#! /usr/bin/python
# -*- coding: UTF-8 -*-
import sys
from PyQt4 import QtCore, QtGui
class TreeComboBox(QtGui.QComboBox):
def __init__(self, parent=None):
super(QtGui.QComboBox, self).__init__(parent)
self._skipNextHide = False
self._treeView = QtGui.QTreeView(self)
self.setView(self._treeView)
self._treeView.header().hide()
self._treeView.viewport().installEventFilter(self)
def eventFilter( self, object, event):
if event.type() == QtCore.QEvent.MouseButtonPress and object == self.view().viewport():
index = self.view().indexAt(event.pos())
if not self.view().visualRect(index).contains(event.pos()):
self._skipNextHide = True
return False
def showPopup(self):
self.setRootModelIndex(QtCore.QModelIndex())
self._treeView.expandAll()
QtGui.QComboBox.showPopup(self)
def hidePopup(self):
if self._skipNextHide:
self._skipNextHide = False
else:
self.setRootModelIndex(self.view().currentIndex().parent())
self.setCurrentIndex(self.view().currentIndex().row())
QtGui.QComboBox.hidePopup(self)
class Main(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self._comboBox = TreeComboBox(self)
self._treeView = QtGui.QTreeView(self)
layout = QtGui.QVBoxLayout()
layout.addWidget(self._comboBox)
layout.addWidget(self._treeView)
self.setLayout(layout)
model = QtGui.QStandardItemModel()
for a in range(3):
i = QtGui.QStandardItem('Item ' + str(a))
for b in range(3):
ii = QtGui.QStandardItem('sub 1 Item ' + str(b))
i.setChild(b, ii)
for c in range(3):
iii = QtGui.QStandardItem('sub 2 Item ' + str(c))
ii.setChild(c, iii)
model.appendRow(i)
self._comboBox.setModel(model)
self._treeView.setModel(model)
self.connect(self._treeView, QtCore.SIGNAL("clicked(const QModelIndex&)"), self.comboSelect)
def comboSelect(self, idx):
self._comboBox.setRootModelIndex(idx.parent())
self._comboBox.setCurrentIndex(idx.row())
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)