保持按钮位置与调整大小的图像成比例

5

我正试图创建一个Winforms应用程序,在其中一个屏幕上,我有一个图像和一些在运行时生成的按钮,现在我希望这些按钮始终与图像成比例。

例如 Hand1 按钮始终应该停留在图像的 Hand1 位置。

这是我的初始图像:

初始图像

但在调整窗体大小时,它会变成这样:

输入图像描述

我希望这些按钮不改变其大小并始终与图像成比例。

图像的 ImageSizeMode 是 StretchImage,而按钮没有被 Anchored (否则它们不会移动或开始拉伸/缩小)。

我该如何实现这种行为呢?


图片是在窗体上还是在图片框上? - γηράσκω δ' αεί πολλά διδασκόμε
@valter,它在一个图片框上。 - Pankaj
3个回答

2

这是一个简单完整的单按钮解决方案:

注意:缩放是相对于控件(按钮)的左上角计算的。如果需要修改缩放比例,例如到中间或下方/右侧,则必须调整缩放计算。否则,位置看起来不太精确,按钮将随着图像的调整而“漫游”。

using System;
using System.Drawing;
using System.Windows.Forms;

public partial class Form1 : Form
{
    // X, Y scaling variables for btn1
    private float _btn1xScale;
    private float _btn1yScale;

    public Form1()
    {
        InitializeComponent();

        // The scale is really the % of btn X & Y along image width and height:
        // Calculate X and Y scale from initial location and position in image
        // Has to happen AFTER InitializeComponent is called!
        _btn1xScale = btn1.Location.X / (float)pictureBox1.Width;
        _btn1yScale = btn1.Location.Y / (float)pictureBox1.Height;
    }

    private void pictureBoxResize(object sender, EventArgs e)
    {
        // adjust position based on 
        btn1.Location = new Point(
            (int)(pictureBox1.Width * _btn1xScale), 
            (int)(pictureBox1.Height * _btn1yScale));
    }
}

Fancier version:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

public partial class Form1 : Form
{
    private List<ControlScaler> _buttonsToScale = new List<ControlScaler>();

    public Form1()
    {
        InitializeComponent();

        // Has to happen AFTER InitializeComponent is called!
        _buttonsToScale.Add(new ControlScaler(btn1, pictureBox1));
        _buttonsToScale.Add(new ControlScaler(btn2, pictureBox1));
    }

    private void pictureBoxResize(object sender, EventArgs e)
    {
        foreach (var control in _buttonsToScale)
            control.AdjustPositionToScale();
    }
}

public class ControlScaler
{
    // X, Y scaling variables
    private float _btn1xScale;
    private float _btn1yScale;

    private Control _scaledControl;
    private readonly Control _scaleTo;

    public ControlScaler(Control scaledControl, Control scaleTo)
    {
        _scaledControl = scaledControl;
        _scaleTo = scaleTo;

        _btn1xScale = scaledControl.Location.X / (float)scaleTo.Width;
        _btn1yScale = scaledControl.Location.Y / (float)scaleTo.Height;
    }

    public void AdjustPositionToScale()
    {
        var newLocation = new Point(
            (int)(_scaleTo.Width * _btn1xScale),
            (int)(_scaleTo.Height * _btn1yScale));

        _scaledControl.Location = newLocation;
    }
}

谢谢@Paul,现在看起来很有前途。让我现在尝试多个按钮。 - Pankaj
@Pankaj:看看我的代码第二个版本。它允许你通过将新对象添加到列表中来简单地添加按钮。你不需要重新创建变量等。它更加清晰和少出错! - Paul Sasik
@Pankaj:请注意新增的注释。比例是根据按钮的左上角计算的。如果您将按钮放置在预期的中间或右下角,则需要进行不同的计算。但是,如果需要,您肯定能够解决这个问题。 - Paul Sasik
foreach (var control in Controls) { if (control is Button) { Button controlButton = (Button) control; _buttonsToScale.Add(new ControlScaler(controlButton, pictureBox1)); } } - Pankaj
@Pankaj:这也可以,只要你需要所有的按钮参与。 :-) 如果您在表单中添加了OK/Cancel按钮,则需要将它们从集合中删除... - Paul Sasik
谢谢@paul,我已经编辑了你的答案。在为多个按钮进行操作时,我所做的工作与你的工作有90%的相似之处。 - Pankaj

1
这个解决方案适用于 hand1 按钮。相同的逻辑也适用于其他按钮。

enter image description here

您希望保持距离c和d不变。首先测量a,b,c,d并:

double dblHand1X, dblHand1Y;

private void Form1_Load(object sender, EventArgs e)
    {
        dblHand1X= (double)b / (double)pictureBox1.Width;
        dblHand1Y= (double)a / (double)pictureBox1.Height;
    }

private void pictureBox1_SizeChanged(object sender, EventArgs e)
    {
        int x, y;

        x = (int)(dblHand1X* (double)pictureBox1.Width) + pictureBox1.Location.X;
        y = (int)(dblHand1Y* (double)pictureBox1.Height) + pictureBox1.Location.Y;

        x -= d;
        y -= c;
        Hand1.Location = new Point(x, y);
    }

valter


0

您将不得不手动移动按钮。

  1. 为所有按钮选择原点。例如,“手 1” 按钮的原点可能是 (button.Width / 2; button.Height),“腿 2” 按钮的原点是 (0; button.Height)

  2. 计算并保存按钮原点的位置:(OriginalX; OriginalY)

  3. 当窗体调整大小时,通过比例缩放原始位置:(OriginalX * ScaleX; OriginalY * ScaleY)。然后根据原点的新位置设置按钮的位置:(OriginalX * ScaleX - OriginX; OriginalY * ScaleY - OriginY)

按钮应锚定在左上角。


这些计算不正确。请参考我的和 @valter 的答案,以获得正确的计算和处理方法。 - Paul Sasik
@PaulSasik 你通过将原点设置为(0;0),添加图像偏移量来删除了一些逻辑,并且这些是唯一的区别。我很惊讶OP接受了你的答案,因为正如你所警告的那样,按钮确实会"漫游"。 - Athari
我没有将原点设置为0, 0。如果您运行代码,您会发现一切都是正确的。这就是为什么答案被接受的原因。(按钮实际上粘在哪里由用户决定。当我测试我的解决方案时,我意识到您可能想将其设置为单独的属性,但这超出了OP的范围。)不过,我已经取消了我的负评。再次阅读您的答案后,我明白了您的意图。 - Paul Sasik
@PaulSasik 当我看到 OP 提供的图片时,我觉得他想让按钮“附着”在图片中的那些线上。你的解决方案并没有提供这个功能(Valter 的解决方案则有;它更或多或少地实现了我的解决方案,只是比例系数像你们两个一样移动了一下)。好吧,事实证明你正确地读懂了 OP 的心思,这种复杂性是不必要的。 - Athari
我真的不确定 OP 想要什么,所以我实现了最简单的可执行解决方案,并添加了有关偏移量计算的注释。此外,从图片上看,我猜测 OP 需要创建可设置的锚点。根据我们的讨论,我知道他喜欢我建议的代码组织方式。顺便说一句,如果你实现你的伪代码,你会发现有些变量是不需要持久化的。 - Paul Sasik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接