自定义QTableWidget实现分页

QT自带没有分页组件,加载表格大数据的时候有些不方便,因此打算全部用源码自定义一个表格+分页,这样方便以后移植。

具体思路如下:

  1.   先实现一个分页组件
  2.  然后用代码定义一个PageTable类,将分页组件与QTableWidget封装进去
  3. 使用封装好的PageTable

完整源码 

核心代码如下:

  • 自定义Page组件 类
#include "PageWidget.h"
#include "ui_PageWidget.h"

#include <QtGlobal>
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QKeyEvent>
#include <QDebug>

PageWidget::PageWidget(int blockSize, QWidget *parent) : QWidget(parent),
    ui(new Ui::PageWidget) {
    ui->setupUi(this);
    setBlockSize(blockSize);
    initialize();

    maxPage = 0;
    setMaxPage(1);
}

PageWidget::~PageWidget() {
    delete ui;
    delete pageLabels;
}

bool PageWidget::eventFilter(QObject *watched, QEvent *e) {
    if (e->type() == QEvent::MouseButtonRelease) {
        int page = -1;
        if (watched == ui->previousPageLabel) { page = getCurrentPage() - 1; }

        if (watched == ui->nextPageLabel) { page = getCurrentPage() + 1; }

        for (int i = 0; i < pageLabels->count(); ++i) {
            if (watched == pageLabels->at(i)) {
                page = pageLabels->at(i)->text().toInt();
                break;
            }
        }

        if (-1 != page) {
            setCurrentPage(page, true);
            return true;
        }
    }

    if (watched == ui->pageLineEdit && e->type() == QEvent::KeyRelease) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(e);
        if (ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return) {
            setCurrentPage(ui->pageLineEdit->text().toInt(), true);
            //setMaxPage(ui->pageLineEdit->text().toInt()); // 测试生成多个页码
            return true;
        }
    }

    return QWidget::eventFilter(watched, e);
}

int PageWidget::getBlockSize() const {
    return blockSize;
}

int PageWidget::getMaxPage() const {
    return maxPage;
}

int PageWidget::getCurrentPage() const {
    return currentPage;
}

void PageWidget::setMaxPage(int page) {
    page = qMax(page, 1);

    if (maxPage != page) {
        this->maxPage = page;
        this->currentPage = 1;
        updatePageLabels();
    }
}

void PageWidget::setCurrentPage(int page, bool signalEmitted) {
    page = qMax(page, 1);
    page = qMin(page, maxPage);

    if (page != this->currentPage) {
        this->currentPage = page;
        updatePageLabels();

        if (signalEmitted) {
            emit currentPageChanged(page);
        }
    }
}

void PageWidget::setBlockSize(int blockSize) {
    // 为了便于计算, block size 必须是奇数, 且最小为3
    blockSize = qMax(blockSize, 3);
    if (blockSize % 2 == 0) {
        ++blockSize;
    }
    this->blockSize = blockSize;
}

// 初始化页码的labels
// 分成三个部分, 左...中...右
void PageWidget::initialize() {
    ui->pageLineEdit->installEventFilter(this);
    ui->pageLineEdit->setValidator(new QIntValidator(1, 10000000, this));

    ui->nextPageLabel->setProperty("page", "true");
    ui->previousPageLabel->setProperty("page", "true");
    ui->nextPageLabel->installEventFilter(this);
    ui->previousPageLabel->installEventFilter(this);

    pageLabels = new QList<QLabel *>();

    QHBoxLayout *leftLayout = new QHBoxLayout();
    QHBoxLayout *centerLayout = new QHBoxLayout();
    QHBoxLayout *rightLayout = new QHBoxLayout();
    leftLayout->setContentsMargins(0, 0, 0, 0);
    leftLayout->setSpacing(0);
    centerLayout->setContentsMargins(0, 0, 0, 0);
    centerLayout->setSpacing(0);
    rightLayout->setContentsMargins(0, 0, 0, 0);
    rightLayout->setSpacing(0);

    for (int i = 0; i < blockSize * 3; ++i) {
        QLabel *label = new QLabel(QString::number(i + 1));
        label->setProperty("page", "true");
        label->installEventFilter(this);

        pageLabels->append(label);

        if (i < blockSize) {
            leftLayout->addWidget(label);
        } else if (i < blockSize * 2) {
            centerLayout->addWidget(label);
        } else {
            rightLayout->addWidget(label);
        }
    }

    ui->leftPagesWidget->setLayout(leftLayout);
    ui->centerPagesWidget->setLayout(centerLayout);
    ui->rightPagesWidget->setLayout(rightLayout);
}

