Qt 自定义分页组件——实现数据的分批展示

       分页是应用程序开发中常见的需求,通过分页可以实现数据的分批展示,提高用户体验。下面介绍一个自定义分页控件的基本功能:

  1. 显示指定数量的数据:分页控件可以根据需求设置每一页展示的数据数量,保证页面展示的数据不会过多或过少。

  2. 显示页码信息:分页控件可以显示当前页码、总页数等信息,让用户清楚地知道当前所在的页码和还有多少页数据可以查看。

  3. 点击按钮翻页:分页控件通常包含上一页和下一页的按钮,用户可以通过点击按钮实现翻页功能。

  4. 输入页码跳转:分页控件可以提供一个输入框,用户可以输入指定的页码并点击跳转按钮进行页面跳转。

  5. 边界检查:分页控件需要对页码进行边界检查,确保用户不能跳转到不存在的页码或越界。

  6. 数据更新后重新分页:当数据更新后,分页控件可以根据最新的数据重新计算页数和当前页码,保证分页功能的准确性。

        通过实现以上功能,自定义分页控件可以方便地实现数据分页的需求,提供更好的用户体验。开发者可以根据具体的应用场景和需求来进行定制和扩展。

一、简述

        分页组件是Qt框架中的一个重要组成部分,用于在用户界面中实现数据的分页显示。这个组件使得大量数据能够以更易于管理的方式呈现,提高用户体验,并减轻了系统的内存负担。我们可以利用Qt Designer来创建UI,然后通过代码实现功能,或者直接编写代码来构建分页组件。 

        本分页控件支持显示总页数,支持显示当前页码,支持跳转到指定页,支持显示每页数量。

二、效果

三、代码实现
1、控件实现 
组件设计 PageWidget.ui

 

 头文件PageWidget.h
#ifndef PAGEWIDGET_H
#define PAGEWIDGET_H

#include <QWidget>
#include <QList>

class QLabel;
class QEvent;

namespace Ui {
    class PageWidget;
}

class PageWidget : public QWidget {
    Q_OBJECT

public:
    explicit PageWidget(int recordCount = 20,int blockSize = 3, QWidget *parent = 0);
    ~PageWidget();

    int getBlockSize() const;
    int getMaxPage() const;
    int getCurrentPage() const;

    // 其他组件只需要调用这两个函数即可
    void setMaxPage(int maxPage);   // 当总页数改变时调用
    void setCurrentPage(int currentPage, bool signalEmitted = false); // 修改当前页时调用
    void showLeft();

protected:
    virtual bool eventFilter(QObject *watched, QEvent *e);

signals:
    void currentPageChanged(int page);

    void recordCountChanged(int PageRecordCount);

private:
    Ui::PageWidget *ui;
    int blockSize;
    int maxPage;        //总页数
    int currentPage;    //当前页面
    QList<QLabel *> *pageLabels;
    int PageRecordCount; //每页显示的记录数量

    void setBlockSize(int blockSize);
    void updatePageLabels();
    void initialize();
    void setRecordCount();
};

