首页 > 其他分享 >自定义一个QAbstractScrollArea(二)

自定义一个QAbstractScrollArea(二)

时间:2024-02-24 16:23:10浏览次数:26  
标签:const MImageList 自定义 QAbstractScrollArea void 一个 int MListWidget event

延续上一篇文章,本文以另一种方法实现QAbstractScrollArea。此例子是一个图片缩略图的列表控件,控件沿水平方向延伸。仅作为一个例子,因为实际的图片列表可以用QListWidget实现,并不需要自己写代码。下面是程序的运行截图:

头文件:

class MListWidget : public QAbstractScrollArea
{
    Q_OBJECT

public:
    MListWidget(QWidget* parent = 0);
    void append(const QPixmap& pixmap, const QString& name);
    int currentItem() const;

private:
    bool eventFilter(QObject* src, QEvent* event) override;
    bool viewportEvent(QEvent* event) override;
    void sizeChanged(const QSize &contentSize);

private slots:
    void verticalScrollBarValueChanged(int value);
    void horizontalScrollBarValueChanged(int value);

private:
    class MImageList;
    MImageList* lists;
};

class MListWidget::MImageList : public QWidget
{
    Q_OBJECT

public:
    MImageList(QWidget* parent = 0);
    void append(const QPixmap& pixmap, const QString& name);
    int currentItem() const;

private:
    void paintEvent(QPaintEvent* event) override;
    void mouseMoveEvent(QMouseEvent* event) override;
    void mousePressEvent(QMouseEvent* event) override;
    void mouseReleaseEvent(QMouseEvent* event) override;
    void enterEvent(QEvent* event) override;
    void leaveEvent(QEvent* event) override;

private:
    static const QSize imageSize;
    static const QSize textSize;
    static const int itemMargin;
    QVector<QPixmap> images;
    QStringList texts;
    QPoint pressPt;
    int hoverItem;
    int clickItem;
};

CPP文件。代码约200行太长我把它折叠了:

MListWidget::MListWidget(QWidget* parent) : 
    QAbstractScrollArea(parent)
{
    QScrollBar* vbar = verticalScrollBar();
    connect(vbar, &QScrollBar::valueChanged, this, &MListWidget::verticalScrollBarValueChanged);
    QScrollBar* hbar = horizontalScrollBar();
    connect(hbar, &QScrollBar::valueChanged, this, &MListWidget::horizontalScrollBarValueChanged);

    lists = new MImageList(viewport());
    lists->installEventFilter(this);
}

int MListWidget::currentItem() const
{
    return lists->currentItem();
}

bool MListWidget::eventFilter(QObject* src, QEvent* event)
{
    if (src == lists && event->type() == QEvent::Resize)
    {
        /* 内容Widget的大小变化 */
        QResizeEvent* rszEvent = dynamic_cast<QResizeEvent*>(event);
        sizeChanged(rszEvent->size());
    }
    return QAbstractScrollArea::eventFilter(src, event);
}

bool MListWidget::viewportEvent(QEvent* event)
{
    if (event->type() == QEvent::Resize)
    {
        /* viewport的大小变化 */
        sizeChanged(lists->size());
    }
    return QAbstractScrollArea::viewportEvent(event);
}

void MListWidget::append(const QPixmap& pixmap, const QString& name)
{
    lists->append(pixmap, name);
}

void MListWidget::verticalScrollBarValueChanged(int value)
{
    lists->move(lists->x(), -value);
}

void MListWidget::horizontalScrollBarValueChanged(int value)
{
    lists->move(-value, lists->y());
}

void MListWidget::sizeChanged(const QSize &contentSize)
{
    QScrollBar* vbar = verticalScrollBar();
    vbar->setMinimum(0);
    vbar->setMaximum(std::max(0, contentSize.height() - viewport()->height()));
    vbar->setPageStep(viewport()->height());
    QScrollBar* hbar = horizontalScrollBar();
    hbar->setMinimum(0);
    hbar->setMaximum(std::max(0, contentSize.width() - viewport()->width()));
    hbar->setPageStep(viewport()->width());
}

/////////////////////////////////////////////////////////////////////////////////////////

const QSize MListWidget::MImageList::imageSize(100, 80);
const QSize MListWidget::MImageList::textSize(100, 22);
const int MListWidget::MImageList::itemMargin = 6;

