#include "pagination.h" #include #include #include #include #include #include #include enum PageNavigation { PreviousPage = -2, // < NextPage = -1, // > PreviousExPage = -4, // << NextExPage = -3, // >> NoSelection = 0 }; class PaginationPrivate { public: PaginationPrivate(QWidget *_q) : q(_q) , prevText("<") , nextText(">") , layout(static_cast(Pagination::TOTAL | Pagination::PREV | Pagination::PAGER | Pagination::NEXT)) {} QWidget *q; int total = 0; //总数 int pageCount = 0; //页面数量 int currentPage = 1; //当前页面 int pagerCount = 7; //翻页大小 int pageSizes = 10; //分页大小 int defaultSize = 30; //控件默认大小 int spacing = 5; //控件默认间距 int hoverNumber = PageNavigation::NoSelection; //焦点控件 QString prevText; //上一页文本 QString nextText; //下一页文本 Pagination::Layout layout; QSize buttonSize(const QString &text) { // QMargins margins = q->contentsMargins(); const QFontMetrics &met = q->fontMetrics(); #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) int w = met.width(text); #else int w = met.horizontalAdvance(text); #endif // 10 边距 但是获取不正确 先固定 int width = std::max(defaultSize, w + margins.left() + margins.right() + 10); int height = std::max(defaultSize, met.height() + margins.top() + margins.bottom()); // width = std::max(width, height); //qDebug() << text << QSize{width, height}; return {width, height}; } void drawNumber(const QRect &rect, int number, QPainter *painter) { QString text; if (PageNavigation::PreviousPage == number) { text = prevText; } else if (PageNavigation::NextPage == number) { text = nextText; } else if (PageNavigation::PreviousExPage == number) { if (hoverNumber == number) { text = "<<"; } else { text = "..."; } } else if (PageNavigation::NextExPage == number) { if (hoverNumber == number) { text = ">>"; } else { text = "..."; } } else { text = QString::number(number); } QStyleOptionButton opt; opt.initFrom(q); opt.text = text; opt.rect = rect; opt.state.setFlag(QStyle::State_MouseOver, hoverNumber == number); if (number > 0) { opt.state.setFlag(QStyle::State_On, currentPage == number); opt.state.setFlag(QStyle::State_Selected, currentPage == number); } q->style()->drawControl(QStyle::CE_PushButton, &opt, painter, q); } void drawText(const QRect &rect, const QString &text, QPainter *painter) { QStyle *style = q->style(); QStyleOption opt; opt.initFrom(q); style->drawItemText(painter, rect, Qt::AlignCenter, opt.palette, true, text, q->foregroundRole()); } QVector numbers() { QVector page; int halfPagerCount = (pagerCount - 1) / 2; bool showPrevMore = false; bool showNextMore = false; if (pageCount > pagerCount) { if (currentPage > pagerCount - halfPagerCount) { showPrevMore = true; } if (currentPage < pageCount - halfPagerCount) { showNextMore = true; } } if (pageCount > 0) { page.push_back(1); } if (showPrevMore && !showNextMore) { int startPage = pageCount - (pagerCount - 2); page.push_back(PageNavigation::PreviousExPage); for (int i = startPage; i < pageCount; ++i) { page.push_back(i); } } else if (!showPrevMore && showNextMore) { for (int i = 2; i < pagerCount; ++i) { page.push_back(i); } page.push_back(PageNavigation::NextExPage); } else if (showPrevMore && showNextMore) { int offset = pagerCount / 2 - 1; page.push_back(PageNavigation::PreviousExPage); for (int i = currentPage - offset; i <= currentPage + offset; ++i) { page.push_back(i); } page.push_back(PageNavigation::NextExPage); } else { for (int i = 2; i < pageCount; ++i) { page.push_back(i); } } if (pageCount > 1) { page.push_back(pageCount); } return page; } }; Pagination::Pagination(QWidget *parent) : QWidget(parent) , d(new PaginationPrivate(this)) { setMouseTracking(true); // 启用鼠标跟踪 setContentsMargins(7, 7, 7, 7); } Pagination::Pagination(int total, int pageSize, QWidget *parent) : QWidget(parent) , d(new PaginationPrivate(this)) { setMouseTracking(true); // 启用鼠标跟踪 setContentsMargins(7, 7, 7, 7); d->total = total; d->pageSizes = pageSize; d->pageCount = (total + d->pageSizes - 1) / d->pageSizes; } Pagination::~Pagination() { delete d; } int Pagination::currentPage() const { return d->currentPage; } void Pagination::setCurrentPage(int page) { d->currentPage = page; update(); } QString Pagination::prevText() const { return d->prevText; } void Pagination::setPrevText(const QString &text) { d->prevText = text; update(); } QString Pagination::nextText() const { return d->nextText; } void Pagination::setNextText(const QString &text) { d->nextText = text; update(); } int Pagination::spacing() const { return d->spacing; } void Pagination::setSpacing(int spacing) { d->spacing = spacing; } Pagination::Layout Pagination::layout() const { return d->layout; } void Pagination::setLayout(Pagination::Layout layout) { d->layout = layout; } int Pagination::pagerCount() const { return d->pagerCount; } void Pagination::setPagerCount(int count) { if (count <= 0) { d->pagerCount = 7; } else { d->pagerCount = count; } update(); } int Pagination::pageSizes() const { return d->pageSizes; } void Pagination::setPageSizes(int count) { d->pageSizes = count; d->pageCount = (d->total + d->pageSizes - 1) / d->pageSizes; update(); } int Pagination::total() const { return d->total; } void Pagination::setTotal(int count) { d->total = count; d->pageCount = (count + d->pageSizes - 1) / d->pageSizes; update(); } QSize Pagination::sizeHint() const { QMargins margins = this->contentsMargins(); const QFontMetrics &met = this->fontMetrics(); int height = std::max(d->defaultSize, met.height() + margins.top() + margins.bottom()); return QSize{150, height}; } QSize Pagination::minimumSizeHint() const { QMargins margins = this->contentsMargins(); const QFontMetrics &met = this->fontMetrics(); int height = std::max(d->defaultSize, met.height() + margins.top() + margins.bottom()); return QSize{150, height}; } void Pagination::paintEvent(QPaintEvent *event) { QPainter painter(this); const auto pages = d->numbers(); int x = 0; int y = 0; if (d->layout & TOTAL) { const QString &text = QString(tr("Total:%1")).arg(d->total); QSize size = d->buttonSize(text); QRect rect(x, y, size.width(), size.height()); d->drawText(rect, text, &painter); x = x + size.width() + d->spacing; } if (d->layout & PREV) { QSize size = d->buttonSize(d->prevText); QRect rect(x, y, size.width(), size.height()); d->drawNumber(rect, PageNavigation::PreviousPage, &painter); x = x + size.width() + d->spacing; } if (d->layout & PAGER) { for (int p : pages) { QSize size = d->buttonSize(QString::number(p)); QRect rect(x, y, size.width(), size.height()); d->drawNumber(rect, p, &painter); x = x + size.width() + d->spacing; } } if (d->layout & NEXT) { QSize size = d->buttonSize(d->nextText); QRect rect(x, y, size.width(), size.height()); d->drawNumber(rect, PageNavigation::NextPage, &painter); x = x + size.width() + d->spacing; } Q_UNUSED(x) setMinimumWidth(x); //painter.drawRect(rect()); return QWidget::paintEvent(event); } void Pagination::mouseMoveEvent(QMouseEvent *event) { const QPoint &point = event->pos(); int x = 0; int y = 0; if (d->layout & TOTAL) { const QString &text = QString(tr("Total:%1")).arg(d->total); QSize size = d->buttonSize(text); QRect rect(x, y, size.width(), size.height()); x = x + size.width() + d->spacing; if (rect.contains(point)) { d->hoverNumber = PageNavigation::NoSelection; update(); return QWidget::mouseMoveEvent(event); } } if (d->layout & PREV) { QSize size = d->buttonSize(d->prevText); QRect rect(x, y, size.width(), size.height()); x = x + size.width() + d->spacing; if (rect.contains(point)) { d->hoverNumber = PageNavigation::PreviousPage; update(); return QWidget::mouseMoveEvent(event); } } if (d->layout & PAGER) { const auto pages = d->numbers(); for (int p : pages) { QSize size = d->buttonSize(QString::number(p)); QRect rect(x, y, size.width(), size.height()); x = x + size.width() + d->spacing; if (rect.contains(point)) { d->hoverNumber = p; update(); return QWidget::mouseMoveEvent(event); } } } if (d->layout & NEXT) { QSize size = d->buttonSize(d->nextText); QRect rect(x, y, size.width(), size.height()); x = x + size.width() + d->spacing; if (rect.contains(point)) { d->hoverNumber = PageNavigation::NextPage; update(); return QWidget::mouseMoveEvent(event); } } Q_UNUSED(x) return QWidget::mouseMoveEvent(event); } void Pagination::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { const QPoint &point = event->pos(); int x = 0; int y = 0; if (d->layout & TOTAL) { const QString &text = QString(tr("Total:%1")).arg(d->total); QSize size = d->buttonSize(text); QRect rect(x, y, size.width(), size.height()); x = x + size.width() + d->spacing; if (rect.contains(point)) { update(); return QWidget::mouseMoveEvent(event); } } if (d->layout & PREV) { QSize size = d->buttonSize(d->prevText); QRect rect(x, y, size.width(), size.height()); x = x + size.width() + d->spacing; if (rect.contains(point)) { int newPage = d->currentPage - 1; if (newPage < 1) { newPage = 1; } if (newPage > d->pageCount) { newPage = d->pageCount; } //发送信号 if (d->currentPage != newPage) { d->currentPage = newPage; emit valueChanged(d->currentPage); } update(); return QWidget::mouseMoveEvent(event); } } if (d->layout & PAGER) { const auto pages = d->numbers(); for (int p : pages) { QSize size = d->buttonSize(QString::number(p)); QRect rect(x, y, size.width(), size.height()); x = x + size.width() + d->spacing; if (rect.contains(point)) { int newPage = d->currentPage; if (p > 0) { newPage = p; } else { const int pagerCountOffset = d->pagerCount - 2; if (p == PageNavigation::PreviousExPage) { newPage = d->currentPage - pagerCountOffset; } else if (p == PageNavigation::NextExPage) { newPage = d->currentPage + pagerCountOffset; } else if (p == PageNavigation::PreviousExPage) { newPage = d->currentPage - 1; } else if (p == PageNavigation::NextPage) { newPage = d->currentPage + 1; } } if (newPage < 1) { newPage = 1; } if (newPage > d->pageCount) { newPage = d->pageCount; } //发送信号 if (d->currentPage != newPage) { d->currentPage = newPage; emit valueChanged(d->currentPage); } update(); return QWidget::mouseMoveEvent(event); } } } if (d->layout & NEXT) { QSize size = d->buttonSize(d->nextText); QRect rect(x, y, size.width(), size.height()); x = x + size.width() + d->spacing; if (rect.contains(point)) { int newPage = d->currentPage + 1; if (newPage < 1) { newPage = 1; } if (newPage > d->pageCount) { newPage = d->pageCount; } //发送信号 if (d->currentPage != newPage) { d->currentPage = newPage; emit valueChanged(d->currentPage); } update(); return QWidget::mouseMoveEvent(event); } } Q_UNUSED(x) } QWidget::mousePressEvent(event); } void Pagination::leaveEvent(QEvent *event) { d->hoverNumber = PageNavigation::NoSelection; update(); QWidget::leaveEvent(event); }