功能描述:采用 Qt 开发一个翻页/分页/多页的窗体组件,封装为 QWidget 的子类,在你的应用程序中可直接使用。
一、最终演示效果
本次制作的翻页/分页/多页窗体组件是基于 Qt 开发,整个程序封装成 PageWidget 类,继承于 QWidget,在你的应用程序中可直接使用。
主要功能包括:向前一页、向后一页、定位到具体某一页,当前页用红色字体表示, 鼠标悬浮到某一页背景色显示蓝色,样式可根据用户需求进行修改。
二、翻页/分页/多页窗体组件开发
翻页/分页/多页窗体组件主要在 PageWidget.h 和 PageWidget.cpp 中封装了 PageWidget 类,实现了向前一页、向后一页、定位到具体某一页等功能。
PageWidget.h 文件代码如下:
#ifndef PAGEWIDGET_H
#define PAGEWIDGET_H
#include <QWidget>
#include <QList>
#include <QLabel>
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QLineEdit>
#include <QIntValidator>
#include <QDebug>
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<QLabel *> 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; i<pageLabels.count(); i++)
{
if(watched == pageLabels.at(i))
{
page = pageLabels.at(i)->text().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; i<blockSize*3; ++i)
{
QLabel * label = new QLabel();
font.setFamily("Times New Roman");
label->setFont(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(i<blockSize)
{
leftLayout->addWidget(label);
}
else if(i<blockSize*2)
{
centerLayout->addWidget(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; i<pageLabels.count(); i++)
{
QLabel * label = pageLabels.at(i);
if(i<maxPage)
{
label->setText(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; 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->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 <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#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/88235059https://download.csdn.net/download/tanou3212/88235059如果出现中文乱码的问题,请参考我的另外一篇博客《第十课:Qt 字符编码和中文乱码相关问题》 ,百分百能解决你的问题!