Можно ли отменить выбор в QTreeView, щелкнув элемент?

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

Ответ 1

Это на самом деле довольно просто (в PyQt):

class DeselectableTreeView(QtGui.QTreeView):
    def mousePressEvent(self, event):
        self.clearSelection()
        QtGui.QTreeView.mousePressEvent(self, event)

Qt использует mousePressEvent для испускания clicked. Если вы очистите выделение перед отправкой события, тогда, если элемент будет нажат, он будет выбран, иначе ничего не будет выбран. Большое спасибо Патрису за то, что он помог мне с этим:)

Ответ 2

Основываясь на решении @Eric, и поскольку он отменяет выбор только в том случае, если был выбран выбранный элемент, вот что я придумал. Это решение также работает, когда вы нажимаете пустую область QTreeView

#ifndef DESELECTABLETREEVIEW_H
#define DESELECTABLETREEVIEW_H
#include "QTreeView"
#include "QMouseEvent"
#include "QDebug"
class DeselectableTreeView : public QTreeView
{
public:
    DeselectableTreeView(QWidget *parent) : QTreeView(parent) {}
    virtual ~DeselectableTreeView() {}

private:
    virtual void mousePressEvent(QMouseEvent *event)
    {
        QModelIndex item = indexAt(event->pos());
        bool selected = selectionModel()->isSelected(indexAt(event->pos()));
        QTreeView::mousePressEvent(event);
        if ((item.row() == -1 && item.column() == -1) || selected)
        {
            clearSelection();
            const QModelIndex index;
            selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select);
        }
    }
};
#endif // DESELECTABLETREEVIEW_H

Яссир

Ответ 3

ClearSelection не работает в моем случае. Я использую treeviews с режимом singleleselection. Вот что я закодировал:

class DeselectableTreeView : public QTreeView
{
public:
    DeselectableTreeView(QWidget *parent) : QTreeView(parent) {}
    virtual ~DeselectableTreeView() {}

private:
    virtual void mousePressEvent(QMouseEvent *event)
    {
        QModelIndex item = indexAt(event->pos());
        bool selected = selectionModel()->isSelected(item);
        QTreeView::mousePressEvent(event);
        if (selected)
            selectionModel()->select(item, QItemSelectionModel::Deselect);
    }

};

Это работает отлично.

Eric

Ответ 4

QTreeView наследует от QAbstractView (http://doc.qt.digia.com/4.6/qtreeview.html), который имеет clicked. Проблема в том, что сигнал испускается только тогда, когда индекс действителен, поэтому вы не можете достичь того, что хотите с этим сигналом.

Попробуйте перехватить mousePressEvent. В функции вы можете найти, где пользователь щелкнул и отменил выбор выбранного элемента, если это необходимо.

Ответ 5

Чтобы добавить к @Skilldrick ответ, если вам нужно применить это к представлению, которое уже было создано, потому что вы используете Qt Designer, вы можете сделать что-то вроде этого:

import new
def mousePressEvent(self, event):
    self.clearSelection()
    QtGui.QTableView.mousePressEvent(self, event)
self.ui.tableView.mousePressEvent = new.instancemethod(mousePressEvent, self.ui.tableView, None)

Это предполагает, что ваше представление self.ui.tableView.

Благодаря этому ответу: fooobar.com/questions/313857/...

Ответ 6

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

Ответ 7

В ответе @Skilldrick мы рискуем отправить лишние события. Если элемент уже выбран, и мы снова нажимаем его, мы поднимаем отмененные и выбранные события. На основе других слушателей в вашем приложении это может быть не то, что вы хотите.

Решение @eric-maeker отменяет выбор элемента, если мы снова нажмем его, когда он уже выбран. Строго говоря, это не ответ на исходный вопрос, который заключается в том, чтобы отменить выбор выбранного элемента, щелкнув в другом месте.

@yassir-ennazk приближается, но, как указывает @adrian-maire, решение не является оптимальным. event->pos() оценивается дважды. Кроме того, событие мыши всегда оценивается, вызывая QTreeView::mousePressEvent.

Вот решение, которое я придумал, основываясь на других ответах, упомянутых выше. Если мы нажимаем на точку, где присутствует другой элемент представления дерева, новый элемент выбирается пересылкой события на TreeView. Если нет, мы очищаем выбор.

Обратите внимание, что это работает и для QTreeWidget.

virtual void mousePressEvent(QMouseEvent* event)
{
    QModelIndex item = indexAt(event->pos());

    if (item.isValid())
    {
        QTreeView::mousePressEvent(event);
    }
    else
    {
        clearSelection();
        const QModelIndex index;
        selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select);
    }
}