QTableWidget表格控件的常用功能示例;

使用QSS修改界面样式

  • 修改QHeaderView表头样式

设置表头样式示例

QHeaderView::section {
	font: 75 12px "微软雅黑";
	font-size: 12px;
	color: #333333;
	line-height: 34px;
	background-color: rgba(245, 245, 245, 255);
	height: 34px; /*设置每个节点的高度*/
	border: 0px;
	padding-left: 5px;
}
  • 修改QScrollBar滚动条 常用样式示例

/* ---竖线--- */
QScrollBar:vertical          
{
	width: 10px;
	height: 153px;
	background: #EBEBEB;
	margin:0px,0px,0px,0px;
	padding-top:0px;
	padding-bottom:0px;
	border-radius:4px;
}
QScrollBar::handle:vertical       
{
	width:10px;
	height: 153px;
	background: #D6D6D6;
	border-radius:4px;
	min-height:20px;
}
QScrollBar::handle:vertical:hover 
{
	width:10px;
	border-radius:4px;
	min-height:20px;
}
QScrollBar::add-line:vertical
{
	height:0px;
	width:10px;
	subcontrol-position:bottom;
}
QScrollBar::sub-line:vertical
{
	height:0px;width:10px;
	subcontrol-position:top;
}
QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical
{
	border-radius:4px;
}



/* ---横向--- */
QScrollBar:horizontal          
{
	width: 153px;
	height: 10px;
	background: #EBEBEB;
	margin:0px,0px,0px,0px;
	padding-top:0px;
	padding-bottom:0px;
	border-radius:4px;
}
QScrollBar::handle:horizontal       
{
	width:153px;
	height: 10px;
	background: #D6D6D6;
	border-radius:4px;
	min-width:20px;
}
QScrollBar::handle:horizontal:hover 
{
	height:10px;
	border-radius:4px;
	min-width:20px;
}
QScrollBar::add-line:horizontal
{
	height:10px;
	width:0px;
	subcontrol-position:right;
}
QScrollBar::sub-line:horizontal
{
	height:10px;width:0px;
	subcontrol-position:left;
}
QScrollBar::add-page:horizontal,QScrollBar::sub-page:horizontal
{
	border-radius:4px;
}
  • 修改QTableWidget 常用样式示例

包括修改QTableWidget控件字体,单元格高度,移除边框等常用功能样式。

QTableWidget{
border:0px;
font: 75 12px "微软雅黑";
font-size: 12px;
background-color: rgb(255, 255, 255);
line-height: 19px;
}
QTableWidget::item {
        height: 35px; /*设置每个节点的高度*/
        border: none; /*去除边框*/
		color: #333333;
		font: 75 14px "微软雅黑";
		line-height: 14px;
		text-align: left;
		padding-left: 5px;
    }   
 	QTableWidget::item:selected {
        border-image: none; /*去除边框 ,QTreeWidget::branch:selected*/
		border: none;	
    }	

	QTableWidget::indicator:checked {
		width:18px;
		height:18px;
        border-image: none; /*去除边框 ,QTreeWidget::branch:selected*/
		image: url(:/Image/cleanC/checked.png);
	}
	QTableWidget::indicator:unchecked {
		width:18px;
		height:18px;
        border-image: none; /*去除边框 ,QTreeWidget::branch:selected*/
		image: url(:/Image/cleanC/unchecked.png);
	}

	QTableWidget::item:hover{
        background-color: #F5F5F5; /*设置选中节点的背景色 ,QTreeWidget::branch:hover*/
		color: #333333;
        border-image: none; /*去除边框*/
    }

实现效果:
在这里插入图片描述

使用QScrollBar滚动条 - 动态加载数据