MListWidget::MImageList::MImageList(QWidget* parent) :
    QWidget(parent), pressPt(0xDEADBEEF, 0xDEADBEEF)
{
    setMouseTracking(true);
    hoverItem = -1;
    clickItem = -1;
}

void MListWidget::MImageList::append(const QPixmap& pixmap, const QString& name)
{
    images.push_back(pixmap);
    texts.push_back(name);
    int count = images.size();
    int w = count * (imageSize.width() + 2 * itemMargin);
    int h = imageSize.height() + textSize.height() + itemMargin;
    setFixedSize(w, h);
    update();
}

void MListWidget::MImageList::paintEvent(QPaintEvent* event)
{
    QPainter painter(this);
    for (int i = 0; i < images.size(); i++)
    {
        int x = i * (imageSize.width() + 2 * itemMargin) + itemMargin;
        int y = itemMargin;
        painter.drawPixmap(QRect(QPoint(x, y), imageSize), images[i]);
        y += imageSize.height();
        painter.drawText(QRect(QPoint(x, y), textSize), Qt::AlignCenter, texts[i]);
        if (clickItem == i)
        {
            int itemx = x - itemMargin;
            int itemy = 0;
            int itemw = imageSize.width() + 2 * itemMargin - 1;
            int itemh = imageSize.height() + textSize.height() + itemMargin - 1;
            painter.save();
            painter.setPen(QColor(97, 142, 229, 97));
            painter.setBrush(QColor(97, 172, 249, 97));
            painter.drawRect(QRect(itemx, itemy, itemw, itemh));
            painter.restore();
        }
        else if (hoverItem == i)
        {
            int itemx = x - itemMargin;
            int itemy = 0;
            int itemw = imageSize.width() + 2 * itemMargin - 1;
            int itemh = imageSize.height() + textSize.height() + itemMargin - 1;
            painter.save();
            painter.setPen(QColor(97, 142, 229, 63));
            painter.setBrush(QColor(97, 172, 249, 63));
            painter.drawRect(QRect(itemx, itemy, itemw, itemh));
            painter.restore();
        }
    }
}

void MListWidget::MImageList::mouseMoveEvent(QMouseEvent* event)
{
    int itemw = imageSize.width() + 2 * itemMargin;
    int itemh = imageSize.height() + textSize.height();
    if (event->pos().y() < itemh)
    {
        hoverItem = event->pos().x() / itemw;
        update();
    }
}

void MListWidget::MImageList::mousePressEvent(QMouseEvent* event)
{
    if (hoverItem >= 0)
    {
        pressPt = event->pos();
        update();
    }
}

void MListWidget::MImageList::mouseReleaseEvent(QMouseEvent* event)
{
    if ((event->pos() - pressPt).manhattanLength() <= 2)
    {
        pressPt = QPoint(0xDEADBEEF, 0xDEADBEEF);
        clickItem = hoverItem;
        update();
    }
}

void MListWidget::MImageList::enterEvent(QEvent* event)
{
    // do nothing.
}

void MListWidget::MImageList::leaveEvent(QEvent* event)
{
    if (hoverItem >= 0)
    {
        hoverItem = -1;
        update();
    }
}

int MListWidget::MImageList::currentItem() const
{
    return clickItem;
}
View Code

在主窗口添加几个项即可。下方代码中,QtTest是主窗口类,ui.ivSelect是MListWidget类:

QtTest::QtTest(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    QPixmap myImage(200, 200);
    myImage.fill(Qt::green);
    ui.ivSelect->append(myImage, u8"图像1");
    ui.ivSelect->append(myImage, u8"图像2");
    ui.ivSelect->append(myImage, u8"图像3");
    ui.ivSelect->append(myImage, u8"图像4");
    ui.ivSelect->append(myImage, u8"图像5");
    ui.ivSelect->append(myImage, u8"图像6");
    ui.ivSelect->append(myImage, u8"图像7");
    ui.ivSelect->append(myImage, u8"图像8");
    ui.ivSelect->append(myImage, u8"图像9");
    ui.ivSelect->append(myImage, u8"图像A");
}

:经过查找Qt帮助文档。我发现上方的两个处理滚动条值改变的槽函数是多余的。Qt默认已经响应了滚动条的事件,封装成虚函数QAbstractScrollArea::scrollContentsBy(...)。只需要重写这个虚函数,根据此函数传入的水平垂直偏移增量计算新的显示内容就行了。不用手动连接滚动条的信号。

