在我全新的Windows 11桌面上,我在稳定生产应用程序中用来指示"已连接数据库“状态的位图在4K 150%缩放的显示屏上突然看起来很糟糕(显示器还是和以前一样)。这个问题似乎是TreeView
特有的,因为同一Form
上的同一位图在设置为Label
的图像时看起来没有问题。在新机器上运行的Win 10虚拟机上看起来还可以。而且主要影响绿色的那个。奇怪。
无论如何,我不能只是坐在那里哭-我真的需要想出一个新的方法来绘制它,看起来100%正确的时间。所以我尝试了一种新的方法,使用字形字体,它看起来很好,当我把它放在一组标签清晰。
在TableLayoutPanel中看起来不错。
我现在需要做的是生成一个ImageList用于树视图,作为概念验证,我尝试使用Control.DrawToBitmap
从标签生成一个运行时ImageList。我添加了一个#DEBUG
块来保存位图,我可以在MS Paint中打开它们,它们看起来很好(当然这里放大了很多)。
在.bmp文件中看起来不错。
当然,这会有所改善,但仍有一些明显的像素缺陷,看起来像噪声抗锯齿或调整大小的伪像,即使我很注意对所有东西都使用一致的32 x 32大小。我已经弄乱了ImageList
的ColorDepth
和ImageSize
属性。我浪费了几个小时试图理解和修复它。它发生在我的产品代码中。它'这种情况发生在我下面详述的最小可复制样本中。所以,在我把剩下的头发扯掉之前,也许有人能发现我做错了什么,或者告诉我一个更好的方法。
这是我在GitHub上的代码或browse完整示例。
public partial class HostForm : Form
{
public HostForm()
{
InitializeComponent();
#if DEBUG
_imgFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Paint")!;
Directory.CreateDirectory(_imgFolder);
#endif
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
BackColor = Color.Teal;
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Fonts", "database.ttf")!;
privateFontCollection.AddFontFile(path);
var fontFamily = privateFontCollection.Families[0];
var font = new Font(fontFamily, 13.5F);
var backColor = Color.FromArgb(128, Color.Teal);
tableLayoutPanel.BackColor = backColor;
// Stage the glyphs in the TableLayoutPanel.
setLabelAttributes(label: label0, font: font, text: "\uE800", foreColor: Color.LightGray, backColor: backColor);
setLabelAttributes(label: label1, font: font, text: "\uE800", foreColor: Color.LightSalmon, backColor: backColor);
setLabelAttributes(label: label2, font: font, text: "\uE800", foreColor: Color.LightGreen, backColor: backColor);
setLabelAttributes(label: label3, font: font, text: "\uE800", foreColor: Color.Blue, backColor: backColor);
setLabelAttributes(label: label4, font: font, text: "\uE800", foreColor: Color.Gold, backColor: backColor);
setLabelAttributes(label: label5, font: font, text: "\uE801", foreColor: Color.LightGray, backColor: backColor);
setLabelAttributes(label: label6, font: font, text: "\uE801", foreColor: Color.LightSalmon, backColor: backColor);
setLabelAttributes(label: label7, font: font, text: "\uE801", foreColor: Color.LightGreen, backColor: backColor);
setLabelAttributes(label: label8, font: font, text: "\uE801", foreColor: Color.Blue, backColor: backColor);
setLabelAttributes(label: label9, font: font, text: "\uE801", foreColor: Color.Gold, backColor: backColor);
setLabelAttributes(label: label10, font: font, text: "\uE803", foreColor: Color.LightGray, backColor: backColor);
setLabelAttributes(label: label11, font: font, text: "\uE803", foreColor: Color.LightSalmon, backColor: backColor);
setLabelAttributes(label: label12, font: font, text: "\uE803", foreColor: Color.LightGreen, backColor: backColor);
setLabelAttributes(label: label13, font: font, text: "\uE803", foreColor: Color.Blue, backColor: backColor);
setLabelAttributes(label: label14, font: font, text: "\uE802", foreColor: Color.LightGray, backColor: backColor);
setLabelAttributes(label: label15, font: font, text: "\uE804", foreColor: Color.LightGreen, backColor: backColor);
makeRuntimeImageList();
}
private void setLabelAttributes(Label label, Font font, string text, Color foreColor, Color backColor)
{
label.UseCompatibleTextRendering = true;
label.Font = font;
label.Text = text;
label.ForeColor = foreColor;
label.BackColor = Color.FromArgb(200, backColor);
}
private void makeRuntimeImageList()
{
var imageList22 = new ImageList(this.components);
imageList22.ImageSize = new Size(32, 32);
imageList22.ColorDepth = ColorDepth.Depth8Bit;
foreach (
var label in
tableLayoutPanel.Controls
.Cast<Control>()
.Where(_=>_ is Label)
.OrderBy(_=>int.Parse(_.Name.Replace("label", string.Empty))))
{
Bitmap bitmap = new Bitmap(label.Width, label.Height);
label.DrawToBitmap(bitmap, label.ClientRectangle);
imageList22.Images.Add(bitmap);
#if DEBUG
bitmap.Save(Path.Combine(_imgFolder, $"{label.Name}.{ImageFormat.Bmp}"), ImageFormat.Bmp);
#endif
}
this.treeView.StateImageList = imageList22;
}
#if DEBUG
readonly string _imgFolder;
#endif
PrivateFontCollection privateFontCollection = new PrivateFontCollection();
}
1条答案
按热度按时间3xiyfsfu1#
如果要使用
TreeView.StateImageList
而不是TreeView.ImageList
,则需要具有/create 16x16图像。将ImageSize
属性的大小设置为更大或更小的大小只会输出模糊、扭曲的重叠像素图像。因为使用TreeView.StateImageList
时,非16x16图像将调整大小以适应分配的空间,复选框的边界,因为TreeView.StateImageList
的通常用途是使用列表的第一(未选中)和第二(选中)图像来指示TreeView
的节点选中状态,其中CheckBoxes
属性被设置为true
。从文件上看
默认情况下,TreeView中显示的状态图像为16 x 16像素。设置StateImageList的ImageSize属性不会影响图像的显示方式。但是,当app.config文件包含以下项时,将根据系统DPI设置调整状态图像的大小:
...以及
当TreeView的CheckBoxes属性设置为true并设置了StateImageList属性时,TreeView中包含的每个TreeNode将显示StateImageList中的第一个和第二个图像,以分别指示未选中或选中状态。
考虑到这一点,将字体字形转换为图像将产生可接受的质量。请确保选择一个适当的字体大小,以锐化字形的细节。
下面是一个简单的helper类,用于将一些
Segoe MDL2 Assets
字体字形转换为图像。......以及实施。
...结果