1

如何缩放 PictureBox 组件以最适合屏幕上的给定空间,同时保持它们的纵横比(与实际图像或其 SizeMode 相互依赖)?

我测试了将 FlowLayout 的 Dock 和 PictureBox 设置为 Fill。我还使用面板作为包装器进行了测试,并测试了 AutoSize 和 AutoSizeMode 的不同设置。

提供有关背景的更多信息:我想在应用程序的视口中动态添加和删除图像,因此 TableLayout 在第一步中是静态的。我不得不承认我也在考虑手动计算位置的大小 - 或者动态调整 TableLayout 的行数和列数 - 但在我看来很容易出错。我认为拥有 FlowLayout 和自动调整大小的组件应该是正确的方法 - 但它似乎不是那样工作的。(作为 Web 开发人员,我只想“将图像向左浮动”,“宽度和高度设置为‘自动’”并且不滚动。)

图像应该有点形象化:第一个图应该指出布局,如果只有一个 PictureBox - 它占用整个空间(或在给定的纵横比下尽可能大)。第二个显示我希望布局如何,如果有两个(三个或四个)图像。第三个图基本上显示了一个带有三个(到六个)图像的调整大小的窗口。

我有什么遗漏吗?

PictureBox 组件在动态添加更多 PictureBox 组件或调整应用程序大小时的期望行为

4

1 回答 1

0

此代码段执行此操作:

它根据纵横比排列容器内的可见控件(参见代码中的 R 变量),并使用容器边距值来获取项目之间的水平和垂直间隙。容器的填充也被处理。

public static void Arrange(Control container)
{
    var H = container.DisplayRectangle.Height;
    var W = container.DisplayRectangle.Width;
    var N = container.Controls.OfType<Control>().Count(c => c.Visible);
    var R = 4 / 3d; // item aspect ratio

    var margin = container.Margin;
    var padding = container.Padding;

    var horizontalGap = margin.Left + margin.Right;
    var verticalGap = margin.Top + margin.Bottom;

    if (N == 0)
        return;

    var bestSizedItem = (

        // Try n rows
        Enumerable.Range(1, N).Select(testRowCount =>
        {
            var testItemHeight = (H - verticalGap * (testRowCount - 1)) / testRowCount;

            return new
            {
                testColCount = (int)Math.Ceiling((double)N / testRowCount),
                testRowCount = testRowCount,
                testItemHeight = (int)testItemHeight,
                testItemWidth = (int)(testItemHeight * R)
            };
        })

        // Try n columns
        .Concat(
        Enumerable.Range(1, N).Select(testColCount =>
        {
            var testItemWidth = (W - horizontalGap * (testColCount - 1)) / testColCount;

            return new
            {
                testColCount = testColCount,
                testRowCount = (int)Math.Ceiling((double)N / testColCount),
                testItemHeight = (int)(testItemWidth / R),
                testItemWidth = (int)testItemWidth
            };
        })))

        // Remove when it's too big
        .Where(item => item.testItemWidth * item.testColCount + horizontalGap * (item.testColCount - 1) <= W &&
                       item.testItemHeight * item.testRowCount + verticalGap * (item.testRowCount - 1) <= H)

        // Get the biggest area
        .OrderBy(item => item.testItemHeight * item.testItemWidth)
        .LastOrDefault();

    Debug.Assert(bestSizedItem != null);

    if (bestSizedItem == null)
        return;

    int x = container.DisplayRectangle.X;
    int y = container.DisplayRectangle.Y;

    foreach (var control in container.Controls.OfType<Control>().Where(c => c.Visible))
    {
        control.SetBounds(x, y,
            bestSizedItem.testItemWidth,
            bestSizedItem.testItemHeight);

        x += bestSizedItem.testItemWidth + horizontalGap;
        if (x + bestSizedItem.testItemWidth - horizontalGap > W)
        {
            x = container.DisplayRectangle.X;
            y += bestSizedItem.testItemHeight + verticalGap;
        }
    }
}

我将此片段放在Gist上,以便您可以根据需要做出贡献。

于 2013-05-22T20:29:30.260 回答