第十四课:采用 Qt 开发翻页/分页/多页窗体组件

功能描述:采用 Qt 开发一个翻页/分页/多页的窗体组件,封装为 QWidget 的子类,在你的应用程序中可直接使用。

一、最终演示效果

本次制作的翻页/分页/多页窗体组件是基于 Qt 开发,整个程序封装成 PageWidget 类,继承于 QWidget,在你的应用程序中可直接使用。

第十四课:采用 Qt 开发翻页/分页/多页窗体组件_第1张图片

主要功能包括:向前一页、向后一页、定位到具体某一页,当前页用红色字体表示, 鼠标悬浮到某一页背景色显示蓝色,样式可根据用户需求进行修改。

二、翻页/分页/多页窗体组件开发

翻页/分页/多页窗体组件主要在 PageWidget.h 和 PageWidget.cpp 中封装了 PageWidget 类,实现了向前一页、向后一页、定位到具体某一页等功能。 

PageWidget.h 文件代码如下:

#ifndef PAGEWIDGET_H
#define PAGEWIDGET_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

class PageWidget : public QFrame
{
    Q_OBJECT
public:
    // 翻页显示分成三个部分, 左...中...右,blockSize 表示每部分的标签个数
    PageWidget(int blockSize = 3);

    /**
     * @brief getBlockSize  获取每部分的标签个数
     * @return
     */
    int getBlockSize() const;

    /**
     * @brief setBlockSize      设置每部分的标签个数
     * @param blockSize         每部分的标签个数,block size 必须是奇数, 且最小为3
     */
    void setBlockSize(int blockSize);

    /**
     * @brief getMaxPage    获取总页数
     * @return
     */
    int getMaxPage() const;

    /**
     * @brief setMaxPage    设置总页数
     * @param maxPage       总页数值
     */
    void setMaxPage(int maxPage);

    /**
     * @brief getCurrentPage    获取当前页数
     * @return
     */
    int getCurrentPage() const;

    /**
     * @brief setCurrentPage    设置当前页
     * @param currentPage       当前页数值
     * @param signalEmitted     为 true 时发送 currentPageChanged(int) 信号
     */
    void setCurrentPage(int currentPage, bool signalEmitted = false);

protected:
    /**
     * @brief eventFilter       事件过滤器,响应上一页标签和下一页标签的点击事件
     * @param watched           发生事件的组件
     * @param e                 发生事件的类型
     * @return
     */
    virtual bool eventFilter(QObject * watched, QEvent * e);

signals:
    /**
     * @brief currentPageChanged        当前页信号
     * @param page                      页码
     */
    void currentPageChanged(int page);

private:
    // 字体
    QFont font;
    // 前一页,"<"
    QLabel * previousPageLabel = nullptr;
    // 左侧部分标签的容器
    QWidget * leftPagesWidget = nullptr;
    // 左侧分隔符,".."
    QLabel * leftSeparateLabel = nullptr;
    // 中间部分标签的容器
    QWidget * centerPagesWidget = nullptr;
    // 右侧分隔符,".."
    QLabel * rightSeparateLabel = nullptr;
    // 右侧部分标签的容器
    QWidget * rightPagesWidget = nullptr;
    // 下一页,">"
    QLabel * nextPageLabel = nullptr;

    // 翻页显示分成三个部分, 左...中...右,blockSize 表示每部分的标签个数
    int blockSize;
    // 总页数
    int maxPage;
    // 当前页
    int currentPage;
    // 存储所有的数字标签,总个数为 blockSize*3
    QList pageLabels;

    /**
     * @brief initialize        标签初始化
     */
    void initialize();

    /**
     * @brief updatePageLabels  更新显示标签
     */
    void updatePageLabels();
};

#endif // PAGEWIDGET_H

PageWidget.cpp 文件代码如下:

#include "PageWidget.h"

