65.9K
CodeProject 正在变化。 阅读更多。
Home

Image ComboBox 控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.84/5 (37投票s)

2005年6月14日

CDDL

4分钟阅读

viewsIcon

372087

downloadIcon

17574

这是一个扩展的、属主绘制的 ComboBox,增加了在下拉列表框和编辑(文本)框中显示图像的支持。

引言

ImageComboBox 是标准 Windows ComboBox 控件的扩展,增加了与项目文本一起显示图标或图像的支持。如果您查看 Windows 界面,可以看到 Windows 资源管理器、Internet Explorer、文件打开/保存/打印对话框,它们都使用可以显示图标和不同级别缩进的 combobox。

标准的 combobox 在 Normal DrawMode 中不支持显示图形图像。但当它被设置为 OwnerDrawn 时,它可以显示图标或图像。但仍然缺少一些东西。图像可以在列表部分绘制,但当您选择一个项目时,它的图像不会显示在文本框中,除非下拉样式设置为 DropDownList。当下拉样式为 DropDownList 时,combobox 不支持编辑。可编辑模式为 SimpleDropDown。所以我想让图像在所有三种 DropDownStyle 的文本框中绘制。这个 ImageComboBox 能够在列表部分和文本部分绘制带有相应图像的项目,支持所有三种 DropDownStyle

除此之外,这个 ImageComboBox 还支持为单个项目进行多级缩进。缩进单个项目通过分组项目和显示层级关系来增强视觉表示。当 DrawMode 设置为 OwnerDrawVariable 时,单个项目可以拥有自己的字体和大小。因此,combobox 中的一个项目有几个属性,所有这些属性都需要在设计时或运行时动态地进行操作。因此,项目不再是简单的字符串,而是独立的 ImageComboBoxItem 对象。所以 ItemsImageComboBoxItem 对象的集合。

ImageComboBoxItem

ImageComboBoxItem 具有以下属性

  • Image

    与 combobox 项目一起显示的图像。Image 属性公开一个下拉窗口,显示来自 ImageList 的图像。

  • 字体

    DrawMode 设置为 OwnerDrawVariable 时,用于 combobox 项目文本的字体。Font 属性公开一个字体编辑器来选择所需的字体。

  • IndentLevel

    项目所需的缩进级别。ImageComboBox 支持多达四个级别的缩进,即 0-5。

  • 文本

    combobox 项目的文本。

ImageComboBox 还需要两个新属性,一个 ImageList 来保存用户可以从中选择与项目关联的图像的图标/图像,以及一个 Indent 属性让用户指定缩进量。Items 属性已更改,以便项目类型为 ImageComboBoxItemCollection。向用户提供了一个集合编辑器,以便可以在设计时添加/删除/修改单个项目的属性。

ImageComboBox

以下属性是新添加到 ImageComboBox 中的

  • ImageList

    保存与项目一起绘制的图像集合。

  • Items (已更改的属性)

    ImageComboBox 的项目。项目类型为 ImageComboBoxItemCollectionItems 属性公开一个新的集合编辑器来添加/删除/编辑 combobox 项目。

  • Indent

    所需的缩进量(以像素为单位)。

如何在 ComboBox 的编辑部分绘制图像?

在 combobox 下拉部分显示图像相对直接,可以通过将 combobox 设置为属主绘制并为每个项目绘制图像来实现。另一方面,当 DropDownStyle 设置为 DropDownSimple 时,在 combobox 的编辑部分显示图像是一项困难的任务。它需要获取编辑框的句柄,绘制图像,并为编辑框设置边距,以便显示的文本能够正确缩进。

老旧的 Windows API 调用可以解决这个问题。

  1. 获取编辑框的句柄。ComboBoxTextBoxListBox 的组合。GetComboBoxInfo(IntPtr hwndCombo, ref ComboBoxInfo info) 方法检索 TextBoxListBox 的句柄和坐标。
          [DllImport("user32")] 
    
          private static extern bool GetComboBoxInfo(IntPtr hwndCombo, 
                                               ref ComboBoxInfo info); 
    
          [StructLayout(LayoutKind.Sequential)] 
    
          private struct ComboBoxInfo 
          {
                public int cbSize;
                public RECT rcItem;
                public RECT rcButton;
                public IntPtr stateButton;
                public IntPtr hwndCombo;
                public IntPtr hwndEdit;
                public IntPtr hwndList; 
          }
  2. TextBox 设置边距。
          [DllImport("user32", CharSet=CharSet.Auto)] 
    
          private extern static int SendMessage(IntPtr hwnd, 
                  int wMsg, int wParam, int lParam);
          private const int EC_LEFTMARGIN = 0x1; 
          private const int EC_RIGHTMARGIN = 0x2; 
    
          private const int EM_SETMARGINS = 0xD3;

    使用 SendMessage 方法设置边距。combobox 支持从左到右或从右到左显示项目。根据此设置,需要设置边距。RightMargin 需要在高字中,所以乘以 65536。

     SendMessage(ComboBox.Handle, EM_SETMARGINS, 
                       EC_RIGHTMARGIN, Margin * 65536);
     SendMessage(ComboBox.Handle, EM_SETMARGINS, EC_LEFTMARGIN, Margin);
  3. 将图像绘制到文本框上。

    要实现这一点,需要一个派生自 NativeWindow 的类。我们将 TextBox 的句柄分配给这个类,以便我们可以访问发送到 TextBox 的消息流。然后重写 WndProc 方法并手动重绘 TextBox

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_PAINT:
            base.WndProc(ref m);
            DrawImage();
            break;
        
        case WM_LBUTTONDOWN:
            base.WndProc(ref m);
            DrawImage();
            break;
        case WM_KEYDOWN:
            base.WndProc(ref m);
            DrawImage();
            break;
        case WM_KEYUP:
            base.WndProc(ref m);
            DrawImage();
            break;
        case WM_CHAR:
            base.WndProc(ref m);
            DrawImage();
            break;
        case WM_GETTEXTLENGTH:
            base.WndProc(ref m);
            DrawImage();
            break;
        case WM_GETTEXT:
            base.WndProc(ref m);
            DrawImage();
            break;
        default:
            base.WndProc(ref m);
            break;
    }
}

public void DrawImage()
{
    if((CurrentIcon!=null))
    {    
        // Gets a GDI drawing surface from the textbox.
        gfx = Graphics.FromHwnd (this.Handle);
        bool rightToLeft = false;
        if(Owner.RightToLeft == RightToLeft.Inherit)
        {
            if(Owner.Parent.RightToLeft == RightToLeft.Yes)
                rightToLeft =  true;

        }
        if(Owner.RightToLeft == RightToLeft.Yes || rightToLeft)
        {
            gfx.DrawImage(CurrentIcon, 
              gfx.VisibleClipBounds.Width - CurrentIcon.Width,0);
        }
        else if(Owner.RightToLeft == RightToLeft.No || rightToLeft)
            gfx.DrawImage(CurrentIcon,0,0);
        
        gfx.Flush();
        gfx.Dispose();
    }
}

使用 ImageComboBox

ImageComoBox.dllbin\Release 目录复制到您的项目目录。打开解决方案资源管理器,右键单击项目名称,然后选择“添加引用”。单击“浏览”按钮,找到 ImageComoBox.dll 并选择它。要将控件显示在工具箱中,请右键单击工具箱,然后单击“添加/删除项”。在“自定义工具箱”窗口中,选择 ImageComoBox.dll

© . All rights reserved.