标签:const,MImageList,自定义,QAbstractScrollArea,void,一个,int,MListWidget,event
From: https://www.cnblogs.com/mengxiangdu/p/17919725.html

相关文章

  • 陪玩app开发,实现一个爱心按钮的代码解析
    陪玩app开发,实现一个爱心按钮的代码解析❤️爱心按钮制作一个爱心的方式有很多,可以用图标库的爱心,可以写一个svg,可以用图片,我这里就用伪元素的方式做一个爱心。<!--fullLove.html--><divclass="likeBtn"id="likeBtn"><spanclass="heart"id="heart"></span></......
  • 前端防抖-通过自定义指令实现
    前端防抖-通过自定义指令实现1、通过自定义事件实现前端防抖Vue.directive('preventReClick',{inserted(el,binding){el.addEventListener('click',()=>{if(!el.disabled){el.disabled=truesetTimeout(()=>......
  • Unity编辑器扩展秘籍-利用EditorApplication.contextualPropertyMenu为右键菜单增加自
    假设我们希望为材质右键弹出按钮增加新的功能,应该怎么做呢我们可以通过注册EditorApplication.contextualPropertyMenu全局回调方法,增加自定义的MenuItemusingUnityEditor;usingUnityEngine;namespaceYaojz{[InitializeOnLoad]publicstaticclassMaterialC......
  • 记录 re:Invent 大会,使用 PartyRock 编写我们第一个 AI 应用以及心得
    如果说2023年什么应用技术最火,那么说是OpenAI为代表的ChatGPT在AI方面的突破和发展,是完全没有任何的争议的。随后,各大云厂商以及应用集成商甚至垂直领域的服务提供商都有了对应的AI模型。我们开玩笑的说,这个好比多年前的百团大战一样,各种的AI相关的应用奔涌出现、百......
  • 盘点一个Python自动化办公Excel数据处理的需求
    大家好,我是Python进阶者。一、前言前几天在Python白银交流群【干锅牛蛙】问了一个Python处理Excel数据的问题。问题如下:有两个问题哈:1、表头有合并单元格识别不出来,如何处理类似下图2、遇到单元格有公式自动识别成了0,如何处理,保留计算后的值,类似下图附上他自己的代码如下:目......
  • 设两个三角形分别为T1和T2,T1的三个端点为A、B、C,T2的三个端点为D、B、C,如何在BC上找到
    如果把T1和T2在平面上展开,问题就简单了。平面上,两个顶点的最短距离就是直线距离。所以,AC和BC的交点P就是所求的点。而2D和3D问题在本质上是一致的,那么原问题就转换为:如何在3D上找到交点P。点A和D向着BC做垂线,记垂足为P1和P2,那么P1、A、P和P2、D、P就构成两个相似三角形,根据相......
  • docker 自定义网络
    docker的网络分为:单主机、跨主机这篇先说:单主机我们先说一下docker的原生网络模式网络模式简介优点使用场景none空网络,没有网络此网络与外界隔离,安全度非常高适合公司内部生产密钥host容器与宿主机共享namespace直接使用宿主机的网络,网络性能方面最好。......
  • 自定义QComboBox解决QCombobox设置样式并与QDateTime一起使用时候弹出选项乱跳
    头文件:#pragmaonce#include<QToolButton>#include<QListView>#include<QWidgetAction>#include<QPushButton>#include<QHBoxLayout>#include<QMenu>#include<QStandardItemModel>#include<qdebug.h>classCustomCo......
  • k8s prometheus监控自定义exporter接口
    案例1:我有的k8s中所有pod应用资源监控接口是/actuator/prometheus,但是默认prometheus监控的是/metrics,这是需要修改prometheus-server的configmap,修改抓取资源监控的api接口需要找到kubernetes-service-endpoints这一项,然后找到action:replace,然后添加replacement案例2:如果......
  • 两个不同的 List 拼接,根据公共字段进行拼接,放入一个新的集合
    //List1List<FaultReport>reportDetail=reportMapper.getReportDetail(pagePo);List<Long>collect=reportDetail.stream().map(FaultReport::getId).collect(Collectors.toList());//List2List<FaultAppro......