void PageWidget::updatePageLabels() {
    ui->leftSeparateLabel->hide();
    ui->rightSeparateLabel->hide();

    if (maxPage <= blockSize * 3) {
        for (int i = 0; i < pageLabels->count(); i += 1) {
            QLabel *label = pageLabels->at(i);

            if (i < maxPage) {
                label->setText(QString::number(i + 1));
                label->show();
            } else {
                label->hide();
            }

            if (currentPage - 1 == i) {
                label->setProperty("currentPage", "true");
            } else {
                label->setProperty("currentPage", "false");
            }

            label->setStyleSheet("/**/");
        }
        return;
    }

    // 以下情况为maxPageNumber大于blockSize * 3, 所有的页码label都要显示
    // c 为 currentPage
    // n 为 block size
    // m 为 maxPage

    // 1. c ∈ [1, n + n/2 + 1]: 显示前 n * 2 个, 后 n 个: 只显示右边的分隔符
    // 2. c ∈ [m - n - n/2, m]: 显示前 n 个, 后 n * 2 个: 只显示左边的分隔符
    // 3. 显示[1, n], [c - n/2, c + n/2], [m - 2*n + 1, m]: 两个分隔符都显示

    int c = currentPage;
    int n = blockSize;
    int m = maxPage;
    int centerStartPage = 0;

    if (c >= 1 && c <= n + n / 2 + 1) {
        // 1. c ∈ [1, n + n/2 + 1]: 显示前 n * 2 个, 后 n 个: 只显示右边的分隔符
        centerStartPage = n + 1;
        ui->rightSeparateLabel->show();
    } else if (c >= m - n - n / 2 && c <= m) {
        // 2. c ∈ [m - n - n/2, m]: 显示前 n 个, 后 n * 2 个: 只显示左边的分隔符
        centerStartPage = m - n - n + 1;
        ui->leftSeparateLabel->show();
    } else {
        // 3. 显示[1, n], [c - n/2, c + n/2], [m - n + 1, m]: 两个分隔符都显示
        centerStartPage = c - n / 2;
        ui->rightSeparateLabel->show();
        ui->leftSeparateLabel->show();
    }

    for (int i = 0; i < n; ++i) {
        pageLabels->at(i)->setText(QString::number(i + 1));                     // 前面 n 个
        pageLabels->at(n + i)->setText(QString::number(centerStartPage + i));   // 中间 n 个
        pageLabels->at(3 * n - i - 1)->setText(QString::number(m - i));         // 后面 n 个
    }

    for (int i = 0; i < pageLabels->count(); ++i) {
        QLabel *label = pageLabels->at(i);
        int page = label->text().toInt();
        if (page == currentPage) {
            label->setProperty("currentPage", "true");
        } else {
            label->setProperty("currentPage", "false");
        }

        label->setStyleSheet("/**/");
        label->show();
    }
}
  •  封装后的PageTable类
#include "PageTable.h"
#include <QTableWidget>
#include <QDebug>
#include <QHeaderView>


PageTable::PageTable(QStringList &header,int rowCount)
{


    qDebug()<<" PageTable init ,rowCount:"<<rowCount << ",header size:"<<header.size();

    tableWidget = new QTableWidget(rowCount,header.size());//构造一个10行5列的表格
    tableWidget->setWindowTitle("Title");
    tableWidget->setHorizontalHeaderLabels(header);
    tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);//设置表格为单行选择
    tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);//设置只能选中行,不能单个选择单元格
    tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);//设置单元格不可编辑
    tableWidget->verticalHeader()->setHidden(true);// 隐藏行号 (不显示前面行号)
    tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//让表格挤满占个父容器
//    for(int i = 1;i<header.size();i++)
//        tableWidget->horizontalHeader()->setSectionResizeMode(i,QHeaderView::Interactive);   //然后设置要根据内容使用宽度的列(其他没设置的列自动缩放)


