覆盖 ListBox 的 DrawItem - 未选择的项目不会重绘

发布于 2024-09-10 12:06:31 字数 1467 浏览 2 评论 0原文

这是一个 C# 桌面应用程序。我的 ListBoxDrawStyle 属性设置为 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

像极了他 2024-09-17 12:06:31

将以下代码放入 Resize 事件中:

private void listDevices_Resize(object sender, EventArgs e) {
    listDevices.Invalidate();
}

这应该会导致重新绘制所有内容。

要停止闪烁,您需要双缓冲。

为此,创建一个从 ListBox 派生的新类,并将以下内容放入构造函数中:

this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

或者将其粘贴到代码文件中:

using System.Windows.Forms;

namespace Whatever {
    public class DBListBox : ListBox {
        public DBListBox(): base() {
            this.DoubleBuffered = true;
            // OR
            // this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }
    }
}

将“Whatever”替换为您的项目使用的命名空间,或者使其更有用。编译后,您应该能够在表单设计器中添加一个 DBListBox。

Put the following code in the Resize event:

private void listDevices_Resize(object sender, EventArgs e) {
    listDevices.Invalidate();
}

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:

this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

Or just paste this into a code file:

using System.Windows.Forms;

namespace Whatever {
    public class DBListBox : ListBox {
        public DBListBox(): base() {
            this.DoubleBuffered = true;
            // OR
            // this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }
    }
}

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.

鲜肉鲜肉永远不皱 2024-09-17 12:06:31

我重现了这个问题。代码中有几个错误,字体名称是“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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文