前言
QT展示列表信息的时候通常用到列表(比如用户信息、机构信息、设备信息等菜单),当需要对某列进行修改、删除操作时,就需要加入按钮(QPushButton),当需要对多列进行右键菜单操作时,就需要加入QCheckBox和右键菜单功能,本篇即围绕QTableView、QCheckBox、QPushButton,以及右键菜单进行讲解。
功能显示效果图
功能讲解
1、创建QTableView
(1)创建QTableView列表头
//两种方式创建列表头
//1、在UI中之间添加
//2、组装QStringList,调用setHorizontalHeaderLabels方法加载进去,列表头不算在数据模型Model里面
QStringList tablelHeader;
for(int i=0;i<m_all_fieldsHeadname.size();i++) {
tablelHeader << m_all_fieldsHeadname[i];
}
qDebug() << __LINE__ << __FUNCTION__<<tablelHeader;
//tablelHeader<< "选择" <<"序号"<<"编码"<<"名称"<<"品牌"<<"类型"<<"IP地址"<<"更新时间"<<"操作";
注意,两种方式在数据展示上没有差别,但存在一个坑:
当使用代码行添加列表头(tablelHeader)时,当设置勾选项(QCheckBox)的信号和槽函数来获取勾选项(QCheckBox)的位置时,会偏差1行,坑的位置是以下代码row在获取最后一行时,返回的是-1,返回值-1其实是无效的意思。
以下是片段代码
//关联信号和槽
QCheckBox *checkBox = new QCheckBox();
connect(checkBox,SIGNAL(stateChanged(int)),this,SLOT(onCheckBoxStateChanged(int)));
//实现槽函数
void MainWindow::onCheckBoxStateChanged(int state){
QCheckBox *checkBox =qobject_cast<QCheckBox *>(QObject::sender());
if(checkBox){
int row = ui->tableWidget->indexAt(checkBox->mapTo(ui->tableWidget, QPoint(0, 0))).row();
}
我提交的源代码也是使用代码行添加列表头(tablelHeader),但用了另外一个方法来规避此问题,规避方法是row取的是继承tableWidget获取到的row,而不是通过checkBox->mapTo(ui->tableWidget, QPoint(0, 0))反向获取到的行位置(本人未深入研究mapTo,有用此方法解决此问题的兄弟,可以把代码放在评论区),所以不会出现偏差。
代码如下:
void tab_basemsg::renderTable(const QStringList& rowData){
int row = ui->tableWidget->rowCount();//当前tableWidget显示的行数
//int rowCount = ui->tableWidget->model()->rowCount();//tableWidget表格中实际的数据行数
ui->tableWidget->insertRow(row);//在 QTableWidget 中插入新行
for (int column = 0; column < rowData.size(); ++column) {
QTableWidgetItem* item = new QTableWidgetItem(rowData.at(column));
item->setTextAlignment(Qt::AlignCenter);
ui->tableWidget->setItem(row, column, item);
if(column == HEAD_BASEMSG_CKBOX){
//========创建复选框QCheckBox===============
QCheckBox* checkBox = new QCheckBox();
QWidget* widget = new QWidget();
QHBoxLayout* layout = new QHBoxLayout(widget);
layout->addWidget(checkBox);
layout->setAlignment(Qt::AlignCenter);
layout->setContentsMargins(0, 0, 0, 0);
widget->setLayout(layout);
if(m_controlstatus==false) checkBox->setEnabled(false); // 设置复选框为不可选中状态
else checkBox->setEnabled(true); // 设置复选框为可选中状态
connect(checkBox,&QCheckBox::stateChanged,this,[=](int state){
//获取当前行的IP
QString ip = ui->tableWidget->item(row, HEAD_BASEMSG_IP)->text();//可以继承到row
//qDebug()<< __LINE__ << "state:"<<state;
qDebug()<< __LINE__ << "row:"<<row << "ip:"<<ip;
m_iplist.append(ip);
if (state == Qt::Checked) {
for(int i=0;i<HEAD_BASEMSG_NUM;i++){
QTableWidgetItem *item = ui->tableWidget->item(row, i);
//if(i==0) {item->setText("");}
item->setBackground(QBrush(QColor("#308cc6")));
item->setForeground(Qt::white);
}
// 改变操作项图标文件(颜色变化)
QWidget *container = ui->tableWidget->cellWidget(row, HEAD_BASEMSG_OPT);
if (container) {
QLayout *layout = container->layout();
if (layout) {
if (layout) {
QPushButton *editbtn = qobject_cast<QPushButton *>(layout->itemAt(0)->widget());
QPushButton *deletebtn = qobject_cast<QPushButton *>(layout->itemAt(1)->widget());
editbtn->setIcon(QIcon(":/index/img/edit_ch.png"));
deletebtn->setIcon(QIcon(":/index/img/delete_ch.png"));
}
}
}
}else {
for(int i=0;i<HEAD_BASEMSG_NUM;i++){
QTableWidgetItem *item = ui->tableWidget->item(row, i);
// 设置未选中行的背景颜色为默认颜色
item->setBackground(QBrush(Qt::white));
item->setForeground(Qt::black);
}
// 改变操作项图标文件(颜色变化)
QWidget *container = ui->tableWidget->cellWidget(row, HEAD_BASEMSG_OPT);
if (container) {
QLayout *layout = container->layout();
if (layout) {
if (layout) {
QPushButton *editbtn = qobject_cast<QPushButton *>(layout->itemAt(0)->widget());
QPushButton *deletebtn = qobject_cast<QPushButton *>(layout->itemAt(1)->widget());
editbtn->setIcon(QIcon(":/index/img/edit.png"));
deletebtn->setIcon(QIcon(":/index/img/delete.png"));
}
}
}
}
});
ui->tableWidget->setCellWidget(row, column, widget);
}
if (column == HEAD_BASEMSG_OPT) {
//编辑按钮
QPushButton* edit = new QPushButton();
edit->setIcon(QIcon(":/index/img/edit.png"));
edit->setIconSize(QSize(24, 24));
edit->setStyleSheet("QPushButton { border: none; }");
edit->setCursor(Qt::PointingHandCursor);
//删除按钮
QPushButton* deleteButton = new QPushButton();
deleteButton->setIcon(QIcon(":/index/img/delete.png"));
deleteButton->setIconSize(QSize(24, 24));
deleteButton->setStyleSheet("background-color:rgba(0,0,0,0);border:none;");
deleteButton->setCursor(Qt::PointingHandCursor);
//按钮信号监听
connect(edit,SIGNAL(clicked()),this,SLOT(editBasemsg()));
connect(deleteButton,SIGNAL(clicked()),this,SLOT(delBasemsg()));
QWidget* widget = new QWidget();
QHBoxLayout* layout = new QHBoxLayout(widget);
layout->addWidget(edit);
layout->addWidget(deleteButton);
layout->setAlignment(Qt::AlignCenter);
layout->setContentsMargins(0, 0, 0, 0);
widget->setLayout(layout);
ui->tableWidget->setCellWidget(row, column, widget);
}
}
}
(2)QTableView中创建QCheckBox
QCheckBox需要通过widget加载到QTableView中,代码如下:
//创建勾选项
QCheckBox* checkBox = new QCheckBox();
//创建窗口视图
QWidget* widget = new QWidget();
//创建布局
QHBoxLayout* layout = new QHBoxLayout(widget);
//把勾选项加载到布局中
layout->addWidget(checkBox);
layout->setAlignment(Qt::AlignCenter);
layout->setContentsMargins(0, 0, 0, 0);
//把布局设置到窗口视图中
widget->setLayout(layout);
//把窗口视图中展示到tableWidget的指定位置
ui->tableWidget->setCellWidget(row, column, widget);
QCheckBox勾选项关联的信号和槽的代码参见【(1)创建QTableView列表头】分享的renderTable()函数源代码。
(3)QTableView中创建QPushButton
QPushButton与QCheckBox一样,也是需要widget加载到QTableView,不过可以设置QPushButton的尺寸、背景颜色等友好展示的布局,源码如下所示:
//编辑按钮
QPushButton* edit = new QPushButton();
edit->setIcon(QIcon(":/index/img/edit.png"));
edit->setIconSize(QSize(24, 24));
edit->setStyleSheet("QPushButton { border: none; }");
edit->setCursor(Qt::PointingHandCursor);
//删除按钮
QPushButton* deleteButton = new QPushButton();
deleteButton->setIcon(QIcon(":/index/img/delete.png"));
deleteButton->setIconSize(QSize(24, 24));
deleteButton->setStyleSheet("background-color:rgba(0,0,0,0);border:none;");
deleteButton->setCursor(Qt::PointingHandCursor);
//按钮信号监听
connect(edit,SIGNAL(clicked()),this,SLOT(editBasemsg()));
connect(deleteButton,SIGNAL(clicked()),this,SLOT(delBasemsg()));
QWidget* widget = new QWidget();
QHBoxLayout* layout = new QHBoxLayout(widget);
layout->addWidget(edit);
layout->addWidget(deleteButton);
layout->setAlignment(Qt::AlignCenter);
layout->setContentsMargins(0, 0, 0, 0);
widget->setLayout(layout);
ui->tableWidget->setCellWidget(row, column, widget);
(4)QTableView创建右键菜单
①在头文件中添加右键菜单绑定的槽函数,源码如下:
//tab_basemsg.h
private slots:
//处理右键菜单请求
void tableWidget_MenuRequested(const QPoint &pos);
②设置右键功能及关联信号和槽,并实现槽函数(在槽函数中增加具体的右键菜单名称),源码如下:
//tab_basemsg.cpp
//设置右键菜单功能
ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);
//绑定右键功能槽函数
connect(ui->tableWidget, &QTableWidget::customContextMenuRequested, this, &tab_basemsg::tableWidget_MenuRequested);
//槽函数实现
void tab_basemsg::tableWidget_MenuRequested(const QPoint &pos) {
QModelIndex index = ui->tableWidget->indexAt(pos);//获取当前行
if (!index.isValid()) return;
QMenu menu(this);
QAction *DiplaymsgAction = menu.addAction(tr("查看详情"));
connect(DiplaymsgAction,&QAction::triggered,[=](){
//获取选择的单元格
QList<QTableWidgetItem *> selected_cells = ui->tableWidget->selectedItems();
if(!selected_cells.isEmpty()){
QTableWidgetItem *codeCell = ui->tableWidget->item(selected_cells.first()->row(),HEAD_BASEMSG_CODE);
if(codeCell!=nullptr){
QString code = codeCell->text();
stBasemsg basemsg=m_basemsgmap[code];
basemsgDialg->setModal(false);
basemsgDialg->setWindowTitle("保存");
//basemsgDialg->setFixedSize(500,400);
basemsgDialg->open();
basemsgDialg->init(1,basemsg);
basemsgDialg->exec();
}
}
});
QAction *NetpingAction = menu.addAction(tr("Ping此计算机"));
connect(NetpingAction,&QAction::triggered,[=](){
//获取选择的单元格
QList<QTableWidgetItem *> selected_cells = ui->tableWidget->selectedItems();
if(!selected_cells.isEmpty()){
QTableWidgetItem *codeCell = ui->tableWidget->item(selected_cells.first()->row(),HEAD_BASEMSG_CODE);
if(codeCell!=nullptr){
QString code = codeCell->text();
stBasemsg basemsg=m_basemsgmap[code];
QString ip=basemsg.Ip;
qDebug() << __LINE__ << ip;
pingdlg->setIp(ip);
pingdlg->setModal(false);
pingdlg->setWindowTitle("PING测试");
pingdlg->setFixedSize(500,400);
pingdlg->open();
pingdlg->init();
pingdlg->exec();
}
}
});
menu.exec(QCursor::pos());
//menu.exec(ui->tableWidget->mapToGlobal(pos));
}
篇尾
因为多个勾选项很多情况下涉及多项数据的处理,有些处理是要异步才不会导致主界面卡顿,下一篇用多线程+ping+全局变量+结果展示技术点(【QT常用技术讲解】多线程处理+全局变量处理异步事件并获取多个线程返回的结果),来详细讲解【多线程解决QTableView多勾选项右键菜单功能卡顿问题】。