我正在开发一个程序来查看和编辑文件中的记录。它具有显示所有记录的QTableView
,用于搜索记录的QLineEdit
以及显示所选记录详细信息的一些标签:
有一个QAbstractTableModel
类来保存数据,一个QSortFilterProxyModel
类可以帮助过滤QTableView
中的行。
搜索和过滤工作正常。在搜索框中键入文本会立即过滤记录列表。但有两件事我无法开展工作:
例如,当我输入“tesla”时,列表将为空,因为没有项匹配。但是当我退回到“te”时,“Forester”会匹配,我希望它被选中。第二个例子:当(在启动程序之后)我输入“f”时,列表缩小到8个项目并选择“Pacifica”。当我删除“f”时,仍然选择了Pacifica但不再位于列表的可见部分。
我已在Pastie上发布了完整的源代码,以下是一些(希望)相关的摘要。
void MainWindow::on_lineEditSearch_textChanged(const QString & text)
{
itemProxy->setFilterFixedString(text);
updateStatusBar();
}
void MainWindow::currentRowChangedSlot(QModelIndex const & current, QModelIndex const & /*previous*/)
{
Car * car = 0;
if (current.isValid())
{
QModelIndex sibling = current.sibling(current.row(), COLUMN_THIS);
QVariant variant = itemProxy->data(sibling);
car = static_cast<Car *> (variant.value<void *> ());
}
updateCarMake(car);
updateCarModel(car);
}
MainWindow::MainWindow(QWidget * parent, CarItemModel * itemModel, CarSortFilterProxyModel * itemProxy) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
this->itemModel = itemModel;
this->itemProxy = itemProxy;
ui->setupUi(this);
setupStatusBar();
ui->tableView->setModel(itemProxy);
ui->tableView->setColumnHidden(COLUMN_THIS, true);
QItemSelectionModel * selectionModel = ui->tableView->selectionModel();
connect(selectionModel, SIGNAL(currentRowChanged(QModelIndex const &, QModelIndex const &)),
this, SLOT(currentRowChangedSlot(QModelIndex const &, QModelIndex const &)));
connect(selectionModel, SIGNAL(selectionChanged(QItemSelection const &, QItemSelection const &)),
this, SLOT(selectionChangedSlot(QItemSelection const &, QItemSelection const &)));
ui->tableView->selectRow(0);
ui->lineEditSearch->setFocus();
updateStatusBar();
}
<widget class="QTableView" name="tableView">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
所以,我的问题是:我怎样才能确保总是选择一个项目并且在列表的可见部分(除非用户正在滚动)?
答案 0 :(得分:1)
这是我做的
解决方案甚至有点过分了,因为当从无可见项目转到某些可见项目时,将选择最近选择的项目,而不是仅选择第一项。
首先,我向QModelIndex lastModelIndex;
类添加了MainWindow
个私有成员,并将其设置在SelectionChanged
广告位中。请注意,模型索引是存储的,而不是代理索引。
void MainWindow::selectionChangedSlot(QItemSelection const & selected, QItemSelection const & /*deselected*/)
{
if (selected.count() > 0)
{
QModelIndex index = selected.indexes().first();
QModelIndex modelIndex = itemProxy->mapToSource(index);
lastModelIndex = modelIndex;
}
}
接下来,我添加了两种方法:ensureSelected()
...
void MainWindow::ensureSelected(QItemSelectionModel * selectionModel, int const proxyCount)
{
if (selectionModel->hasSelection())
{
// an item is currently selected - don't have to do anything
}
else if (proxyCount == 1)
{
// no item is currently selected, but there is exactly one item in the list - select it
QModelIndex proxyIndex = itemProxy->index(0, 0);
selectionModel->setCurrentIndex(proxyIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows);
}
else if (proxyCount > 1)
{
// no item is currently selected, but there are several items in the list
QModelIndex proxyIndex; // !isValid
if (lastModelIndex.isValid())
{
// there's a most recently selected item - compute its index in the list
proxyIndex = itemProxy->mapFromSource(lastModelIndex);
}
if (proxyIndex.isValid())
{
// the most recently selected item is in the list - select it
proxyIndex = proxyIndex.sibling(proxyIndex.row(), COLUMN_THIS);
}
else
{
// there's no most recently selected item or it is no longer in the list - select the first item
proxyIndex = itemProxy->index(0, 0);
}
selectionModel->setCurrentIndex(proxyIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows);
}
else
{
// There are no items in the list - cannot select anything.
}
}
...和ensureVisible()
:
void MainWindow::ensureVisible(QItemSelectionModel * selectionModel)
{
if (selectionModel->hasSelection())
{
const QModelIndex index = ui->tableView->currentIndex();
ui->tableView->scrollTo(index);
ui->tableView->selectRow(index.row());
ui->tableView->scrollTo(index);
}
}
看起来很奇怪,我必须两次调用scrollTo()
,否则tableView将不会滚动。
这些新方法从on_lineEditSearch_textChanged()
调用,如下所示:
void MainWindow::on_lineEditSearch_textChanged(const QString & text)
{
itemProxy->setFilterFixedString(text);
QItemSelectionModel * selectionModel = ui->tableView->selectionModel();
int modelCount = itemModel->rowCount(); // number of items in the model
int proxyCount = itemProxy->rowCount(); // number of items in tableview
ensureSelected(selectionModel, proxyCount);
ensureVisible(selectionModel);
updateStatusBar();
}
请在Pastie上找到更新完整的源代码。
答案 1 :(得分:0)
处理选择更改信号并将其连接到您的自定义插槽:
QSortFilterProxyModel *model = new QSortFilterProxyModel(this);
ui->tableView->setModel(model);
connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(selectionChanged(QItemSelection,QItemSelection)));
每次,您的表格更改当前选择,应用程序应选择模型中的第一个项目:
void MainWindow::selectionChanged(QItemSelection selected, QItemSelection deselected) {
// Use this
const int rows = ui->tableView->selectionModel()->selectedRows().size();
// or
const int rowCount = selected.size();
// Lets select the first item if there are some items availables
if (rowCount < 1) {
const int availableItems = ui->tableView->model()->rowCount();
if (availableItems > 0) {
const QModelIndex index = ui->tableView->model()->index(0,0);
ui->tableView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
}
}
}
通过这种方式,您应该至少选择一个项目。