覆盖 ListBox 的 DrawItem - 未选择的项目不会重绘
这是一个 C# 桌面应用程序。我的 ListBox
的 DrawStyle
属性设置为 OwnerDrawFixed
。
问题:我重写了 DrawItem 以使用不同的字体绘制文本,并且它有效。但是,当我开始在运行时调整表单大小时,所选项目会正确绘制,但其余项目不会重新绘制,导致未选定项目的文本看起来损坏。
这是我的代码:
private void listDevices_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
string textDevice = ((ListBox)sender).Items[e.Index].ToString();
e.Graphics.DrawString(textDevice,
new Font("Ariel", 15, FontStyle.Bold), new SolidBrush(Color.Black),
e.Bounds, StringFormat.GenericDefault);
// Figure out where to draw IP
StringFormat copy = new StringFormat(
StringFormatFlags.NoWrap |
StringFormatFlags.MeasureTrailingSpaces
);
copy.SetMeasurableCharacterRanges(new CharacterRange[] {new CharacterRange(0, textDevice.Length)});
Region[] regions = e.Graphics.MeasureCharacterRanges(
textDevice, new Font("Ariel", 15, FontStyle.Bold), e.Bounds, copy);
int width = (int)(regions[0].GetBounds(e.Graphics).Width);
Rectangle rect = e.Bounds;
rect.X += width;
rect.Width -= width;
// draw IP
e.Graphics.DrawString(" 255.255.255.255",
new Font("Courier New", 10), new SolidBrush(Color.DarkBlue),
rect, copy);
e.DrawFocusRectangle();
}
listDevices.Items.Add("Device001");
listDevices.Items.Add("Device002");
此外,正确绘制的项目(选定的项目)在调整表单大小时闪烁。没什么大不了的,但如果有人知道为什么...... tnx
This is a C# desktop application. The DrawStyle
property of my ListBox
is set to OwnerDrawFixed
.
The problem: I override DrawItem to draw text in different fonts, and it works. But when I start resizing the form at the runtime, the selected item is drawn correctly, but the rest of them are not redrawn, causing text looking corrupt for unselected items.
Here's my code:
private void listDevices_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
string textDevice = ((ListBox)sender).Items[e.Index].ToString();
e.Graphics.DrawString(textDevice,
new Font("Ariel", 15, FontStyle.Bold), new SolidBrush(Color.Black),
e.Bounds, StringFormat.GenericDefault);
// Figure out where to draw IP
StringFormat copy = new StringFormat(
StringFormatFlags.NoWrap |
StringFormatFlags.MeasureTrailingSpaces
);
copy.SetMeasurableCharacterRanges(new CharacterRange[] {new CharacterRange(0, textDevice.Length)});
Region[] regions = e.Graphics.MeasureCharacterRanges(
textDevice, new Font("Ariel", 15, FontStyle.Bold), e.Bounds, copy);
int width = (int)(regions[0].GetBounds(e.Graphics).Width);
Rectangle rect = e.Bounds;
rect.X += width;
rect.Width -= width;
// draw IP
e.Graphics.DrawString(" 255.255.255.255",
new Font("Courier New", 10), new SolidBrush(Color.DarkBlue),
rect, copy);
e.DrawFocusRectangle();
}
listDevices.Items.Add("Device001");
listDevices.Items.Add("Device002");
Also, the item that is drawn correctly (the selected one) is flickering on form resizing. No biggie, but if anyone know why.... tnx
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
将以下代码放入 Resize 事件中:
这应该会导致重新绘制所有内容。
要停止闪烁,您需要双缓冲。
为此,创建一个从 ListBox 派生的新类,并将以下内容放入构造函数中:
或者将其粘贴到代码文件中:
将“Whatever”替换为您的项目使用的命名空间,或者使其更有用。编译后,您应该能够在表单设计器中添加一个 DBListBox。
Put the following code in the Resize event:
This should cause everything to be redrawn.
To stop the flickering, you need double buffering.
To do this, make a new class, derived from ListBox, and put the following in the constructor:
Or just paste this into a code file:
Replace "Whatever" with the namespace your project uses, or make it something more useful. AFter compiling, you should be able to add a DBListBox in the form designer.
我重现了这个问题。代码中有几个错误,字体名称是“Arial”,您不应该调整 rect.Width,您忘记对字体、画笔和区域调用 Dispose()。但他们没有解释这种行为。剪切区域存在问题,导致文本无法正确更新。我不知道这种情况发生在哪里,Graphics 对象状态正常。
Graphics.DrawString() 是一个非常麻烦的方法,你真的应该避免它。所有 Windows 窗体控件(包括 ListBox)都使用 TextRenderer.DrawText()。当我使用它时,这解决了问题。我知道测量比较困难,您可以通过以固定偏移量显示 IP 地址来解决这个问题。看起来也更好,他们会这样排成一列。
它闪烁是因为您使用了 e.DrawBackground()。这会擦除现有文本,您可以在其上重新绘制文本。我不认为双缓冲可以解决这个问题,你必须绘制整个项目,这样你就不必绘制背景。如果您无法获得大字体文本的确切大小,则很棘手,解决方法是首先绘制位图。
I repro the problem. There are several mistakes in the code, the font name is "Arial", you should not adjust rect.Width, you forget to call Dispose() on the fonts, brushes and regions. But they don't explain the behavior. There's something wrong with the clipping area that prevents the text from being properly updated. I don't see where that occurs, the Graphics object state is okay.
Graphics.DrawString() is a very troubled method, you should really avoid it. All Windows Forms controls, including ListBox, use TextRenderer.DrawText(). That solves the problem when I use it. I know measuring is more difficult, you could work around that by displaying the IP address at a fixed offset. Looks better too, they'll line up in a column that way.
It flickers because you use e.DrawBackground(). That erases the existing text, you draw the text right back on it. I don't think double-buffering is going to fix that, you'd have to draw the entire item so you don't have to draw the background. Tricky if you can't get the exact size of the text with the large font, a workaround is to draw into a bitmap first.