我希望能够通过在 QTreeView 中没有项目的部分点击来取消选择项目,但是我似乎找不到任何方法来实现这一点。我想拦截不在项上的单击,但是 QTreeView 没有 clicked
信号,因此我不知道该如何做。
根据 @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
亚西尔
这个其实很简单(在PyQt中):
class DeselectableTreeView(QtGui.QTreeView):
def mousePressEvent(self, event):
self.clearSelection()
QtGui.QTreeView.mousePressEvent(self, event)
Qt使用mousePressEvent
来发出clicked
。如果在发送事件之前清除选择,则如果单击项,则将选择该项,否则将不选择任何内容。非常感谢Patrice帮我解决了这个问题:)
clearSelection在我的情况下不起作用。我正在使用单选模式的treeviews。这是我的代码:
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
QTreeView
继承自QAbstractView
(http://doc.qt.digia.com/4.6/qtreeview.html),它有一个clicked
信号。问题在于,只有当索引有效时信号才会被发射,所以你无法通过这个信号来达到想要的效果。
尝试拦截mousePressEvent
。在该函数中,您可以找到用户单击的位置,并在需要时取消选择已选定的项目。
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);
}
}
clearSelection()
。然后无条件调用基类的 mousePressEvent
。 - ekhumoroimport 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
。由于问题特别涉及PyQt,我想根据Nick Pruehs的答案和ekhumoro的评论,提供最简单的实现方式:
class TreeView(QTreeView):
def __init__(self, *args, **kwds):
QTreeView.__init__(self, *args, **kwds)
def mousePressEvent(self, event):
item = self.indexAt(event.pos())
if not item.isValid():
self.clearSelection()
QTreeView.mousePressEvent(self, event)
我选择使用事件过滤器而不是子类化。如果我有很多这样的情况,我会进行子类化,但对于一次性的情况,我认为修改我的窗口代码更容易。
一些注意事项:
下面的示例显示了对话框构造函数和事件过滤器:
MyWindow::MyWindow(QWidget *theParent) :
QDialog(theParent),
ui(new Ui::MyWindow)
{
ui->setupUi(this);
ui->MyTreeView->viewport()->installEventFilter(this);
}
bool MyWindow::eventFilter(QObject* theObject, QEvent* theEvent)
{
if (theObject == ui->MyTreeView->viewport())
{
if(theEvent->type() == QEvent::MouseButtonPress)
{
QMouseEvent* aMouseEvent = static_cast<QMouseEvent*>(theEvent);
if (aMouseEvent->button() == Qt::LeftButton)
{
auto anIndex = ui->MyTreeView->indexAt(aMouseEvent->pos());
if (anIndex.isValid() == false)
{
ui->MyTreeView->clearSelection();
ui->MyTreeView->selectionModel()->clearSelection();
}
}
}
}
return QObject::eventFilter(theObject, theEvent);
}
indexAt
可能会非常昂贵,您可以使用item
代替第二个调用。item.isValid()
可能比将行和列与-1
进行比较更好。 此外,如果单击元素,似乎会更改选择? - Adrian Maire