【问题标题】:Scaling owner-draw window around mouse point围绕鼠标点缩放自绘窗口
【发布时间】:2020-08-08 08:22:26
【问题描述】:

我有一个自绘图片框 (picGrid),我希望允许用户使用鼠标滚轮进行缩放。那部分很容易。但我想自动滚动,使鼠标下的逻辑点仍然是缩放后鼠标下的逻辑点。

这是我目前所拥有的。它几乎可以工作,但只是不正确。 XScrollYScroll 是我的滚动位置,将用于设置滚动条(除了偏移图像)。

/// <summary>
/// Sets the current zoom percent.
/// </summary>
/// <param name="percent">The percent that the zoom should be set (100 == 1:1 scaling).</param>
/// <param name="x">X coordinate of the mouse in pixels.</param>
/// <param name="y">Y coordinate of the mouse in pixels.</param>
public void SetZoom(int percent, int x, int y)
{
    // If needed, this method translates mouse coordinate to logical coordinates
    // but doesn't appear to be needed here.
    //TranslateCoordinates(ref x, ref y);

    // Calculate new scale (1.0f == 1:1 scaling)
    float newDrawScale = (float)percent / 100;

    // Enforce zoom limits
    if (newDrawScale < 0.1f)
        newDrawScale = 0.1f;
    else if (newDrawScale > 1500.0f)
        newDrawScale = 1500.0f;

    // Set new zoom (if it's changed)
    if (newDrawScale != DrawScale)
    {
        DrawScale = newDrawScale;

        // *** Here's the part that isn't right ***

        // Scroll to keep same logical point under mouse
        float delta = (DrawScale - 1f);
        XScroll = (x * delta);
        YScroll = (y * delta);

        // Reflect change in scrollbars
        UpdateScrollbars();

        // Redraw content
        picGrid.Invalidate();
    }
}

如何计算新的滚动位置,以便缩放后相同的逻辑点保持在鼠标指针下方?

【问题讨论】:

  • @Spektre:谢谢。我花了很多时间查看那个答案(我看到的是你的)。有些事情让我感到困惑。例如,变量名称不是很具有描述性。此外,您的scr2obj()obj2scr() 方法在我需要减去它们的地方添加x0y0,并在需要添加它们的地方减去它们。另外,我不知道 gfx objects 是什么,所以我不明白这两个版本的代码。但是,我终于能够根据您的方法提出一个可行的解决方案。我很感激。我已经发布了我的工作代码,以防其他人受益。
  • 是的,有更多方法可以在屏幕和世界之间转换,正如您所看到的,它不仅是正/负offset,如果您在zoom 之前或之后应用offset 也是如此,如果zoom 是直接缩放或倒数,如1/zoom 这些给你2^3=8 等式组合。如果您添加变换矩阵,那么在所有这些之上还有更多可能的符号,这对于那些只是复制粘贴代码而不知道发生了什么的新手来说是一团糟。

标签: c# c++ .net algorithm graphics


【解决方案1】:

我能够解决这个问题。这就是我想出的。 (注意XOffsetYOffset 在屏幕坐标中以匹配滚动条。)

public void SetZoom(int percent, int x, int y)
{
    // Calculate new scale (100% == 1:1)
    float newDrawScale = (float)percent / 100;

    // See if scale has changed
    if (newDrawScale != DrawScale)
    {
        // Update scale and adjust offsets
        ScreenToWorld(x, y, out float logicalX, out float logicalY);
        DrawScale = newDrawScale;
        WorldToScreen(logicalX, logicalY, out float screenX, out float screenY);
        XOffset += (screenX - x);
        YOffset += (screenY - y);

        // Update scrollbars and redraw
        UpdateScrollbars();
        picGrid.Invalidate();
    }
}

private void WorldToScreen(float srcX, float srcY, out float destX, out float destY)
{
    destX = (srcX * DrawScale) - XOffset;
    destY = (srcY * DrawScale) - YOffset;
}

private void ScreenToWorld(float srcX, float srcY, out float destX, out float destY)
{
    destX = (srcX + XOffset) / DrawScale;
    destY = (srcY + YOffset) / DrawScale;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-09
    • 1970-01-01
    相关资源
    最近更新 更多