自定义的Qt图片列表控件
这里自定义了一个显示图片列表的控件,在某些时候可能会方便地显示图片缩略图。效果如下图:
在下述代码中,列表的功能都在MImageListPrivate类里,但不要直接使用它,而是使用MImageList类。列表功能都被MImageList类重新包了一遍,因为MImageListPrivate类没有滚动条。如果你需要对控件添加新功能,可能需要在MImageListPrivate类里实现新功能,然后在MImageList包一层。这些代码经过在VS2015和Qt5.9中测试可以使用。但也明显缺少一些功能,比如缺少删除item的方法。由于博主没有时间,所以这些功能都不写了,留给以后用到时候再写。MImageList的使用方法是在Qt Designer中添加一个Widget,然后把Widget提升为MImageList。给出代码,头文件:
#pragma once #include "qwidget.h" class MImageListPrivate; class QScrollArea; class MImageListItem { public: MImageListItem(const QImage& image, const QString& text); void setSelected(bool select); bool isSelected() const; void setText(const QString& text); QString text() const; void setImage(const QImage& image); QImage image() const; void setParent(MImageListPrivate* parent); private: bool iselected; MImageListPrivate* iparent; QImage iimage; QString itext; }; class MImageListPrivate : public QWidget { Q_OBJECT public: MImageListPrivate(QScrollArea* frame, QWidget* parent = 0); ~MImageListPrivate(); void addItem(MImageListItem* item); QList<MImageListItem*> selectedItems() const; int indexOf(MImageListItem* item) const; void setCurrentItem(MImageListItem* item); void clearSelection(); signals: void itemClicked(MImageListItem* item); void itemDoubleClicked(MImageListItem* item); private: MImageListItem* hitTest(const QPoint& pos) const; void setItemVisible(int index); void paintEvent(QPaintEvent*) override; void mousePressEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; void mouseDoubleClickEvent(QMouseEvent* event) override; void wheelEvent(QWheelEvent* event) override; void enterEvent(QEvent* event) override; void leaveEvent(QEvent* event) override; bool focusNextPrevChild(bool next) override; void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; private: const static int imageMargin; const static int textHeight; const static QSize imageSize; const static QSize itemSize; QList<MImageListItem*> itemList; MImageListItem* hoverItem; QScrollArea* frameArea; QPoint mouseExecPos; }; class MImageList : public QWidget { Q_OBJECT public: MImageList(QWidget *parent = 0); void addItem(MImageListItem* item); void setCurrentItem(MImageListItem* item); QList<MImageListItem*> selectedItems() const; private: MImageListPrivate* mainList; };
CPP文件:
#include "MWidget.h" #include "qapplication.h" #include "qpainter.h" #include "qscrollarea.h" #include "qscrollbar.h" #include "qgridlayout.h" #include "qevent.h" MImageListItem::MImageListItem(const QImage& image, const QString& text) : iimage(image), itext(text) { iselected = false; iparent = 0; } void MImageListItem::setSelected(bool select) { bool changed = (iselected != select); iselected = select; if (changed && iparent) { iparent->update(); } } bool MImageListItem::isSelected() const { return iselected; } void MImageListItem::setText(const QString& text) { itext = text; if (iparent) { iparent->update(); } } QString MImageListItem::text() const { return itext; } void MImageListItem::setImage(const QImage& image) { iimage = image; if (iparent) { iparent->update(); } } QImage MImageListItem::image() const { return iimage; } void MImageListItem::setParent(MImageListPrivate* parent) { iparent = parent; } ///////////////////////////////////////////////////////////////////////////////////////// const int MImageListPrivate::imageMargin = 6; const int MImageListPrivate::textHeight = 20; const QSize MImageListPrivate::imageSize(120, 90); const QSize MImageListPrivate::itemSize(imageSize.width() + 2 * imageMargin, imageMargin + imageSize.height() + textHeight); MImageListPrivate::MImageListPrivate(QScrollArea* frame, QWidget* parent) : QWidget(parent), hoverItem(0) { frameArea = frame; setMouseTracking(true); } MImageListPrivate::~MImageListPrivate() { for (auto it : itemList) { delete it; } } void MImageListPrivate::addItem(MImageListItem* item) { item->setParent(this); itemList.push_back(item); int count = (int)itemList.size(); int w = itemSize.width() * count; int h = itemSize.height(); setMinimumSize(w, h); } QList<MImageListItem*> MImageListPrivate::selectedItems() const { QList<MImageListItem*> selects; for (auto it : itemList) { if (it->isSelected()) { selects.push_back(it); } } return selects; } int MImageListPrivate::indexOf(MImageListItem* item) const { int count = (int)itemList.size(); for (int i = 0; i < count; i++) { if (item == itemList[i]) { return i; } } return -1; } void MImageListPrivate::setCurrentItem(MImageListItem* item) { item->setSelected(true); setItemVisible(indexOf(item)); } void MImageListPrivate::paintEvent(QPaintEvent*) { QPainter painter(this); int count = (int)itemList.size(); for (int i = 0; i < count; i++) { int leftEdge = itemSize.width() * i + x(); int rightEdge = leftEdge + itemSize.width(); /* 计算当前item的左边和右边坐标,如果不在可视范围内则跳过 */ if (rightEdge < 0 || leftEdge > frameArea->width()) { continue; } QPoint offset; offset.setX(imageMargin + itemSize.width() * i); offset.setY(imageMargin); painter.drawImage(QRect(offset, imageSize), itemList[i]->image()); painter.setBrush(Qt::NoBrush); if (itemList[i]->isSelected()) { painter.setPen(QPen(QColor(32, 243, 243), 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); painter.drawRect(QRect(offset, imageSize).adjusted(-2, -2, 2, 2)); } else if (itemList[i] == hoverItem) { painter.setPen(QPen(QColor(173, 255, 255), 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); painter.drawRect(QRect(offset, imageSize).adjusted(-2, -2, 2, 2)); } painter.setPen(Qt::black); offset.setY(imageMargin + imageSize.height()); QSize textSize(imageSize.width(), textHeight); QFontMetrics fm = painter.fontMetrics(); QString zipText = fm.elidedText(itemList[i]->text(), Qt::ElideRight, textSize.width()); QSize sz = fm.size(0, zipText); offset.setX(offset.x() + (textSize.width() - sz.width()) / 2); offset.setY(offset.y() + (textSize.height() - sz.height()) / 2); painter.drawText(QRect(offset, sz), zipText); } } MImageListItem* MImageListPrivate::hitTest(const QPoint& pos) const { int count = (int)itemList.size(); for (int i = 0; i < count; i++) { QRect rect; rect.setX(itemSize.width() * i); rect.setY(0); rect.setWidth(itemSize.width()); rect.setHeight(itemSize.height()); if (rect.contains(pos)) { return itemList[i]; } } return 0; } void MImageListPrivate::mousePressEvent(QMouseEvent* event) { if (event->button() == Qt::LeftButton) { mouseExecPos = event->pos(); } } void MImageListPrivate::mouseReleaseEvent(QMouseEvent* event) { if (event->button() == Qt::LeftButton && mouseExecPos == event->pos()) { MImageListItem* hit = hitTest(mouseExecPos); if (hit) { if (!hit->isSelected()) { clearSelection(); hit->setSelected(true); } emit itemClicked(hit); } } } void MImageListPrivate::mouseMoveEvent(QMouseEvent* event) { MImageListItem* hit = hitTest(event->pos()); if (hit != hoverItem) { setToolTip(QString()); hoverItem = hit; if (hoverItem) { setToolTip(hoverItem->text()); } update(); } } void MImageListPrivate::mouseDoubleClickEvent(QMouseEvent* event) { MImageListItem* hit = hitTest(event->pos()); if (hit) { emit itemDoubleClicked(hit); } } void MImageListPrivate::wheelEvent(QWheelEvent* event) { qApp->sendEvent(frameArea->horizontalScrollBar(), event); } void MImageListPrivate::enterEvent(QEvent* event) { // nothing. } void MImageListPrivate::leaveEvent(QEvent* event) { hoverItem = 0; update(); } void MImageListPrivate::clearSelection() { for (auto it : itemList) { it->setSelected(false); } } void MImageListPrivate::setItemVisible(int index) { int padding = itemSize.width() / 2; int offset = index * itemSize.width() + padding; frameArea->ensureVisible(offset, 0, padding); } bool MImageListPrivate::focusNextPrevChild(bool next) { int count = (int)itemList.size(); if (next) { int last = 0; for (int i = count - 1; i >= 0; i--) { if (itemList[i]->isSelected()) { last = i; break; } } if (last < count - 1) { clearSelection(); last++; itemList[last]->setSelected(true); setItemVisible(last); return true; } } else { int first = 0; for (int i = 0; i < count; i++) { if (itemList[i]->isSelected()) { first = i; break; } } if (first > 0) { clearSelection(); first--; itemList[first]->setSelected(true); setItemVisible(first); return true; } } return false; } void MImageListPrivate::keyPressEvent(QKeyEvent* event) { switch (event->key()) { case Qt::Key_Right: focusNextPrevChild(true); break; case Qt::Key_Left: focusNextPrevChild(false); break; default: break; } } void MImageListPrivate::keyReleaseEvent(QKeyEvent* event) { // nothing. } ///////////////////////////////////////////////////////////////////////////////////////// MImageList::MImageList(QWidget *parent) : QWidget(parent) { QScrollArea* area = new QScrollArea(this); area->setWidgetResizable(true); mainList = new MImageListPrivate(area, this); mainList->setFocusPolicy(Qt::StrongFocus); area->setWidget(mainList); QGridLayout* ly = new QGridLayout(this); ly->setContentsMargins(0, 0, 0, 0); ly->addWidget(area); setLayout(ly); } void MImageList::addItem(MImageListItem* item) { mainList->addItem(item); } void MImageList::setCurrentItem(MImageListItem* item) { mainList->setCurrentItem(item); } QList<MImageListItem*> MImageList::selectedItems() const { return mainList->selectedItems(); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库