自定义的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();
}
复制代码

 

posted @   兜尼完  阅读(687)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示