如何在保持纵横比(与实际图像或其SizeMode相互依赖)的同时,将PictureBox组件缩放到最适合屏幕上的给定空间?
我测试了将FlowLayout的Dock和PictureBox设置为Fill。我还测试了使用Panel作为包装器并测试了AutoSize和AutoSizeMode的不同设置。
提供有关背景的更多信息:我想在应用程序的视口中动态添加和删除图像,因此TableLayout在第一步是静态的。我不得不承认我还在考虑手动计算一个位置的大小 - 或者动态调整TableLayout的行数和列数 - 但我觉得容易出错。我认为拥有一个FlowLayout并且自动调整大小的组件应该是正确的方式 - 但它似乎不能那样工作。 (作为Web开发人员,我只是想“将图像浮动”,“将宽度和高度设置为'auto'”并且不滚动。)
图像应该可以看到这一点:第一个图形应该指出布局,如果只有一个PictureBox - 它占用整个空间(或者在给定的宽高比下尽可能大)。第二个显示了如果有两个(三个或四个)图像,我希望布局如何。第三个图基本上显示了一个调整大小的窗口,其中包含三个(至六个)图像。
我有什么不足之处吗?
答案 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上,以便您可以根据需要做出贡献。