Winforms 尽可能大地缩放FlowLayout中的组件

Winforms 尽可能大地缩放FlowLayout中的组件,winforms,user-interface,resize,picturebox,flowlayout,Winforms,User Interface,Resize,Picturebox,Flowlayout,我如何缩放PictureBox组件以最适合屏幕上的给定空间,同时保持其纵横比(与实际图像或其SizeMode相互依赖) 我测试了设置FlowLayout的Dock和要填充的PictureBox。我还使用面板作为包装进行了测试,并测试了AutoSize和AutoSizeMode的不同设置 为了提供更多关于背景的信息:我想在应用程序的视口中动态添加和删除图像,因此TableLayout是静态的第一步。我不得不承认,我也在考虑手动计算位置的大小——或者动态调整TableLayout的行和列计数——但在

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

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

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

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

有什么我遗漏的吗


此代码段执行以下操作:

它根据纵横比排列容器内的可见控件(请参见代码中的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;
        }
    }
}
publicstaticvoidarrange(控制容器)
{
var H=container.DisplayRectangle.Height;
var W=container.DisplayRectangle.Width;
var N=container.Controls.OfType().Count(c=>c.Visible);
var R=4/3d;//项目纵横比
var保证金=容器保证金;
var padding=container.padding;
var horizontalGap=保证金.左+保证金.右;
var verticalGap=页边距.顶部+页边距.底部;
如果(N==0)
返回;
var bestSizedItem=(
//尝试n行
枚举范围(1,N)。选择(testRowCount=>
{
var testItemHeight=(H-verticalGap*(testRowCount-1))/testRowCount;
还新
{
testColCount=(int)数学上限((double)N/testRowCount),
testRowCount=testRowCount,
testItemHeight=(int)testItemHeight,
testItemWidth=(int)(testItemHeight*R)
};
})
//尝试n列
康卡特先生(
枚举范围(1,N)。选择(testColCount=>
{
var testItemWidth=(W-水平间隙*(testColCount-1))/testColCount;
还新
{
testColCount=testColCount,
testRowCount=(int)数学上限((double)N/testColCount),
testItemHeight=(int)(testItemWidth/R),
testItemWidth=(int)testItemWidth
};
})))
//当它太大时移除
其中(item=>item.testItemWidth*item.testColCount+horizontalGap*(item.testColCount-1)c.Visible))
{
控制立根(x,y,
bestSizedItem.testItemWidth,
最佳尺寸试验高度);
x+=最佳尺寸测试项宽度+水平间隙;
如果(x+bestSizedItem.testItemWidth-水平间隙>W)
{
x=container.DisplayRectangle.x;
y+=最佳尺寸试验高度+垂直间隙;
}
}
}

我把这段代码放在上面,这样你可以根据自己的意愿做出贡献。

你可能应该使用TableLayoutPanel而不是FlowLayoutPanel,但是你的文章没有描述你将使用的逻辑,它决定了你希望使用的列数和行数。这种逻辑很可能是您的自定义代码。谢谢,实际上这是问题的一部分。我只是稍微修改了一下描述。行的数量应该(至少这将是巨大的)根据当前图像的数量和给定的(固定的)纵横比来隐式确定,例如,所有图像的行数为4:3。