c++ - 如何修改我的Qt PaintEvent代码以相对于鼠标指针缩放显示的Pixmap

标签 c++ qt

我有一个(到目前为止)相当简单的QWidget(大小为300 * 300),我正在使用它显示一个大的QPixmap(例如5184 * 3456)。该代码的关键部分如下:

void DSSImageWidget::resizeEvent(QResizeEvent* e)
{
    QSize sz = e->size();
    qreal hScale = (qreal)sz.width() / (m_pixmap.width() + 4);
    qreal vScale = (qreal)sz.height() / (m_pixmap.height() + 4);
    m_scale = std::min(hScale, vScale);

    update();
    Inherited::resizeEvent(e);
}

void DSSImageWidget::paintEvent(QPaintEvent* event)
{
    QPainter painter;
    painter.begin(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    
    //QPointF whereScaled = m_where / (m_zoom * m_scale);
    //qDebug() << "m_where:" << m_where.x() << m_where.y();
    //qDebug() << whereScaled.x() << " " << whereScaled.y();

    //painter.translate(-m_where);
    painter.scale(m_zoom*m_scale, m_zoom*m_scale);
    //painter.translate(m_where);

    painter.drawPixmap(QPointF(0.0, 0.0), m_pixmap);

    painter.setPen(QPen(QColor(255, 0, 0, alpha), 0.25, Qt::SolidLine, Qt::FlatCap, Qt::BevelJoin));
    painter.setBrush(Qt::NoBrush);
    painter.drawRect(QRectF(0, 0, m_pixmap.width(), m_pixmap.height()).adjusted(-2, -2, 2, 2));
    painter.end();
}

void DSSImageWidget::wheelEvent(QWheelEvent* e)
{
    qreal degrees = -e->angleDelta().y() / 8.0;
    //
    // If zooming in and zoom factor is currently 1.0
    // then remember mouse location
    //
    if ((degrees > 0) && (m_zoom == 1.0))
    {
        m_where = e->position();
    }
    qreal steps = degrees / 60.0;
    qreal factor = m_zoom * std::pow(1.125, steps);
    
    m_zoom = std::clamp(factor, 1.0, 5.0);
    update();
    Inherited::wheelEvent(e);
}
这样可以缩放有关窗口原点的像素图,这是一个很好的开始,但这不是我想要的。我希望它缩放像素图,以便将鼠标指针下方的图像部分保留在原处,并且图像围绕该点扩展。
我已经用painter.translate()调用以及我实际用来绘制像素图的位置播放了各种各样的乐曲,但到目前为止,我仍然无法获得出色的色彩:)。
请知道我的工作原理的人让我摆脱痛苦,并告诉我如何在这里实现目标吗?
谢谢

最佳答案

经过对代码的一些摸索之后,我终于解决了这个问题。考虑到它并非一帆风顺,我在这里发布代码的相关部分,希望对其他人有所帮助。
从标题:

typedef QWidget
        Inherited;

private:
    bool initialised;
    qreal m_scale, m_zoom;
    QPointF m_origin;
    QPixmap & m_pixmap;
    QPointF m_pointInPixmap;

    inline bool mouseOverImage(QPointF loc)
    {
        qreal x = loc.x(), y = loc.y(), ox = m_origin.x(), oy = m_origin.y();
        return (
            (x >= ox) &&
            (x <= ox + (m_pixmap.width() * m_scale)) &&
            (y >= oy) &&
            (y <= oy + (m_pixmap.height() * m_scale)));

    };
以及源代码:
DSSImageWidget::DSSImageWidget(QPixmap& p, QWidget* parent)
    : QWidget(parent),
    initialised(false),
    m_scale(1.0),
    m_zoom(1.0),
    m_origin(0.0, 0.0),
    m_pixmap(p),
    m_pointInPixmap((m_pixmap.width() / 2), (m_pixmap.height() / 2))

{
    setAttribute(Qt::WA_MouseTracking);
   
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}

