QT中view/model中只视图选择模型QItemSelectionModel

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvdepeng123/article/details/85165368

选择是视图中常用的一个操作。在列表、树或者表格中,通过鼠标点击可以选中某一项,被选中项会变成高亮或者反色。在 Qt 中,选择也是使用了一种模型。在 model/view 架构中,这种选择模型提供了一种更通用的对选择操作的描述。对于一般应用而言,Qt 内置的选择模型已经足够,但是,Qt 还是允许你创建自己的选择模型,来实现一些特殊的操作。

Qt 使用QItemSelectionModel类获取视图中项目的选择情况。这个模型保持有项目的索引,并且独立于任何视图。这意味着,我们可以让不同的视图共享同一个选择模型,从来达到一种同步操作的目的。选择由选择区域组成。模型只将选区的开始和结束的索引位置记录下来,以保证对于很大的选区也有很好的性能。非连续选区则由多个连续选择组成。

选择会直接应用于选择模型所维护的那些被选中的索引上面。最新的选择就是当前选择。这意味着,即便界面上没有显示有任何项目被选择,如果通过某些命令对选区进行操作,同样会有作用。

在视图中,始终存在一个当前项和被选择项(即便从界面上看不到有任何选择)。与通常所想的不同,当前项和选择项是相互独立的两个状态。一个项目可以即是当前项又是选择项。下表是当前项和选择项的区别:当前项

当前项 选择项
只能有一个当前项。 可以有多个选择项。
使用键盘或者鼠标点击可以改变当前项。 选择项使用两种状态:选择和未选择,这取决于项目之前的状态和其它一些设置,例如,单选或多选。只有在用户进行交互的时候,这种状态才会发生改变。
当前项可以使用 F2 或者鼠标双击进行编辑(前提是程序允许)。 当前项可以结合另外一个锚点指定被选择或者去除选择的一块选区(或二者的结合)。
当前项通常会有一个焦点框进行标识。 选择项使用选区颜色进行标识。

在处理选择的时候,我们可以将QItemSelectionModel当成数据模型中所有数据项的选择状态的一个记录。一旦选择模型创建好,这些数据项就可以在不知道哪些项被选择的情况下进行选择、取消选择或者改变选择状态的操作。所有被选择项的索引都在可随时更改,其它组件也可以通过信号槽机制修改这些选择的信息。

标准视图类(QListViewQTreeView以及QTableView)已经提供了默认的选择模型,足以满足大多数应用程序的需求。某一个视图的选择模型可以通过selectionModel()函数获取,然后使用setSelectionModel()提供给其它视图共享,因此,一般没有必要新建选择模型。

如果需要创建一个选区,我们需要指定一个模型以及一对索引,使用这些数据创建一个QItemSelection对象。这两个索引应该指向给定的模型中的数据,并且作为一个块状选区的左上角和右下角的索引。为了将选区应用到模型上,需要将选区提交到选择模型。这种操作有多种实现,对于现有选择模型有着不同的影响。

下面我们来看一些代码片段。首选构建一个总数 24个数据项的表格模型,然后将其设置为一个表格视图的数据:

 tableWidget = new QTableWidget(6,4,nullptr);
    tableWidget->setColumnCount(4);
    tableWidget->setRowCount(6);
    selectModel = tableWidget->selectionModel();

QStringList headers,headColunm;
    headers << "ID" << "Name" << "屌长" << "Sex";
    tableWidget->setHorizontalHeaderLabels(headers);
    headColunm <<"一"<<"二"<<"三"<<"四"<<"五"<<"六";
    tableWidget->setVerticalHeaderLabels(headColunm);
    tableWidget->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
    tableWidget->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    tableWidget->setLayoutDirection(Qt::LayoutDirectionAuto);
    tableWidget->setColumnWidth(3,50);
    tableWidget->setColumnWidth(2,50);
