0

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

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

/// <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();
    }
}

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

4

1 回答 1

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;
}
于 2020-04-25T18:37:00.453 回答