今天主要介绍QT中tabwidget的用法,即怎样利用表格存储数据并对表里的数据进行其他类似excel 的操作,具体包括:
1.选中方式,单行选中或者多行选中;
2.复制行,可以将单行或者多行选中的内容复制到剪贴板,之后就可以复制到excel或者其他任何地方;
3.多选行,选中单行或者选中多行甚至全选;
4.删除,删除所选中行或者清空整个tabwidget等功能;
主要想实现的效果如下:
我们要实现的功能对应到ui上是鼠标右键的下拉菜单,这里就必须实现contextMenuEvent事件重写:
具体实现为如下代码:
/// 在tabwidget上增加鼠标右键下拉菜单,并增加五种对应子功能:单行复制、带表头复制、单行删除、全删、全选;
void contextMenuEvent(QContextMenuEvent* e)
{
// 首先判断鼠标目前位置是否在tablewidget上
if(ui->tableWidget_results_info->underMouse()){
QMenu *menu = new QMenu();
menu->addSeparator();
menu->addSeparator();
QAction* Act_Copy;
QAction* Act_Copy_with_Header;
QAction* Act_Delete;
QAction* Act_Delete_All;
QAction* Act_Selete_All;
Act_Copy = new QAction(tr("复制"), this);
//想要添加icon图标的话可以使用seticon实现
// Act_Copy->setIcon(QIcon("Resources/logo.png"));
Act_Copy_with_Header = new QAction(tr("带表头复制"), this);
// Act_Copy_with_Header->setIcon(QIcon("Resources/logo.png"));
Act_Delete = new QAction(tr("删除"), this);
Act_Delete_All = new QAction(tr("删除全部"), this);
Act_Selete_All = new QAction(tr("全选"), this);
menu->addAction(Act_Copy);
menu->addSeparator();
menu->addSeparator();
menu->addAction(Act_Copy_with_Header);
menu->addSeparator();
menu->addSeparator();
menu->addAction(Act_Delete);
menu->addSeparator();
menu->addSeparator();
menu->addAction(Act_Delete_All);
menu->addSeparator();
menu->addSeparator();
menu->addAction(Act_Selete_All);
menu->addSeparator();
menu->addSeparator();
// 连接各个功能对应的实现槽函数
connect(Act_Copy, SIGNAL(triggered()), this, SLOT(Copy_Line()));
connect(Act_Copy_with_Header, SIGNAL(triggered()), this, SLOT(Copy_Lines()));
connect(Act_Delete, SIGNAL(triggered()), this, SLOT(Delete_Line()));
connect(Act_Delete_All, SIGNAL(triggered()), this, SLOT(Delete_Lines()));
connect(Act_Selete_All, SIGNAL(triggered()), this, SLOT(Selete_Lines()));
menu->exec(e->globalPos());
delete menu;
}
}
然后具体说明以下函数具体内容:首先我们要明确先要实现选择区域范围的读取然后再对应到子功能上,打比方就是:如果是全选内容后,复制操作则是复制全选的内容;如果是选择的是某一行,那么复制操作则是复制选中的某一行的内容即可;同理,删除也是一样的思路;所以这里首先说明获取tabwidget中选中区域的范围;即起始行和终止行的行数,当选中的是某一行时,这两个值是同一值而已;
QT中的selectedRanges()函数就是帮助我们获取当前tabwidget中选中区域的范围,返回值是Qlist类型,其中包括4个值,即top(起始行), bottom(终止行),left(起始列)和right(中止列);
QList<int> selete_line_range(){
QList<QTableWidgetSelectionRange> range = ui->tableWidget_results_info->selectedRanges();
// 因为我们设置了tabwidget的选中方式为行选中,所以关于列的两个参数对我们没有帮助
int top, bottom;
// 当选中的区域是单行时,list仅有1个元素,所以直接读取id为0的top和bottom
if(1==range.length()){
top = range[0].topRow();
bottom = range[0].bottomRow();
}
// 当选中的区域为全选时,list会有多个元素,所以起始行则为id为0的top,终止行为id是list最后一个元素的bottom
else {
top = range[0].topRow();
bottom = range[range.length()-1].bottomRow();
}
// 将获取到的top和bottom两个值放进新的QList并返回以供调用
QList<int> range_final;
range_final.append(top);
range_final.append(bottom);
return range_final;
}
全选功能:
void Selete_Lines(){
printf("Selete_Lines");
// 首先更改行选中方式为多行选中
ui->tableWidget_results_info->setSelectionMode(QAbstractItemView::MultiSelection);
// 清空目前所选高亮行
ui->tableWidget_results_info->clearSelection();
// 获取当前所有行数目
int rows = ui->tableWidget_results_info->rowCount();
for(int subrow=0; subrow<rows; subrow++){
// 当每行第一个cell值不为空时直接选中此行,反之,不做任何操作
if(ui->tableWidget_results_info->item(subrow, 0)!=NULL){
ui->tableWidget_results_info->selectRow(subrow);
}
}
// 最后更改行选中方式为extend,这种选中方式即一般为单行选中,当使用ctrl键辅助则可多行选中
ui->tableWidget_results_info->setSelectionMode(QAbstractItemView::ExtendedSelection);
}
复制功能:
void Copy_Line(){
printf("Copy_Line");
QList<int> range_final = selete_line_range();
int row_start=range_final[0];
int row_end = range_final[1];
int colnum = ui->tableWidget_results_info->columnCount();
QString clipText;
QString text;
for(int subrow=row_start; subrow<=row_end; subrow++){
for(int subcol=0; subcol<colnum; subcol++){
// 当cell不为空时获取文本,否则设置为“”
if(ui->tableWidget_results_info->item(subrow, subcol)!=NULL)
text = ui->tableWidget_results_info->item(subrow, subcol)->text();
else {
text= "";
}
clipText.append(text);
clipText.append("t");
}
clipText.append("n");
}
clipText.chop(1);//删除末尾一个字符
clipText.append("n");
// 将获取的文本放到剪贴板
QClipboard *clipboard = QApplication::clipboard();
clipboard->clear();
clipboard->setText(clipText);
}
带表头复制:
void Copy_Lines(){
printf("Copy_Lines");
int colnum = ui->tableWidget_results_info->columnCount();
QString clipText;
// 先复制表头
for(int col=0; col<colnum; col++){
QString text;
if(ui->tableWidget_results_info->horizontalHeaderItem(col)!=NULL)//这个很重要
text = ui->tableWidget_results_info->horizontalHeaderItem(col)->text();
else {
text= "";
}
clipText.append(text);
clipText.append("t");
}
// 表头和行之间不要忘记换行符
clipText.append("n");
QList<int> range_final = selete_line_range();
int row_start=range_final[0];
int row_end = range_final[1];
QString text;
for(int subrow=row_start; subrow<=row_end; subrow++){
for(int subcol=0; subcol<colnum; subcol++){
if(ui->tableWidget_results_info->item(subrow, subcol)!=NULL)
text = ui->tableWidget_results_info->item(subrow, subcol)->text();
else {
text= "";
}
clipText.append(text);
clipText.append("t");
}
// 行与行之间也不要忘记换行符
clipText.append("n");
}
clipText.chop(1);//删除末尾一个字符
clipText.append("n");
clipboard->clear();
clipboard->setText(clipText);
}
删除功能:
void Delete_Line(){
printf("Delete_Line");
int rowcount = ui->tableWidget_results_info->rowCount();
QList<int> range_final = selete_line_range();
int row_start=range_final[0];
int row_end = range_final[1];
for(int subrow=row_start; subrow<=row_end; subrow++){
// 删除一行内容后为了保证原表行数不变则需要移除动作之后随即插入新行
ui->tableWidget_results_info->removeRow(row_start);
ui->tableWidget_results_info->insertRow(rowcount-1);
}
}
清空功能:
void Delete_Lines(){
printf("Delete_Lines");
ui->tableWidget_results_info->clearContents();
}
我们的实现效果如下: