static class Extensions
{
public static float BinarySearchFontSize(this Control control, float containerHeight)
{
float
vertical = BinarySearchVerticalFontSize(control, containerHeight),
horizontal = BinarySearchHorizontalFontSize(control);
return Math.Min(vertical, horizontal);
}
/// <summary>
/// Get a font size that produces control size between 90-100% of available height.
/// </summary>
private static float BinarySearchVerticalFontSize(Control control, float containerHeight)
{
var name = control.Name;
switch (name)
{
case "comboBox1":
Debug.WriteLine($"{control.Name}: CONTAINER HEIGHT {containerHeight}");
break;
}
var proto = new TextBox
{
Text = "|", // Vertical height independent of text length.
Font = control.Font
};
using (var graphics = proto.CreateGraphics())
{
float
targetMin = 0.9F * containerHeight,
targetMax = containerHeight,
min, max;
min = 0; max = proto.Font.Size * 2;
for (int i = 0; i < 10; i++)
{
if(proto.Height < targetMin)
{
// Needs to be bigger
min = proto.Font.Size;
}
else if (proto.Height > targetMax)
{
// Needs to be smaller
max = proto.Font.Size;
}
else
{
break;
}
var newSizeF = (min + max) / 2;
proto.Font = new Font(control.Font.FontFamily, newSizeF);
proto.Invalidate();
}
return proto.Font.Size;
}
}
/// <summary>
/// Get a font size that fits text into available width.
/// </summary>
private static float BinarySearchHorizontalFontSize(Control control)
{
var name = control.Name;
// Fine-tuning
string text;
if (control is ButtonBase)
{
text = "SETTINGS"; // representative max staing
}
else
{
text = string.IsNullOrWhiteSpace(control.Text) ? "LOCAL FOLDERS" : control.Text;
}
var protoFont = control.Font;
using(var g = control.CreateGraphics())
{
using (var graphics = control.CreateGraphics())
{
int width =
(control is ComboBox) ?
control.Width - SystemInformation.VerticalScrollBarWidth :
control.Width;
float
targetMin = 0.9F * width,
targetMax = width,
min, max;
min = 0; max = protoFont.Size * 2;
for (int i = 0; i < 10; i++)
{
var sizeF = g.MeasureString(text, protoFont);
if (sizeF.Width < targetMin)
{
// Needs to be bigger
min = protoFont.Size;
}
else if (sizeF.Width > targetMax)
{
// Needs to be smaller
max = protoFont.Size;
}
else
{
break;
}
var newSizeF = (min + max) / 2;
protoFont = new Font(control.Font.FontFamily, newSizeF);
}
}
}
return protoFont.Size;
}
}
1条答案
按热度按时间hpxqektj1#
TableLayoutPanel
控件,并将行和列设置为使用百分比而不是绝对大小。然后,将控件放置在单元格中,并将它们锚定在所有四个边上。对于背景图像设置为
BackgroundImageLayout = Stretch
的按钮,这就是您需要做的全部工作。但是,使用文本的控件可能需要自定义方式来缩放字体。例如,您使用的ComboBox控件的大小是字体的函数,而不是相反。为了弥补这一点,这些实际屏幕截图利用扩展来进行改变字体大小直到达到目标控件高度的二分搜索。基本思想是通过设置一个看门狗定时器来响应
TableLayoutPanel
大小的变化,当定时器超时时,迭代控制树以应用BinarySearchFontSize
扩展。您可能需要将我用来测试这个答案的代码clone,并自己进行实验,看看这些部分是如何组合在一起的。像这样的东西会起作用,但你可能想做更多的测试比我没有。
TableLayoutPanel
不是一个全面的解决方案,不能缩放组合框和其他字体的高度。(对于原始帖子中的例子来说,这并不是那么微不足道)我的回答也展示了一种实现这一目标的方法。(我确实想提供"足够"的信息!)下面是一个附录,显示了调用扩展的MainForm代码。*在加载主窗体的方法中:
SizeChanged
事件的事件处理程序。TableLayoutPanel
的控制树以应用onAnyCellPaint
方法来获得小区度量并调用扩展。通过采用这种方法,可以自由地添加和/或移除单元格和控件,而不必改变缩放引擎。