//    tableWidget->setFixedHeight(207);
//    tableWidget->setFixedWidth(407);

    tableWidget->setItem(0, 0, new QTableWidgetItem(QIcon( QApplication::applicationDirPath()+"/6.jpg"),QString("0001")));
    tableWidget->setItem(1, 0, new QTableWidgetItem(QIcon( QApplication::applicationDirPath()+"/6.jpg"),QString("0002")));
    tableWidget->setItem(2, 0, new QTableWidgetItem(QIcon( QApplication::applicationDirPath()+"/6.jpg"),QString("0003")));
    tableWidget->setItem(3, 0, new QTableWidgetItem(QIcon( QApplication::applicationDirPath()+"/6.jpg"),QString("0004")));
    tableWidget->setItem(4, 0, new QTableWidgetItem(QIcon( QApplication::applicationDirPath()+"/6.jpg"),QString("0005")));
    tableWidget->setItem(5, 0, new QTableWidgetItem(QIcon( QApplication::applicationDirPath()+"/6.jpg"),QString("0005")));

    tableWidget->setItem(0, 1, new QTableWidgetItem(QString("逼哥")));
    tableWidget->setItem(1, 1, new QTableWidgetItem(QString("吕德朋")));
    tableWidget->setItem(2, 1, new QTableWidgetItem(QString("雪山飞舞")));
    tableWidget->setItem(3, 1, new QTableWidgetItem(QString("黑寡妇")));
    tableWidget->setItem(4, 1, new QTableWidgetItem(QString("神州大地")));
    tableWidget->setItem(5, 1, new QTableWidgetItem(QString("血液风阀")));

    tableWidget->setItem(0, 2, new QTableWidgetItem(QString("9mm")));
    tableWidget->setItem(1, 2, new QTableWidgetItem(QString("18cm")));
    tableWidget->setItem(2, 2, new QTableWidgetItem(QString("9")));
    tableWidget->setItem(3, 2, new QTableWidgetItem(QString("9")));
    tableWidget->setItem(4, 2, new QTableWidgetItem(QString("9")));
    tableWidget->setItem(5, 2, new QTableWidgetItem(QString("9")));

    tableWidget->setItem(0, 3, new QTableWidgetItem(QString("男")));
    tableWidget->setItem(1, 3, new QTableWidgetItem(QString("男")));
    tableWidget->setItem(2, 3, new QTableWidgetItem(QString("男")));
    tableWidget->setItem(3, 3, new QTableWidgetItem(QString("女")));
    tableWidget->setItem(4, 3, new QTableWidgetItem(QString("男")));
    tableWidget->setItem(5, 3, new QTableWidgetItem(QString("女")));
    tableWidget->setWindowTitle("视图 widget");
    tableWidget->show();


    connect(selectModel, SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
                      this,  SLOT(changeCurrent(const QModelIndex &,const QModelIndex &)));

    int h = tableWidget->height();
    int w = tableWidget->width();
    int columnWidth = tableWidget->columnWidth(2);
    Q_UNUSED(columnWidth);
    qDebug()<<"h w"<<h<<w;

正如前面我们说的,首先利用左上角和右下角的坐标构建一个QItemSelection对象,然后将这个对象设置为选择模型的选择区。select()函数的第一个参数就是需要选择的选区,第二个参数是选区的标志位。Qt 提供了很多不同的操作,可以参考下QItemSelectionModel::SelectionFlags的文档。在本例中,我们使用了QItemSelectionModel::Select,这意味着选区中所包含的所有单元格都会被选择。

QModelIndex topLeft = tableWidget->model()->index(1,0,QModelIndex());
    QModelIndex topRight = tableWidget->model()->index(3,3,QModelIndex());
    QItemSelection seletion;
    seletion.select(topLeft,topRight);
    selectModel->select(seletion,QItemSelectionModel::Select);

现在我们知道如何设置选区。下面来看看如何获取选区。获取选区需要使用selectedIndexes()函数。该函数返回一个无序列表。我们可以通过遍历这个列表获得哪些被选择:

QDialog *dialog = new QDialog(nullptr,Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint );
    dialog->setWindowTitle(tr("Hello, dialog!"));
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->open();


    QModelIndexList indexes = selectModel->selectedIndexes();
    QModelIndex index;

    QTableWidget* tableView = new QTableWidget(5,4,dialog);
    tableView->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    tableView->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);//数据内容最大化展示

    tableView->show();
    //tableView->setModel(model);
    foreach(index, indexes)
    {
        //QString text = QString("(%1,%2)").arg(index.row()).arg(index.column()); //显示位置
        QString text = QString("%1").arg(index.data().toString());
        tableView->model()->setData(index, text,Qt::DisplayRole);
    }

我们上一个model中选择视图,放在两一个视图的相同模型展示出来

在选择发生更改时,选择模型会发出信号。我们可以连接selectionChanged()信号,在选区改变时检查哪个项目发生了变化。这个信号有两个参数:第一个是新选择的项目,第二个是刚刚被取消选择的项目。在下面的示例中,我们通过selectionChanged()信号,将所有新选择的项目填充字符串,将所有被取消选择的部分清空:

void myDefineEvent::changeCurrent(const QModelIndex &current,
                               const QModelIndex &previous)
{
    qDebug()<<"changeCurrent ";
    QStatusBar  *statusBar = new QStatusBar(nullptr);
    statusBar->showMessage(
        tr("Moved from (%1,%2) to (%3,%4)")
            .arg(previous.row()).arg(previous.column())
            .arg(current.row()).arg(current.column()),5);
    qDebug()<<QString(tr("Moved from (%1,%2) to (%3,%4)").arg(previous.row()).arg(previous.column())
                      .arg(current.row()).arg(current.column()));
}

我们可以清楚的看见前一项和后一项的变化 

同样是利用前面所说的QItemSelectionModel::SelectionFlag,我们可以对选区进行组合操作。还记得我们在前面的select()函数中使用过的第二个参数吗?当我们替换这个参数,就可以获得不同的组合方式。最常用的就是QItemSelectionModel::Select,它的作用是将所有指定的选区都选择上。QItemSelectionModel::Toggle则是一种取反的操作:如果指定的部分原来已经被选择,则取消选择,否则则选择上。QItemSelectionModel::Deselect则是取消指定的已选择的部分。

源代码请打击这里  源代码

猜你喜欢

转载自blog.csdn.net/lvdepeng123/article/details/85165368
今日推荐