Параметр QTreeWidgetItem не доступен для выбора, очищает выбор

У меня есть QTreeWidget, и я хочу, чтобы некоторые строки нельзя было выбирать, чего можно добиться с помощью QTreeWidgetItem::setFlags(treeWidgetItem->flags() & ~Qt::ItemIsSelectable).

Проблема в том, что у меня есть существующая строка, которая уже выбрана, и позже я нажимаю на недоступную для выбора строку, selectedItems() возвращает пустой список. Я хочу, чтобы выбранная строка сохраняла свой выбор, если пользователь пытается выбрать недоступную для выбора строку.

Следует ли мне отслеживать выбор и обрабатывать этот сценарий в коде, или этого можно добиться как-то иначе. Я бы предпочел не изобретать велосипед.

Спасибо.


person aalimian    schedule 05.09.2018    source источник
comment
Я подключился к сигналу selectionChanged (), и именно здесь я его называю. И в это время я получаю пустой список. Таким образом, новый элемент, по которому щелкнули, не был выбран, однако старый был очищен от выбора. И это говорит мне не только selectedItems (), я могу визуально видеть, что выделение очищается ...   -  person aalimian    schedule 05.09.2018
comment
Вот когда вы можете найти только что сделанный мной фрагмент: github.com/aalimian/TreeWidgetSamples   -  person aalimian    schedule 05.09.2018
comment
Я сделал верхнюю строку недоступной для выбора. И я не могу его выбрать. Так что это работает. Но в тот момент, когда я нажимаю на нее, выбор дочерней строки исчезает.   -  person aalimian    schedule 05.09.2018
comment
О, и давайте не будем сейчас сосредотачиваться на множественном выборе. Я установил его как одиночный выбор.   -  person aalimian    schedule 05.09.2018
comment
Я не в этом фрагменте кода. Но какое это имеет значение? Мы ясно видим, что выбор очищается. Если хотите, могу быстро добавить.   -  person aalimian    schedule 05.09.2018
comment
@scopchanov, только что добавил ...   -  person aalimian    schedule 05.09.2018
comment
@scopchanov, не стесняйтесь нажимать на репо ...   -  person aalimian    schedule 05.09.2018
comment
@scopchanov, решением было бы отслеживать выбранные элементы, а затем, когда выбор изменился и список выбранных элементов пуст, вернуться к предыдущему выбору. Я просто не хочу этого делать ...   -  person aalimian    schedule 05.09.2018
comment
Только что проверил. Проблема с этим решением заключается в том, что я не хочу, чтобы родительский узел разворачивался / сворачивался, когда я нажимаю на него ... Я думаю, что это можно изменить только в случае двойного щелчка ...   -  person aalimian    schedule 05.09.2018
comment
void MyTreeWidget :: mousePressEvent (событие QMouseEvent *) {QTreeWidgetItem * item = itemAt (event- ›pos ()); if (item- ›flags () & Qt :: ItemIsSelectable) {QTreeWidget :: mousePressEvent (событие); } else if (event- ›type () == QEvent :: MouseButtonDblClick) {if (item-› childCount ()) {item- ›setExpanded (! item-› isExpanded ()); }}}   -  person aalimian    schedule 05.09.2018
comment
Не могли бы вы немного изменить свой ответ и добавить приведенный выше фрагмент кода, чтобы я мог отметить его как решение? Спасибо!   -  person aalimian    schedule 05.09.2018
comment
Да. Оно работает.   -  person aalimian    schedule 05.09.2018
comment
Большой! Затем я обновлю свой ответ, и вы добавите эти детали к своему вопросу, пожалуйста.   -  person scopchanov    schedule 05.09.2018


Ответы (1)


Причина

Вызов QTreeView::mousePressEvent(event) очищает выбор при нажатии на недоступный для выбора элемент, если выбор режим установлен на QAbstractItemView::SingleSelection.

Решение

Мое решение:

или (если это нежелательно):

  • Повторно реализуйте события мыши в подклассе QTreeWidget, чтобы обойти поведение по умолчанию.

Примечание. В любом случае используйте сигнал QItemSelectionModel::selectionChanged, чтобы получить список выбранных элементов.

Пример

Вот пример повторной реализации событий мыши в MyTreeWidget, предотвращающей очистку выбора при щелчке по невыбираемому элементу. Верхний элемент разворачивается / сворачивается двойным щелчком:

void MyTreeWidget::mousePressEvent(QMouseEvent *event)
{
    if (indexAt(event->pos())->flags() & Qt::ItemIsSelectable)
        QTreeWidget::mousePressEvent(event);
}

void MyTreeWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
    QTreeWidget::mouseDoubleClickEvent(event);

    QTreeWidgetItem *item = itemAt(event->pos());

    if (item && item->childCount())
        item->setExpanded(!item->isExpanded());
}

Измененная описанным образом версия предоставленного примера доступна на GitHub.

Улучшения

Особая благодарность @eyllanesc за то, что сделал этот пример более водонепроницаемым:

  • добавление проверки, если item не NULL
  • замена itemAt на indexAt
person scopchanov    schedule 05.09.2018
comment
Плохо в этом решении то, что doc.qt.io/qt-5 /qtreewidget.html#itemClicked и doc.qt.io/qt -5 / qtreewidget.html # itemPressed для этих элементов удаляется. :) - person eyllanesc; 05.09.2018
comment
@eyllanesc, да, это компромисс. Полагаю, что перетаскивание тоже не сработает. - person scopchanov; 05.09.2018
comment
@scopchanov сменить if(item->childCount()) на if(item->childCount() && item) - person eyllanesc; 05.09.2018
comment
@scopchanov измените if (itemAt(event->pos())->flags() & Qt::ItemIsSelectable) на if(indexAt(event->pos())->flags() & Qt::ItemIsSelectable), itemAt() может вернуть нулевой указатель и затем вылетит XD. - person eyllanesc; 05.09.2018