| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- #include "pagination.h"
- #include <QVector>
- #include <QComboBox>
- #include <QDebug>
- #include <QMouseEvent>
- #include <QPainter>
- #include <QPushButton>
- #include <QStyleOptionButton>
- 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::Layout>(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<int> numbers()
- {
- QVector<int> 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);
- }
|