#endif // PAGEWIDGET_H
实现代码PageWidget.cpp
#include "PageWidget.h"
#include "ui_PageWidget.h"

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

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

    // 分页组件的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));}");
    this->setStyleSheet(qss);

    setBlockSize(blockSize);
    initialize();

    maxPage = 0;
    setMaxPage(1);
    ui->pageLineEdit->setText(QString::number(1));

    PageRecordCount = recordCount;
    ui->spinBox->setValue(PageRecordCount);
    ui->spinBox->installEventFilter(this);
}

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)
        {
            int page = ui->pageLineEdit->text().toInt();
            if(page > maxPage)
            {
                page = maxPage;
                ui->pageLineEdit->setText(QString::number(page));
            }
            setCurrentPage(page, true);
            return true;
        }
    }

    if (watched == ui->spinBox && e->type() == QEvent::KeyRelease) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(e);
        if (ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return)
        {
            int recordCount = ui->spinBox->value();
            if(PageRecordCount != recordCount)
            {
                ui->pageLineEdit->setText(QString::number(1));
                PageRecordCount = recordCount;
                emit recordCountChanged(PageRecordCount);
            }
            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) {
        maxPage = page;
        currentPage = 1;
        updatePageLabels();
    }
}

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

    if (page != currentPage) {
        currentPage = page;
        updatePageLabels();

        ui->spinBox->setValue(PageRecordCount);
        ui->pageLineEdit->setText(QString::number(page));

        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;
    }

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

    if (c >= 1 && c <= n + n / 2 + 1) {
        // 显示前 n * 2 个, 后 n 个: 只显示右边的分隔符
        centerStartPage = n + 1;
        ui->rightSeparateLabel->show();
    } else if (c >= m - n - n / 2 && c <= m) {
        // 显示前 n 个, 后 n * 2 个: 只显示左边的分隔符
        centerStartPage = m - n - n + 1;
        ui->leftSeparateLabel->show();
    } else {
        // 显示[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();
    }
}
 2、控件使用

以下是一个使用示例,创建了一个窗口,并在窗口中创建了一个QTableWidget。

 mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "PageWidget.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void PageChanged(int page);
    void RecordCountChanged(int recordCount);

private:
    void init_table();
    void SetPage();
    void ShowData(int page);

private:
    Ui::MainWindow *ui;

    PageWidget *m_pPageWidget;
    int m_pageRecordCount;  //每页显示的记录数量
    int m_currentPage;      //当前页面
};
#endif // MAINWINDOW_H
 mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    m_pPageWidget = new PageWidget;
    connect(m_pPageWidget, &PageWidget::currentPageChanged, this, &MainWindow::PageChanged);
    connect(m_pPageWidget, &PageWidget::recordCountChanged, this, &MainWindow::RecordCountChanged);
    QVBoxLayout *playout = new QVBoxLayout;
    playout->addWidget(m_pPageWidget);
    ui->widget->setLayout(playout);

    m_pageRecordCount = 20;
    m_currentPage = 1;
    init_table();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::PageChanged(int page)
{
    ShowData(page);
}

void MainWindow::RecordCountChanged(int recordCount)
{
    m_pageRecordCount = recordCount;
    SetPage();
}

void MainWindow::init_table()
{
    ui->tableWidget->clear();

    QStringList labels;
    labels<<QString("编号")<<QString("数量");

    ui->tableWidget->setColumnCount(2);
    ui->tableWidget->setHorizontalHeaderLabels(labels);

    SetPage();
}

void MainWindow::SetPage()
{
    m_pPageWidget->setMaxPage(ceil(2000.0/m_pageRecordCount)/*此处不能用整数,防止页数计算错误*/);
    ShowData(1);
}

void MainWindow::ShowData(int page)
{
    m_currentPage = page;

    int records = (page*m_pageRecordCount > 2000) ? (2000-(page-1)*m_pageRecordCount) : m_pageRecordCount;
    ui->tableWidget->setRowCount(0);
    int start = (page-1)*m_pageRecordCount;
    for (int i = 0; i < records; i++)
    {
        int rowCount = ui->tableWidget->rowCount();
        ui->tableWidget->insertRow(rowCount);
        ui->tableWidget->setItem(i, 0, new QTableWidgetItem(QString("%1").arg(start+i+1)));
        ui->tableWidget->setItem(i, 1, new QTableWidgetItem("1"));
    }
}

         到此这篇关于Qt实现分页组件的文章就介绍到这了。 

         感谢阅读!希望这些内容对您有所帮助,并且能够给您带来一些启发和灵感。如果您有任何问题或想要了解更多信息,请随时联系。再次感谢您的支持和关注!祝您一切顺利!

  四、示例下载
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值