Scale components in FlowLayout as big as possible

妖精的绣舞 提交于 2019-12-08 06:11:20

问题


How can I scale PictureBox components to best fit the given space on the screen while keeping their aspect ratio (interdependent of the actual image or its SizeMode) ?

I tested setting the Dock of the FlowLayout and the PictureBox to Fill. I also tested using a Panel as a wrapper and tested different settings for AutoSize and AutoSizeMode.

To give more information about the background: I want to dynamically add and remove images in the viewport of the application, so a TableLayout is in the first step sort of to static. I have to admit I'm was also thinking of calculating the size an position manually - or to dynamically adapt the row and column count of the TableLayout - but it seems to me prone to errors. I thought having a FlowLayout and automatically sized components should be the correct way - but it seems not to work that way. (To speak as web developer, I simply want to "float the images left", "with width and height set to 'auto'" and no scrolling.)

The images should visualize this a bit: the first figure should point out the layout, if there is only one PictureBox - it takes the whole space (or as big as possible with the given aspect ratio). The second shows how I would like the Layout to be, if there are two (three or four) images. The third figure is showing basically a resized window with three (to six) images.

Is there some point I'm missing?


回答1:


This code snippet do this:

It arranges the visible controls inside a container in respect of the aspect ratio (see R variable in the code), and uses the container margin values to get horizontal and vertical gaps between items. The padding of the container is also handled.

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;
        }
    }
}

I put this snippet on Gist so you can contribute if you wish.



来源:https://stackoverflow.com/questions/15930182/scale-components-in-flowlayout-as-big-as-possible

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!