PageWidget::PageWidget(int blockSize): blockSize(blockSize)
{
    setStyleSheet("background-color:#2B2C2E;color:rgba(255,255,255,0.85);");

    font = QFont("Times New Roman", 14);
    font.setBold(true);

    previousPageLabel = new QLabel;
    previousPageLabel->setFont(font);
    previousPageLabel->setAlignment(Qt::AlignCenter);
    previousPageLabel->setFixedSize(23,23);
    previousPageLabel->setText("<");
    previousPageLabel->setStyleSheet("QLabel{color:rgba(255,255,255,0.85); padding:2px;}"
                                     "QLabel:hover{color: black; 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));}");

    leftPagesWidget = new QWidget;
    leftPagesWidget->resize(23,23);
    leftPagesWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);

    leftSeparateLabel = new QLabel;
    leftSeparateLabel->setFont(font);
    leftSeparateLabel->setAlignment(Qt::AlignCenter);
    leftSeparateLabel->setFixedSize(23,23);
    leftSeparateLabel->setText("..");
    leftSeparateLabel->setStyleSheet("QLabel{color:rgba(255,255,255,0.85);}");
    centerPagesWidget = new QWidget;
    centerPagesWidget->resize(23,23);
    centerPagesWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);

    rightSeparateLabel = new QLabel;
    rightSeparateLabel->setFont(font);
    rightSeparateLabel->setAlignment(Qt::AlignCenter);
    rightSeparateLabel->setFixedSize(23,23);
    rightSeparateLabel->setText("..");
    rightSeparateLabel->setStyleSheet("QLabel{color:rgba(255,255,255,0.85);}");
    rightPagesWidget = new QWidget;
    rightPagesWidget->resize(23,23);
    rightPagesWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);

    nextPageLabel = new QLabel;
    nextPageLabel->setFont(font);
    nextPageLabel->setAlignment(Qt::AlignCenter);
    nextPageLabel->setFixedSize(23,23);
    nextPageLabel->setText(">");
    nextPageLabel->setStyleSheet("QLabel{color:rgba(255,255,255,0.85); padding:2px;}"
                                 "QLabel:hover{color: black; 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));}");

    QHBoxLayout * mainLayout = new QHBoxLayout;
    mainLayout->setMargin(0);
    mainLayout->setContentsMargins(0,0,0,0);
    mainLayout->setSpacing(0);
    mainLayout->addStretch(1);
    mainLayout->addWidget(previousPageLabel);
    mainLayout->addWidget(leftPagesWidget);
    mainLayout->addWidget(leftSeparateLabel);
    mainLayout->addWidget(centerPagesWidget);
    mainLayout->addWidget(rightSeparateLabel);
    mainLayout->addWidget(rightPagesWidget);
    mainLayout->addWidget(nextPageLabel);
    mainLayout->addStretch(1);

    setLayout(mainLayout);

    initialize();

    setMaxPage(1);
}

// 获取每部分的标签个数
int PageWidget::getBlockSize() const
{
    return blockSize;
}

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

// 获取总页数
int PageWidget::getMaxPage() const
{
    return maxPage;
}

// 设置总页数
void PageWidget::setMaxPage(int page)
{
    page = qMax(page, 1);
    if(maxPage != page)
    {
        this->maxPage = page;
        this->currentPage = 1;
        updatePageLabels();
    }
}

// 获取当前页数
int PageWidget::getCurrentPage() const
{
    return currentPage;
}

// 设置当前页
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);
        }
    }
}

// 事件过滤器,响应上一页标签和下一页标签的点击事件
bool PageWidget::eventFilter(QObject * watched, QEvent * e)
{
    if(e->type() == QEvent::MouseButtonRelease)
    {
        int page = -1;

        // 点击了前一页标签
        if(watched == previousPageLabel)
        {
            page = getCurrentPage()-1;
        }

        // 点击了后一页标签
        if(watched == nextPageLabel)
        {
            page = getCurrentPage()+1;
        }

        // 点击了具体数字的标签
        for(int i=0; itext().toInt();
                break;
            }
        }

        if(page != -1)
        {
            setCurrentPage(page, true);
            return true;
        }
    }
    return QWidget::eventFilter(watched, e);
}

// 页码标签初始化,分成三个部分, 左...中...右
void PageWidget::initialize()
{
    previousPageLabel->installEventFilter(this);
    nextPageLabel->installEventFilter(this);

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

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

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

    for(int i=0; isetFont(font);
        label->setAlignment(Qt::AlignCenter);
        label->setFixedHeight(23);
        label->setMinimumWidth(23);
        label->setText(QString::number(i+1));
        label->setStyleSheet("QLabel{color:rgba(255,255,255,0.85); padding:2px;}"
                             "QLabel:hover{color: black; 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));}");
        label->installEventFilter(this);

        pageLabels.append(label);

        if(iaddWidget(label);
        }
        else if(iaddWidget(label);
        }
        else
        {
            rightLayout->addWidget(label);
        }
    }

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

// 更新显示标签
void PageWidget::updatePageLabels()
{
    leftSeparateLabel->hide();
    rightSeparateLabel->hide();

    // 总页数小于 blockSize*3,总页数数值之前的 Label 都显示,之后的都隐藏
    if(maxPage <= blockSize*3)
    {
        for(int i=0; isetText(QString::number(i+1));
                label->show();
            }
            else
            {
                label->hide();
            }

            if(currentPage-1 == i)
            {
                // 当前页的字体设置为蓝色
                label->setStyleSheet("QLabel{color:rgba(255,0,0,0.85); padding:2px;}"
                                     "QLabel:hover{color: black; 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));}");
            }
            else
            {
                // 非当前页的字体设置为白色
                label->setStyleSheet("QLabel{color:rgba(255,255,255,0.85); padding:2px;}"
                                     "QLabel:hover{color: black; 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));}");
            }
        }
        return;
    }

    // 以下情况为 maxPage 大于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;
        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;
        leftSeparateLabel->show();
    }
    else
    {
        // 3. 显示[1, n], [c - n/2, c + n/2], [m - n + 1, m]: 两个分隔符都显示
        centerStartPage = c-n/2;
        rightSeparateLabel->show();
        leftSeparateLabel->show();
    }

    for(int i=0; isetText(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; itext().toInt();
        if(page == currentPage)
        {
            // 当前页的字体设置为蓝色
            label->setStyleSheet("QLabel{color:rgba(255,0,0,0.85); padding:2px;}"
                                 "QLabel:hover{color: black; 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));}");
        }
        else
        {
            // 非当前页的字体设置为白色
            label->setStyleSheet("QLabel{color:rgba(255,255,255,0.85); padding:2px;}"
                                 "QLabel:hover{color: black; 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));}");

        }
        label->show();
    }
}