//    for(int i = 0;i<rowCount;i++){
//        tableWidget->setItem(i,0, new QTableWidgetItem("context"));
//        tableWidget->item(i,0)->setTextAlignment(Qt::AlignLeft|Qt::AlignVCenter);
//        tableWidget->setRowHeight(i,25);
//    }

    //设置表头样式
    tableWidget->setStyleSheet("QHeaderView::section {"
                               "color: black;font:bold 14px \"微软雅黑\";"
                               "text-align:center;"
                               "height:25px;"
                               "background-color: #d1dff0;"
                               " border:1px solid #8faac9;"
                               "border-left:none;"
                               "}");

    QHBoxLayout *hLayout = new QHBoxLayout();//让PageWidget水平居中
    pageWidget = new PageWidget();
    //pageWidget->setMaxPage(20);
    hLayout->addWidget(pageWidget);

    // 分页组件的css,这个内容应该放到普通文件中然后加载
    QString qss = QString(".QLabel[page=\"true\"] { padding: 1px; }")
            + QString(".QLabel[currentPage=\"true\"] { color: rgb(190, 0, 0);}")
            + QString(".QLabel[page=\"true\"]:hover { color: white; border-radius: 4px; background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(53, 121, 238, 255), stop:1 rgba(0, 202, 237, 255));}");
    pageWidget->setStyleSheet(qss);


    this->addWidget(tableWidget);
    this->addLayout(hLayout);

    tableWidget->horizontalHeader()->size();//列

}

void PageTable::SetData(QList<QList<QString>> &DataList)
{
   for(int i = 0;i<DataList.size();i++){

        QList<QString> Item = DataList[i];
        for(int j = 0;j<Item.size();j++){
            this->tableWidget->setItem(i,j, new QTableWidgetItem(Item[j]));
        }
   }
}



PageTable::~PageTable()
{
    qDebug() << "~PageTable() invoke..." ;
}
  •   使用
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QVBoxLayout>
    #include <QHBoxLayout>
    #include <QTableWidget>
    #include <QDebug>
    #include "pageWidget/PageTable.h"
    
    
    
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        qDebug() << "[Debug] MyObject::test ";
    
        QStringList header;
        header<<"T1"<<"T2"<<"T3"<<"T4"<<"T5"<<"T6"<<"T7";
        pageTable = new PageTable(header,5);
        ui->testLayout->addLayout(pageTable);
    
        connect(pageTable->pageWidget, SIGNAL(currentPageChanged(int)), this, SLOT(PageChange(int)));
    
    }
    
    QList<QList<QString>> DataList;//数据
    int RowIndex = 0;
    
    void MainWindow::LoadPage(int pageIndex){
    
        DataList.clear();//先清空,只缓存一页。如果有100万条,缓存到List不合适
    
        for(int i = 0;i< 10;i++){//10行
            QList<QString> Row;
            RowIndex += 1;
            Row.append(QString("Data_1_%1_%2").arg(RowIndex).arg(pageIndex));
            Row.append(QString("Data_2_%1_%2").arg(RowIndex).arg(pageIndex));
            Row.append(QString("Data_3_%1_%2").arg(RowIndex).arg(pageIndex));
            Row.append(QString("Data_4_%1_%2").arg(RowIndex).arg(pageIndex));
            Row.append(QString("Data_5_%1_%2").arg(RowIndex).arg(pageIndex));
            Row.append(QString("Data_6_%1_%2").arg(RowIndex).arg(pageIndex));
            Row.append(QString("Data_7_%1_%2").arg(RowIndex).arg(pageIndex));
            DataList.append(Row);
        }
        pageTable->SetData(DataList);
    }
    
    void MainWindow::BtnLoadDataClick(){
    
        qDebug() << "click ...."<<RowIndex;
        pageTable->pageWidget->setMaxPage(10);//假如有10页数据
        pageTable->pageWidget->setCurrentPage(1);
        RowIndex = 0;
        LoadPage(1);//加载第一页
    
    
    }
    
    
    void MainWindow::PageChange(int currentPage){
    
        qDebug()<<"pageChagne"<<currentPage;
        this->LoadPage(currentPage);
    }
    
    
    
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    

    效果如下:

猜你喜欢

转载自blog.csdn.net/PZ0605/article/details/108715079
今日推荐