在FlowLayout中扩展组件尽可能大

时间:2013-04-10 15:30:19

标签: winforms user-interface resize picturebox flowlayout

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

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

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

图像应该可以看到这一点:第一个图形应该指出布局,如果只有一个PictureBox - 它占用整个空间(或者在给定的宽高比下尽可能大)。第二个显示了如果有两个(三个或四个)图像,我希望布局如何。第三个图基本上显示了一个调整大小的窗口,其中包含三个(至六个)图像。

我有什么不足之处吗?

Desired behaviour of PictureBox components on dynamically adding more PictureBox components or resizing the application

1 个答案:

答案 0 :(得分: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上,以便您可以根据需要做出贡献。