feat: Improve date picker, add select item loop logic

This commit is contained in:
kradchen
2024-09-18 13:06:25 +08:00
parent df7342625e
commit 3f0f05f397
3 changed files with 232 additions and 81 deletions

View File

@@ -13,11 +13,15 @@ DateSlidePickerBox::DateSlidePickerBox(QWidget *parent)
initBox(mHundredYearBox, {"19", "20"}, 56); initBox(mHundredYearBox, {"19", "20"}, 56);
QStringList tenYearValues{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; QStringList tenYearValues{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
mTenYearBox->setLoop(true);
mYearBox->setLoop(true);
initBox(mTenYearBox, tenYearValues); initBox(mTenYearBox, tenYearValues);
initBox(mYearBox, tenYearValues); initBox(mYearBox, tenYearValues);
addSplitLabel(); addSplitLabel();
mMonthBox->setLoop(true);
QStringList monthValues{"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"}; QStringList monthValues{"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"};
initBox(mMonthBox, monthValues, 56); initBox(mMonthBox, monthValues, 56);
@@ -27,6 +31,7 @@ DateSlidePickerBox::DateSlidePickerBox(QWidget *parent)
for (int i = 13; i <= 31; i++) { for (int i = 13; i <= 31; i++) {
days << QString("%1").arg(i, 2); days << QString("%1").arg(i, 2);
} }
mDayBox->setLoop(true);
initBox(mDayBox, days, 56); initBox(mDayBox, days, 56);
mBigMonthList.append({"01", "03", "05", "07", "08", "10", "12"}); mBigMonthList.append({"01", "03", "05", "07", "08", "10", "12"});

View File

@@ -6,8 +6,8 @@
#include <QLabel> #include <QLabel>
#include <qdebug.h> #include <qdebug.h>
namespace
namespace { {
const int LABEL_FONT_SIZE = 80; const int LABEL_FONT_SIZE = 80;
const int LABEL_CENTER_Y = 150; const int LABEL_CENTER_Y = 150;
const int LABEL_HEIGHT = 110; const int LABEL_HEIGHT = 110;
@@ -19,11 +19,7 @@ namespace {
const int SELECTED_AREA_BOTTOM = 200; const int SELECTED_AREA_BOTTOM = 200;
} }
SlidePickerBox::SlidePickerBox(QWidget *parent) SlidePickerBox::SlidePickerBox(QWidget *parent)
: QWidget(parent) : QWidget(parent), mIsDragging(false), mOriginPosY(0), mSelectedIndex(0), mLoopItem(false), mSelectedLbl(new QLabel(this))
, mIsDragging(false)
, mOriginPosY(0)
, mSelectedIndex(0)
, mSelectedLbl(new QLabel(this))
{ {
this->setFixedHeight(360); this->setFixedHeight(360);
mSelectedLbl->setText("2"); mSelectedLbl->setText("2");
@@ -45,46 +41,115 @@ SlidePickerBox::SlidePickerBox(QWidget *parent)
linePlaceholderWidget->move(lp); linePlaceholderWidget->move(lp);
} }
void SlidePickerBox::mousePressEvent(QMouseEvent * ev) { void SlidePickerBox::mousePressEvent(QMouseEvent *ev)
{
mIsDragging = true; mIsDragging = true;
mOriginPosY = ev->pos().y(); mOriginPosY = ev->pos().y();
QWidget::mousePressEvent( ev); QWidget::mousePressEvent(ev);
} }
void SlidePickerBox::mouseMoveEvent(QMouseEvent *ev) { void SlidePickerBox::mouseMoveEvent(QMouseEvent *ev)
//只有一个label无需滑动 {
if (mLabels.count() < 2) return; // 只有一个label无需滑动
if (nullptr == mSelectedLbl) return; if (mLabels.count() < 2)
return;
if (nullptr == mSelectedLbl)
return;
if (mIsDragging) if (mIsDragging)
{ {
int offset = (ev->pos().y() - mOriginPosY); int offset = (ev->pos().y() - mOriginPosY);
//防止速度过快 // 防止速度过快
while(abs(offset)>50) while (abs(offset) > 50)
{ {
offset=offset/2; offset = offset / 2;
} }
//防止拉过头 // 防止拉过头
int selItemCenterY = mSelectedLbl->geometry().center().y(); int selItemCenterY = mSelectedLbl->geometry().center().y();
if (mSelectedLbl == getEnabledLastLabel() && selItemCenterY <= LABEL_CENTER_Y && offset < 0) return; if (!mLoopItem || mLabels.count() < 3)
if (mSelectedLbl == getEnabledFirstLabel() && selItemCenterY >= LABEL_CENTER_Y && offset > 0) return;
int i = 0;
for (auto item : mLabels)
{ {
if (mDisabledItems.contains(item->text()))continue; if (mSelectedLbl == getEnabledLastLabel() && selItemCenterY <= LABEL_CENTER_Y && offset < 0)
//不需要横向,只需要纵向 return;
int ny = item->geometry().top() + offset; if (mSelectedLbl == getEnabledFirstLabel() && selItemCenterY >= LABEL_CENTER_Y && offset > 0)
item->move(item->geometry().left(),ny); return;
int centerY = item->geometry().center().y(); int i = 0;
if (centerY <= SELECTED_AREA_BOTTOM+5 for (auto item : mLabels)
&& centerY > SELECTED_AREA_TOP-5)
{ {
item->setStyleSheet("color:white"); if (mDisabledItems.contains(item->text()))
mSelectedLbl = item; continue;
mSelectedIndex = i; // 不需要横向,只需要纵向
} else{ int ny = item->geometry().top() + offset;
item->setStyleSheet("background:transparent"); item->move(item->geometry().left(), ny);
int centerY = item->geometry().center().y();
// new in selectd area
if (centerY <= SELECTED_AREA_BOTTOM + 5 && centerY > SELECTED_AREA_TOP - 5)
{
item->setStyleSheet("color:white");
mSelectedLbl = item;
mSelectedIndex = i;
}
else
{
item->setStyleSheet("background:transparent");
}
i++;
}
}
else
{
int newSelectedIndex = 0;
for (int i = 0; i<mLabels.count(); i++)
{
if (mDisabledItems.contains(mLabels[i]->text()))
continue;
// 不需要横向,只需要纵向
int ny = mLabels[i]->geometry().top() + offset;
mLabels[i]->move(mLabels[i]->geometry().left(), ny);
int centerY = mLabels[i]->geometry().center().y();
// new in selectd area
if (centerY <= SELECTED_AREA_BOTTOM + 5 && centerY > SELECTED_AREA_TOP - 5)
{
mSelectedLbl->setStyleSheet("background:transparent");
mSelectedLbl = mLabels[i];
newSelectedIndex = i;
}
}
mSelectedLbl->setStyleSheet("color:white");
if (newSelectedIndex > mSelectedIndex)
{
auto lastVisibelBack = mLabels.back();
int i = mLabels.length()-2;
while (!lastVisibelBack->isVisible())
{
lastVisibelBack = mLabels[i--];
}
do
{
auto first = mLabels.first();
mLabels.pop_front();
mLabels.push_back(first);
} while (!mLabels.back()->isVisible());
mLabels.back()->move(lastVisibelBack->geometry().left(),
lastVisibelBack->geometry().top()+LABEL_HEIGHT);
}
else if(newSelectedIndex < mSelectedIndex)
{
auto lastVisibelFirst = mLabels.first();
int i = 1;
while (!lastVisibelFirst->isVisible())
{
lastVisibelFirst = mLabels[i++];
}
do
{
auto back = mLabels.back();
mLabels.pop_back();
mLabels.push_front(back);
} while (!mLabels.first()->isVisible());
mLabels.first()->move(lastVisibelFirst->geometry().left(),
lastVisibelFirst->geometry().top()-LABEL_HEIGHT);
} }
i++;
} }
mOriginPosY = ev->pos().y(); mOriginPosY = ev->pos().y();
repaint(); repaint();
@@ -92,33 +157,36 @@ void SlidePickerBox::mouseMoveEvent(QMouseEvent *ev) {
QWidget::mouseMoveEvent(ev); QWidget::mouseMoveEvent(ev);
} }
void SlidePickerBox::mouseReleaseEvent(QMouseEvent *ev) { void SlidePickerBox::mouseReleaseEvent(QMouseEvent *ev)
{
mIsDragging = false; mIsDragging = false;
adjustPosition(); adjustPosition();
QWidget::mouseReleaseEvent(ev); QWidget::mouseReleaseEvent(ev);
QString v = getSelectedValue(); QString v = getSelectedValue();
emit valueChanged(v); emit valueChanged(v);
} }
void SlidePickerBox::adjustPosition() const
{
void SlidePickerBox::adjustPosition() const { if (mSelectedLbl == nullptr)
if(mSelectedLbl == nullptr)
{ {
return; return;
} }
if (mSelectedLbl->geometry().center().y() != LABEL_CENTER_Y) if (mSelectedLbl->geometry().center().y() != LABEL_CENTER_Y)
{ {
//选择完毕,选中项回归正位 // 选择完毕,选中项回归正位
int offset = LABEL_CENTER_Y - mSelectedLbl->geometry().center().y(); int offset = LABEL_CENTER_Y - mSelectedLbl->geometry().center().y();
for (auto item : mLabels) for (auto item : mLabels)
{ {
int ny = item->geometry().top()+offset; int ny = item->geometry().top() + offset;
item->move(item->geometry().left(),ny); item->move(item->geometry().left(), ny);
} }
} }
} }
void SlidePickerBox::setItems(const QStringList& itemsList) { void SlidePickerBox::setItems(const QStringList &itemsList)
{
this->mItems = itemsList; this->mItems = itemsList;
hideLabel(mSelectedLbl); hideLabel(mSelectedLbl);
for (auto item : mLabels) for (auto item : mLabels)
@@ -127,8 +195,8 @@ void SlidePickerBox::setItems(const QStringList& itemsList) {
} }
mSelectedLbl = nullptr; mSelectedLbl = nullptr;
mLabels.clear(); mLabels.clear();
QPoint p = {MARGIN_LEFT,-LABEL_CENTER_Y}; QPoint p = {MARGIN_LEFT, -LABEL_CENTER_Y};
for (const QString& str : this->mItems) for (const QString &str : this->mItems)
{ {
auto lbl = new QLabel(this); auto lbl = new QLabel(this);
lbl->setText(str); lbl->setText(str);
@@ -140,21 +208,42 @@ void SlidePickerBox::setItems(const QStringList& itemsList) {
mLabels.push_back(lbl); mLabels.push_back(lbl);
lbl->move(p); lbl->move(p);
} }
mSelectedIndex = mLabels.count() - 1; if (!mLoopItem || mLabels.count() <= 3)
if(!mItems.isEmpty())
{ {
setSelectedValue(this->mItems.last()); mSelectedIndex = mLabels.count() - 1;
if (!mItems.isEmpty())
{
setSelectedValue(this->mItems.last());
}
}
else
{
mSelectedIndex = (mLabels.count() + 1) / 2;
if (!mItems.isEmpty())
{
setSelectedValue(mLabels[mSelectedIndex]->text());
}
} }
} }
QString SlidePickerBox::getSelectedValue() { void SlidePickerBox::setLoop(bool aIsLoop)
if (!mSelectedLbl) return ""; {
mLoopItem = aIsLoop;
}
QString SlidePickerBox::getSelectedValue()
{
if (!mSelectedLbl)
return "";
return mSelectedLbl->text(); return mSelectedLbl->text();
} }
void SlidePickerBox::setCurrentLabel(QLabel *label) { void SlidePickerBox::setCurrentLabel(QLabel *label)
if (mSelectedLbl)hideLabel(mSelectedLbl); {
if (label) { if (mSelectedLbl)
hideLabel(mSelectedLbl);
if (label)
{
QPoint p = {MARGIN_LEFT, MARGIN_TOP}; QPoint p = {MARGIN_LEFT, MARGIN_TOP};
label->move(p); label->move(p);
label->show(); label->show();
@@ -162,47 +251,92 @@ void SlidePickerBox::setCurrentLabel(QLabel *label) {
} }
} }
QLabel * SlidePickerBox::getEnabledFirstLabel() { QLabel *SlidePickerBox::getEnabledFirstLabel()
if (mDisabledItems.empty()) return mLabels.first(); {
for(int idx = 0; idx < mDisabledItems.size(); ++idx){ if (mDisabledItems.empty())
if(mDisabledItems.contains(mLabels[idx]->text()))continue; return mLabels.first();
for (int idx = 0; idx < mDisabledItems.size(); ++idx)
{
if (mDisabledItems.contains(mLabels[idx]->text()))
continue;
return mLabels[idx]; return mLabels[idx];
} }
return nullptr; return nullptr;
} }
QLabel * SlidePickerBox::getEnabledLastLabel() { QLabel *SlidePickerBox::getEnabledLastLabel()
if (mDisabledItems.empty()) return mLabels.last(); {
for(int idx = mLabels.size() - 1; idx >= 0; --idx){ if (mDisabledItems.empty())
if(mDisabledItems.contains(mLabels[idx]->text()))continue; return mLabels.last();
for (int idx = mLabels.size() - 1; idx >= 0; --idx)
{
if (mDisabledItems.contains(mLabels[idx]->text()))
continue;
return mLabels[idx]; return mLabels[idx];
} }
return nullptr; return nullptr;
} }
void SlidePickerBox::hideLabel(QLabel *label) { void SlidePickerBox::hideLabel(QLabel *label)
if (!label) return; {
if (!label)
return;
QPoint p = {MARGIN_LEFT, -LABEL_CENTER_Y}; QPoint p = {MARGIN_LEFT, -LABEL_CENTER_Y};
label->move(p); label->move(p);
} }
void SlidePickerBox::setSelectedValue(const QString& val) { void SlidePickerBox::setSelectedValue(const QString &val)
for (int i = 0; i < mLabels.count() ; ++i) { {
if(mLabels[i]->text() == val) { if (!mLoopItem || mLabels.count() <= 3)
mSelectedIndex = i; {
break; for (int i = 0; i < mLabels.count(); ++i)
{
if (mLabels[i]->text() == val)
{
mSelectedIndex = i;
break;
}
} }
} }
int firstLabelY = -LABEL_HEIGHT * (mSelectedIndex - 1); else
for (int i = 0; i < mLabels.count() ; ++i) { {
int newSelectIndex = 0;
for (int i = 0; i < mLabels.count(); ++i)
{
if (mLabels[i]->text() == val)
{
newSelectIndex = i;
break;
}
}
bool step = newSelectIndex > mSelectedIndex;
int round = abs(newSelectIndex - mSelectedIndex);
for (int i = 0; i < round; i++)
{
if (step)
{
auto item = mLabels.first();
mLabels.pop_front();
mLabels.push_back(item);
}
else
{
auto item = mLabels.back();
mLabels.pop_back();
mLabels.push_front(item);
}
}
}
int firstLabelY = -LABEL_HEIGHT * (mSelectedIndex-1);
for (int i = 0; i < mLabels.count(); ++i)
{
QPoint leftPoint = this->mapTo(this, {MARGIN_LEFT, firstLabelY + i * LABEL_HEIGHT}); QPoint leftPoint = this->mapTo(this, {MARGIN_LEFT, firstLabelY + i * LABEL_HEIGHT});
mLabels[i]->move(leftPoint); mLabels[i]->move(leftPoint);
mLabels[i]->show(); mLabels[i]->show();
mLabels[i]->setStyleSheet("background:transparent"); mLabels[i]->setStyleSheet("background:transparent");
} }
if(mSelectedIndex >= 0) if (mSelectedIndex >= 0)
{ {
mSelectedLbl = mLabels[mSelectedIndex]; mSelectedLbl = mLabels[mSelectedIndex];
mLabels[mSelectedIndex]->setStyleSheet("color:white"); mLabels[mSelectedIndex]->setStyleSheet("color:white");
@@ -210,33 +344,42 @@ void SlidePickerBox::setSelectedValue(const QString& val) {
adjustPosition(); adjustPosition();
} }
void SlidePickerBox::resizeLabelWidth() { void SlidePickerBox::resizeLabelWidth()
for (int i = 0; i < mLabels.count() ; ++i) { {
for (int i = 0; i < mLabels.count(); ++i)
{
mLabels[i]->setAlignment(Qt::AlignCenter); mLabels[i]->setAlignment(Qt::AlignCenter);
mLabels[i]->setFixedWidth(this->width() + this->contentsMargins().left() + this->contentsMargins().right()); mLabels[i]->setFixedWidth(this->width() + this->contentsMargins().left() + this->contentsMargins().right());
} }
} }
void SlidePickerBox::disableItem(const QString& val) { void SlidePickerBox::disableItem(const QString &val)
if (!mDisabledItems.contains(val)){ {
if (!mDisabledItems.contains(val))
{
mDisabledItems.append(val); mDisabledItems.append(val);
rearrangeLabels(); rearrangeLabels();
} }
} }
void SlidePickerBox::enableItem(const QString &val) { void SlidePickerBox::enableItem(const QString &val)
if (mDisabledItems.contains(val)){ {
if (mDisabledItems.contains(val))
{
mDisabledItems.removeOne(val); mDisabledItems.removeOne(val);
rearrangeLabels(); rearrangeLabels();
} }
} }
void SlidePickerBox::rearrangeLabels() { void SlidePickerBox::rearrangeLabels()
{
int firstLabelY = -100 * (mSelectedIndex - 1); int firstLabelY = -100 * (mSelectedIndex - 1);
int visibleItemIndex = 0; int visibleItemIndex = 0;
for (int i = 0; i < mLabels.count() ; ++i) { for (int i = 0; i < mLabels.count(); ++i)
if (mDisabledItems.contains(mLabels[i]->text())){ {
mLabels[i]->hide(); if (mDisabledItems.contains(mLabels[i]->text()))
{
mLabels[i]->setVisible(false);
continue; continue;
} }
QPoint p = this->mapTo(this, {MARGIN_LEFT, firstLabelY + visibleItemIndex * LABEL_HEIGHT}); QPoint p = this->mapTo(this, {MARGIN_LEFT, firstLabelY + visibleItemIndex * LABEL_HEIGHT});
@@ -249,4 +392,3 @@ void SlidePickerBox::rearrangeLabels() {
mLabels[mSelectedIndex]->setStyleSheet("color:white"); mLabels[mSelectedIndex]->setStyleSheet("color:white");
adjustPosition(); adjustPosition();
} }

View File

@@ -2,6 +2,7 @@
#define GUI_SLIDEPICKERBOX_H #define GUI_SLIDEPICKERBOX_H
#include <QWidget> #include <QWidget>
#include <QLinkedList>
class QLabel; class QLabel;
class SlidePickerBox:public QWidget { class SlidePickerBox:public QWidget {
Q_OBJECT Q_OBJECT
@@ -9,6 +10,8 @@ public:
explicit SlidePickerBox(QWidget *parent = nullptr); explicit SlidePickerBox(QWidget *parent = nullptr);
QString getSelectedValue(); QString getSelectedValue();
void setItems(const QStringList& itemsList); void setItems(const QStringList& itemsList);
void setLoop(bool isLoop);
void addItem(QString& item) { void addItem(QString& item) {
this->mItems.append(item); this->mItems.append(item);
} }
@@ -37,6 +40,7 @@ protected:
private: private:
int mOriginPosY; int mOriginPosY;
int mSelectedIndex; int mSelectedIndex;
bool mLoopItem;
QLabel* mSelectedLbl; QLabel* mSelectedLbl;
QList<QLabel*> mLabels; QList<QLabel*> mLabels;
QStringList mItems; QStringList mItems;