数据处理的时候,如果QTableWidget表格控件一次性加载太多数据,会造成界面上的卡顿,通过QScrollBar竖直滚动条信号动态加载数据,一次加载个几百条数据就能解决这个问题,
类似于网页的动态加载:

  • 首先定义一个根据开始索引加载条数加载数据的方法:
  • 设置 setFlags(rowid->flags()^Qt::ItemIsEditable); 禁用单元格编辑
  • 设置 setData(Qt::DisplayRole,QVariant::fromValue(Datas[i].ParentDirectoryRecord)用于单元格排序
//! dataLists 是总数据源,
//! int start 从什么地方开始
//! int step 要加载多少条
void QTableWindow::LoadDataBy(int start,int step)
{
    QList<NTFSMFT_DATA> Datas=dataLists.mid(start,step);
    for(int i=0;i<Datas.count();i++)
    {
    	//! 一条一条的插入
        int row=ui->tableWidget->rowCount();
        ui->tableWidget->insertRow(row);

        QTableWidgetItem* rowid=new QTableWidgetItem();
        rowid->setFlags(rowid->flags()^Qt::ItemIsEditable);
        rowid->setData(Qt::DisplayRole,QVariant::fromValue(Datas[i].Row));
        ui->tableWidget->setItem(row,0,rowid);

        QTableWidgetItem* path=new QTableWidgetItem(Datas[i].lpszFileName);
        path->setFlags(path->flags()^Qt::ItemIsEditable);
        path->setToolTip(Datas[i].lpszFileName);
        ui->tableWidget->setItem(row,1,path);

        QTableWidgetItem* IsDirectory=new QTableWidgetItem(Datas[i].IsDirectory?"DIR":"FILE");
        IsDirectory->setFlags(IsDirectory->flags()^Qt::ItemIsEditable);
        ui->tableWidget->setItem(row,2,IsDirectory);

        QTableWidgetItem* ParentDirectoryRecord=new QTableWidgetItem();
        ParentDirectoryRecord->setData(Qt::DisplayRole,QVariant::fromValue(Datas[i].ParentDirectoryRecord));
        ParentDirectoryRecord->setFlags(ParentDirectoryRecord->flags()^Qt::ItemIsEditable);
        ui->tableWidget->setItem(row,3,ParentDirectoryRecord);

        QTableWidgetItem* MftRecordIndex=new QTableWidgetItem();
        MftRecordIndex->setData(Qt::DisplayRole,QVariant::fromValue(Datas[i].MftRecordIndex));
        MftRecordIndex->setFlags(MftRecordIndex->flags()^Qt::ItemIsEditable);
        ui->tableWidget->setItem(row,4,MftRecordIndex);

        QTableWidgetItem* AllocatedFileSize=new QTableWidgetItem();
        AllocatedFileSize->setFlags(AllocatedFileSize->flags()^Qt::ItemIsEditable);
        AllocatedFileSize->setData(Qt::DisplayRole,QVariant::fromValue(Datas[i].AllocatedFileSize.toLongLong()));
        ui->tableWidget->setItem(row,5,AllocatedFileSize);

        QTableWidgetItem* selectPath=new QTableWidgetItem("查看");
        selectPath->setFlags(selectPath->flags()^Qt::ItemIsEditable);
        selectPath->setData(Qt::UserRole,Datas[i].lpszFileName);
        ui->tableWidget->setItem(row,6,selectPath);
    }

}
  • 再绑定QScrollBar竖直滚动条的 QScrollBar::valueChanged信号加载数据
//! 加载步长
#define LOADSTEP 500
//! 动态加载数据
connect(ui->tableWidget->verticalScrollBar(),&QScrollBar::valueChanged,this,[&](int value){
    QScrollBar* bar=(QScrollBar*)sender();
    //! 加载数据
    if(value==bar->maximum() //! 已经滑动到最后一条数据
            && dataLists.count()>0 //! 数据源不为空
            && ui->tableWidget->rowCount()!=dataLists.count() //! 加载的数据总条数与数据源不相等
    ){
        LoadDataBy(ui->tableWidget->rowCount(),LOADSTEP);
    }
});

简单实现动态加载数据。

使用QHeaderView标题和sortItems方法排序

对数据源的排序建议直接使用qSort()函数进行排序
这里指的是使用的是QTableWidget表格控件和QHeaderView标题控件对已经加载的表格数据进行排序,

  • 需要在加载数据前先启用排序
    ui->tableWidget->horizontalHeader()->setSortIndicatorShown(true);
  • 再绑定QHeaderView::sortIndicatorChanged信号
 //! 标题排序
    connect(ui->tableWidget->horizontalHeader(),&QHeaderView::sortIndicatorChanged,this,[&](int logicalIndex, Qt::SortOrder order){
        ui->tableWidget->sortItems(logicalIndex,order);
    });

实现点击标题排序,像这样:
在这里插入图片描述
值得注意的是:
想要单元格按数据类型排序而是不按字符串排序:
必须设置setData(Qt::DisplayRole,QVariant::fromValue(T))
而不是在创建单元格时直接赋值:
QTableWidgetItem* ParentDirectoryRecord=new QTableWidgetItem(QString::number(T));
T:是数据类型,如果需要单元格结构体排序,尝试运算符重载 (operator)
参考:

QTableWidgetItem* FileSize=new QTableWidgetItem();
FileSize->setFlags(FileSize->flags()^Qt::ItemIsEditable);
FileSize->setData(Qt::DisplayRole,QVariant::fromValue(Datas[i].FileSize.toLongLong()));
ui->tableWidget->setItem(row,5,FileSize);

使用QStyledItemDelegate实现QPushButton控件简单样式

一开始在实现 <查看 >这个单元格样式,以及鼠标移上去显示下划线这个效果时
在这里插入图片描述
我是直接在QTableWidget表格控件中插入的QPushButton 控件然后设置QSS样式,像这样:

 QPushButton*  pBut_Select = new QPushButton(ui->tableWidget);
  pBut_Select->setObjectName(QString::fromUtf8("pBut_Select"));
  pBut_Select->setMaximumSize(QSize(28, 35));
  pBut_Select->setCursor(QCursor(Qt::PointingHandCursor));
  pBut_Select->setStyleSheet(QString::fromUtf8("QPushButton\n"
      "{background-color:transparent;\n"
      "font: 75 14px \"\345\276\256\350\275\257\351\233\205\351\273\221\";\n"
      "font-size: 14px;\n"
      "color: #079F41;\n"
      "line-height: 19px;\n"
      "border:0px;\n"
      "}\n"
      "QPushButton:hover\n"
      "{\n"
      "	font-weight: bold;\n"
      "   text-decoration:underline;"
      "}"));
  pBut_Select->setFlat(true);
  pBut_Select->setText("查看");
  pBut_Select->setProperty("filepath",Datas[i].lpszFileName);
  connect(pBut_Select,&QPushButton::clicked,this,[&](bool check){
//           QPushButton* button=(QPushButton*)sender();
//           if(ISNOTNULL(button))
//                Explorer_Select(button->property("filepath").toString());
  });
  ui->tableWidget->setCellWidget(row,6,pBut_Select);

结果发现在QTableWidget控件中动态添加QPushButton控件或者QLabel控件时加载速度非常慢,于是考虑使用QStyledItemDelegate直接绘制单元格样式。

QStyledItemDelegate类主要用于自定义表格单元格的编辑器小部件,也可以直接重写void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override事件绘制单元格。

重写QStyledItemDelegate

要实现上面QPushButton控件的效果只需要重写

  //! 事件监控
    bool eventFilter(QObject *object, QEvent *event) override;
    //! 重新绘制
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
    /*不需要重写createEditor(),setEditorData()和setModelData()函数实现编译器功能*/

两个函数。
如果只是要在 单元格获取到焦点时 -> 绘制下划线,只需要在
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
事件中使用
if(option.state & QStyle::State_MouseOver){}
判断 鼠标是否在单元格范围内
但是我希望在鼠标移动到 <查看 >这两个字上面的时候添加下滑线,
就需要通过重写bool eventFilter(QObject *object, QEvent *event) override;事件,
获取鼠标的移动坐标:

bool eventFilter(QObject *object, QEvent *event)
{
    /*此处获取不到 MouseButtonPress 事件*/
     if (event->type() == QEvent::HoverMove && object == this->parent())
     {
        //! 鼠标在单元格上移动
         QHoverEvent *hoverEvent = static_cast<QHoverEvent *>(event);
         QTableWidget* parentW=(QTableWidget*)(this->parent());
         if(parentW!=NULL && parentW!=nullptr){
             QModelIndex index = parentW->indexAt(hoverEvent->pos());
             if(index.isValid()){
                 //! 计算坐标时需要减去表格标题的高度
                 mouseLocal=hoverEvent->pos()-QPoint(0,parentW->horizontalHeader()->height());
                 if(index.column()==6)
                     parentW->repaint();
             }
         }
     }
     return QStyledItemDelegate::eventFilter(object, event);
}

再在void paint(QPainter *painter,const QStyleOptionViewItem &option, const QModelIndex &index) const方法中绘制下划线

void  paint(QPainter *painter,const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    painter->save();
    painter->setPen(QColor("#079F41"));
    const QRect rectangle = option.rect;
    QRect boundingRect;
    //! 绘制< 查看 >文本内容,并返回文本框
    painter->drawText(rectangle, Qt::AlignCenter, index.data().toString(), &boundingRect);

	//! 如果鼠标在文字上方 添加下划线 否则只绘制文本内容
    if(boundingRect.contains(mouseLocal))
    {
        QPen pen = painter->pen();
        pen.setStyle(Qt::SolidLine);
        painter->setPen(pen);
        //! 在文本框内,添加下划线
        painter->drawLine(boundingRect.bottomLeft()+QPoint(0,-1),boundingRect.bottomRight()+QPoint(0,-1));

    }

    /* 示例 --如果对坐标边框这些不了解可以取消注释看看,一看就懂
    //! 绘制文本表格
    QPen pen = painter->pen();
    pen.setStyle(Qt::DotLine);
    painter->setPen(pen);
    painter->drawRect(boundingRect.adjusted(0, 0, -painter->pen().width(), -painter->pen().width()));

    //! 绘制实际单元格边框
    pen.setStyle(Qt::DashLine);
    painter->setPen(pen);
    painter->drawRect(rectangle.adjusted(0, 0, -pen.width(), -pen.width()));

    //! 绘制鼠标所选的单元格边框
    pen.setStyle(Qt::SolidLine);
    painter->setPen(pen);
    painter->drawRect(visualRect.adjusted(0, 0, -pen.width(), -pen.width()));

    //! 绘制文本表格右下点
    QPen pen2 = painter->pen();
    pen2.setColor(Qt::red);
    painter->setPen(pen2);
    painter->drawPoint(boundingRect.bottomLeft());

    //绘制鼠标点 跟随鼠标移动
    QPen pen3 = painter->pen();
    pen3.setColor(Qt::red);
    pen3.setWidth(3);
    painter->setPen(pen3);
    painter->drawPoint(mouseLocal);
    */
    painter->restore();

再将重写后的QStyledItemDelegate类绑定到QTableWidget表格控件中,实现QPushButton控件简单样式。

    TQLabelDelegate* delegate=new TQLabelDelegate(ui->tableWidget);
    //! 启用事件监控
    ui->tableWidget->installEventFilter(delegate);
    ui->tableWidget->setItemDelegateForColumn(6,delegate);

本来还打算在实现 点击文本的时候触发点击事件
但是QStyledItemDelegate类的
bool eventFilter(QObject *object, QEvent *event) override
获取不到 QEvent::MouseButtonPress 事件,
就只能使用QTableWidget控件自带的单元格点击事件。

QHeaderView::ResizeMode 调整单元格列宽度小技巧

QHeaderView::ResizeMode 是 Qt 框架中的一个枚举类型,它用来定义表头视图(QHeaderView)中的单元格是否可以通过用户交互来改变大小,以及如何改变大小(出至文言一心)
这个枚举有以下几个值:

  • QHeaderView::Interactive:表头可以通过用户交互来调整大小。
  • QHeaderView::Fixed:表头的大小是固定的,不能通过用户交互来调整。
  • QHeaderView::Stretch:所有表头的空间会被拉伸以填满可用空间。
  • QHeaderView::ResizeToContents:表头的大小会调整到内容的大小。

QTableWidget表格控件不存在按比例调整单元格列宽度的方法,
使用setColumnWidth修改列后,
拖拽标题单元格列宽,依旧会出现横线的滚动条。
为了横线的滚动条不出现,影响界面布局
可以只设置某一列被拉伸以填满可用空间,而其他列设置一个固定宽度:
像这样,就能实现近乎按比例缩放的效果,拉伸的那行除外。

//!固定查看栏高度
ui->tableWidget->setColumnWidth(0,96);
ui->tableWidget->horizontalHeader()->setSectionResizeMode(1,QHeaderView::Stretch);
ui->tableWidget->setColumnWidth(2,96);
ui->tableWidget->setColumnWidth(3,96);
ui->tableWidget->setColumnWidth(4,96);
ui->tableWidget->setColumnWidth(5,96);
ui->tableWidget->setColumnWidth(6,40);
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