#ifndef LISTWIDGET_H
#define LISTWIDGET_H
#include <QWidget>
struct ListItem
{
QString text;
QRect rect;
QString icon{":/setting.png"};
};
class ListWidget : public QWidget
{
Q_OBJECT
public:
explicit ListWidget(QWidget *parent = nullptr);
void setSize(int newSize);
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private:
std::shared_ptr<struct ListWidgetPrivate> d_ptr;
};
#endif // LISTWIDGET_H
#include "listwidget.h"
#include <QPainter>
#include <QDebug>
#include <QMouseEvent>
#include <QDateTime>
struct ListWidgetPrivate
{
void setSize(int newSize);
void onMousePressed(const QPoint & pos);
void onMouseReleased();
void onMouseMoved(const QPoint & pos);
void updateRect();
void drawRect(QPainter * painter);
~ListWidgetPrivate();
QPoint pressPos;
QList<ListItem*> itemList;
bool isPressed{false};
int startHeight{0};
int offsetY{0};
int pressIndex{-1};
int itemHeight = 50;
int tempOffsetY{0};
int gridLineWidth{3};
qint64 preessTime{0};
ListWidget * q_ptr;
QColor backgroundColor{"#ffffffff"};
QColor itemPressedBackgroundColor{"#f0121212"};
QColor itemBackgroundColor{"#f0555555"};
QColor gridColor{"#f8111111"};
QColor textColor{"#ffffffff"};
};
void ListWidgetPrivate::setSize(int newSize)
{
auto oldSize = itemList.size();
if(newSize != oldSize)
{
if(newSize > oldSize)
{
for (int i = 0;i < (newSize - oldSize);++i)
{
auto item = new ListItem;
item->text = "项目" + QString::number(oldSize + i + 1);
itemList << item;
}
}
else
{
for(int i = oldSize - 1;i != (oldSize - 1);--i)
{
auto item = itemList.last();
itemList.removeLast();
delete item;
}
}
updateRect();
}
}
void ListWidgetPrivate::updateRect()
{
auto width = q_ptr->rect().width() + gridLineWidth * 2;
for(int i = 0,height = 0;i < itemList.size();++i, height += itemHeight)
{
itemList[i]->rect = QRect(-gridLineWidth, height, width, itemHeight);
}
}
void ListWidgetPrivate::drawRect(QPainter *painter)
{
painter->fillRect(q_ptr->rect(),backgroundColor);
painter->setPen(QPen(gridColor, gridLineWidth));
painter->setBrush(itemBackgroundColor);
for (int i = 0; i < itemList.size(); ++i)
{
const auto & item = itemList.at(i);
auto itemRect = item->rect;
itemRect.moveBottom(itemRect.bottom() - offsetY);
if (Q_UNLIKELY(isPressed && i == pressIndex))
{
painter->save();
painter->setBrush(itemPressedBackgroundColor);
painter->drawRect(itemRect);
painter->restore();
}
else
{
painter->drawRect(itemRect);
}
painter->save();
painter->setPen(QPen(textColor));
painter->drawText(itemRect, Qt::AlignCenter, item->text);
painter->restore();
painter->drawPixmap(QRect(itemRect.topLeft() + QPoint(itemHeight / 4,0),QSize(itemHeight,itemHeight)).adjusted(4,4,-4,-4),
QPixmap(item->icon));
painter->save();
painter->setPen(QPen(QColor("#C0C0C0"),2,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin));
QRect symbolRect(itemRect.topRight() - QPoint(itemHeight * 1.5,0),QSize(itemHeight* 1.5,itemHeight));
auto symbolRectCenter = symbolRect.center();
painter->drawLine(symbolRect.topLeft() + QPoint(itemHeight / 2.5,itemHeight / 3.5),symbolRectCenter);
painter->drawLine(symbolRect.bottomLeft() + QPoint(itemHeight / 2.5,-itemHeight / 3.5),symbolRectCenter);
painter->restore();
}
}
ListWidgetPrivate::~ListWidgetPrivate()
{
qDeleteAll(itemList);
}
void ListWidgetPrivate::onMousePressed(const QPoint &pos)
{
pressPos = pos;
tempOffsetY = offsetY;
isPressed = true;
pressIndex = -1;
preessTime = QDateTime::currentMSecsSinceEpoch();
for (int i = 0; i < itemList.size(); ++i)
{
auto itemRect = itemList.at(i)->rect;
itemRect.moveBottom(itemRect.bottom() - offsetY);
if (itemRect.contains(pressPos))
{
pressIndex = i;
break;
}
}
q_ptr->update();
}
void ListWidgetPrivate::onMouseReleased()
{
if (isPressed)
{
isPressed = false;
if (offsetY < 0)
offsetY = 0;
auto lastItemRect = itemList.last()->rect;
lastItemRect.moveBottom(lastItemRect.bottom() - offsetY);
if (lastItemRect.bottom() < 0 || lastItemRect.bottom() < itemHeight)
offsetY = (itemList.size() - 1) * itemHeight;
if(pressIndex != -1)
{
qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
if ((currentTime - preessTime) < 1000)//从按下到松开超过1秒就不认为是按下项目操作
{
qDebug()<<itemList.at(pressIndex)->text;
preessTime = currentTime;
}
pressIndex = -1;
}
q_ptr->update();
}
}
void ListWidgetPrivate::onMouseMoved(const QPoint &pos)
{
if (isPressed)
{
auto diff = pressPos - pos;
offsetY = tempOffsetY + diff.y();
q_ptr->update();
}
}
ListWidget::ListWidget(QWidget *parent)
: QWidget{parent}
{
d_ptr = std::make_shared<ListWidgetPrivate>();
d_ptr->q_ptr = this;
for(int i = 1;i < 10;++i)
{
auto item = new ListItem;
item->text = "项目" + QString::number(i);
d_ptr->itemList << item;
}
}
void ListWidget::setSize(int newSize)
{
d_ptr->setSize(newSize);
}
void ListWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
d_ptr->drawRect(&painter);
}
void ListWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
d_ptr->onMousePressed(event->pos());
}
}
void ListWidget::mouseReleaseEvent(QMouseEvent *event)
{
d_ptr->onMouseReleased();
}
void ListWidget::mouseMoveEvent(QMouseEvent *event)
{
d_ptr->onMouseMoved(event->pos());
}
void ListWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
d_ptr->updateRect();
update();
}
![](https://i-blog.csdnimg.cn/direct/d7f76aaca35f4f4bba046445d63a26e1.gif)