void DSSImageWidget::resizeEvent(QResizeEvent* e)
{
    QSize sz = e->size();
    qreal pixWidth = m_pixmap.width();
    qreal pixHeight = m_pixmap.height();
    qreal hScale = (qreal)sz.width() / pixWidth;
    qreal vScale = (qreal)sz.height() / pixHeight;
    m_scale = std::min(hScale, vScale);

    qreal xoffset = 0.0, yoffset = 0.0;
    if ((pixWidth * m_scale) < sz.width())
    {
        xoffset = (sz.width() - (pixWidth * m_scale)) / 2.0;

    }
    if ((pixHeight * m_scale) < sz.height())
    {
        yoffset = (sz.height() - (pixHeight * m_scale)) / 2.0;
    }
    m_origin = QPointF(xoffset, yoffset);

    update();
    Inherited::resizeEvent(e);
}

void DSSImageWidget::paintEvent(QPaintEvent* event)
{
    QPainter painter;
 
    qDebug() << "pointInPixmap: " << m_pointInPixmap.x() << m_pointInPixmap.y();
    //
    // Now calcualate the rectangle we're interested in
    //
    qreal width = m_pixmap.width();
    qreal height = m_pixmap.height();
    qreal x = m_pointInPixmap.x();
    qreal y = m_pointInPixmap.y();
    QRectF  sourceRect(
        x - (x / m_zoom),
        y - (y / m_zoom),
        width / m_zoom,
        height / m_zoom
    );

    qDebug() << "sourceRect: " << sourceRect.x() << sourceRect.y() << sourceRect.width() << sourceRect.height();

    //
    // Now calculate the rectangle that is the intersection of this rectangle and the pixmap's rectangle.
    //
    sourceRect &= m_pixmap.rect();

    painter.begin(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    
    painter.translate(m_origin);
    painter.scale(m_zoom*m_scale, m_zoom*m_scale);
    painter.translate(-m_origin);

    //painter.drawPixmap(QPointF(0.0, 0.0), m_pixmap, sourceRect);
    painter.drawPixmap(m_origin, m_pixmap, sourceRect);

    painter.end();
}


#if QT_CONFIG(wheelevent)
void DSSImageWidget::wheelEvent(QWheelEvent* e)
{
    qreal degrees = -e->angleDelta().y() / 8.0;
    //
    // If zooming in and zoom factor is currently 1.0
    // then remember mouse location
    //
    if ((degrees > 0) && (m_zoom == 1.0))
    {
        QPointF mouseLocation = e->position();

        if (mouseOverImage(mouseLocation))
        {
            m_pointInPixmap = QPointF((mouseLocation-m_origin) / m_scale);
        }
        else
        {
            m_pointInPixmap = QPointF((m_pixmap.width() / 2), (m_pixmap.height() / 2));
        }
    }
    qreal steps = degrees / 60.0;
    qreal factor = m_zoom * std::pow(1.125, steps);
    
    m_zoom = std::clamp(factor, 1.0, 5.0);

    if (degrees < 0 && m_zoom == 1.0)
    {
        m_pointInPixmap = QPointF((m_pixmap.width() / 2), (m_pixmap.height() / 2));
    }
    update();
    Inherited::wheelEvent(e);
}
#endif
祝一切顺利,大卫

关于c++ - 如何修改我的Qt PaintEvent代码以相对于鼠标指针缩放显示的Pixmap,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63485308/

相关文章:

c++ - 对于具有附加(非推导)模板参数的函数,ADL 失败(或未完成?)

c++ - g++ 悬挂指针警告不一致?

c++ - 拆分一个句子,以便将每个单词添加到一个数组项中

qt - 以本地化格式显示月份和日期

c++ - 在鼠标悬停在填充栏上时更改 QProgressBar 的颜色/文本

c++ - CDT 索引器找不到 std::unordered_map

c++ - 模板类特化来处理它自己的类型

c++ - QT5.5相机预览报错

c++ - Qt C++ QTouchEvent & TouchPoint 混淆

qt - Fedora Qt 运行时包