如果仅作为翻页/分页/多页组件使用的话,将以上两个文件直接添加到程序中即可使用。为了演示效果,我还写了 Widget.cpp 和 Widget.h 文件,集成翻页/分页/多页组件的使用。

Widget.h 文件代码如下:

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include 
#include 
#include 
#include 
#include 
#include "PageWidget.h"

class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget();

private slots:
    /**
     * @brief changeMaxPage  设置总页数
     */
    void changeMaxPage();

private:
    // 字体
    QFont font;
    // 总页数标签
    QLabel * maxPageLabel;
    // 总页数输入框
    QLineEdit * maxPageLineEdit;
    // 总页数设置
    QPushButton * maxPageBtn;
    // 分页窗口
    PageWidget * pageWidget;
};

#endif // WIDGET_H

Widget.cpp 文件代码如下:

#include "Widget.h"
#include "PageWidget.h"

Widget::Widget()
{
    setStyleSheet("background-color:#2B2C2E;color:rgba(255,255,255,0.85);");

    font = QFont("黑体", 12);

    maxPageLabel = new QLabel;
    maxPageLabel->setFont(font);
    maxPageLabel->setAlignment(Qt::AlignCenter);
    maxPageLabel->setFixedSize(80,23);
    maxPageLabel->setText("总页数:");

    maxPageLineEdit = new QLineEdit;
    font.setFamily("Times New Roman");
    maxPageLineEdit->setFixedHeight(23);
    maxPageLineEdit->setMinimumWidth(200);
    maxPageLineEdit->setFont(font);
    maxPageLineEdit->setAlignment(Qt::AlignCenter);
    maxPageLineEdit->setValidator(new QIntValidator(1,10000000));
    maxPageLineEdit->setStyleSheet("background-color:rgba(255,255,255,0.05); border-radius: 3px; margin:0px;");
    connect(maxPageLineEdit, SIGNAL(returnPressed()), this, SLOT(changeMaxPage()));

    maxPageBtn = new QPushButton;
    font.setFamily("黑体");
    maxPageBtn->setFont(font);
    maxPageBtn->setText("设置");
    maxPageBtn->setStyleSheet("QPushButton{background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #5EDCF8, stop:0.5 #82E5FB, stop:1 #06C9F4); color:rgb(255,255,255); border-radius:8px; margin:0px;}"
                              "QPushButton:pressed{background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #c0c0c0, stop:1 #808080); color:rgb(255,255,255); border-radius:8px; margin:0px;}"
                              "QPushButton:disabled{background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #c0c0c0, stop:1 #808080); color:rgb(255,255,255); border-radius:8px; margin:0px;}");
    maxPageBtn->setFixedSize(60,23);
    connect(maxPageBtn, SIGNAL(clicked()), this, SLOT(changeMaxPage()));

    pageWidget = new PageWidget;

    QHBoxLayout * topLayout = new QHBoxLayout();
    topLayout->setMargin(0);
    topLayout->setContentsMargins(0,0,0,0);
    topLayout->setSpacing(10);
    topLayout->addWidget(maxPageLabel);
    topLayout->addWidget(maxPageLineEdit);
    topLayout->addWidget(maxPageBtn);

    QVBoxLayout * mainLayout = new QVBoxLayout();
    mainLayout->setMargin(0);
    mainLayout->setContentsMargins(20,20,20,20);
    mainLayout->setSpacing(20);
    mainLayout->addLayout(topLayout);
    mainLayout->addWidget(pageWidget);

    setLayout(mainLayout);
}

// 设置总页数
void Widget::changeMaxPage()
{
    pageWidget->setMaxPage(maxPageLineEdit->text().toInt());
    pageWidget->setCurrentPage(1);
}

完整的代码已经贴上,每个函数的备注写的非常清楚,如有不清楚的地方可以私信我。

完整代码压缩包下载地址: 

https://download.csdn.net/download/tanou3212/88235059icon-default.png?t=N6B9https://download.csdn.net/download/tanou3212/88235059如果出现中文乱码的问题,请参考我的另外一篇博客《第十课:Qt 字符编码和中文乱码相关问题》 ,百分百能解决你的问题!

你可能感兴趣的:(Qt,实战经验,qt,翻页,分页)