Combobox文本对齐中心

时间:2018-04-13 13:19:56

标签: c# winforms combobox .net-1.1

我在.net framework 1.1上创建了自定义组合框,我可以自定义绘制下拉项目,但我无法在中左设置或绘制组合框文本,组合框文本总是渲染到左上角,但我需要文本应该渲染在左边中间。

[ToolboxBitmap(typeof(ComboBox))]
public class MenComboBox :ComboBox
{
    private Image _image = Image.FromFile("Expand.png");
    public MenComboBox()
    {
        this.DrawMode = DrawMode.OwnerDrawFixed;
        this.BackColor = Color.White;
        this.ItemHeight = 18;
        this.Font = new Font("Arial",12f,FontStyle.Regular);
    }       
    protected override void OnDrawItem(DrawItemEventArgs e)
    {

            if (!DesignMode)
            {
                if (e.Index > -1)
                {
                    int textHeight = (int)e.Graphics.MeasureString(this.Items[e.Index].ToString(), e.Font).Height;
                    Point textPos = new Point(e.Bounds.X + 4, e.Bounds.Y + ((this.ItemHeight - textHeight) / 2));
                    if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
                    {
                        e.Graphics.FillRectangle(Brushes.Blue, e.Bounds);
                        e.Graphics.DrawString(this.Items[e.Index].ToString(),e.Font,Brushes.White,textPos);
                    }
                    else
                    {
                        e.Graphics.FillRectangle(Brushes.White, e.Bounds);
                        e.Graphics.DrawString(this.Items[e.Index].ToString(),e.Font,Brushes.Black,textPos);
                    }
                }
            }

    }
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == 0x000F)
        {
            using (Graphics g = this.CreateGraphics())
            {
                g.FillRectangle(new SolidBrush(BackColor), this.ClientRectangle);
                g.DrawRectangle(Pens.Blue, new Rectangle(this.ClientRectangle.X, this.ClientRectangle.Y, this.ClientRectangle.Width - 1, this.ClientRectangle.Height - 1));
                Rectangle rect = new Rectangle(this.Width - 15, 3, 12, this.Height - 6);
                g.FillRectangle(new SolidBrush(BackColor), rect);
                g.DrawImage(this._image, this.Width - 16, (this.Height - 8) / 2);
                g.Dispose();
            }
        }
    }   
}

my Custom Combobox Appearance

2 个答案:

答案 0 :(得分:2)

在所有者抽奖ComboBox中,无论Edit的高度如何,控件的ItemHeight部分的文字都将始终显示在左上角。

要将Edit部分垂直放置在中间位置,您可以使用Edit找到GetComboBoxInfo元素,然后使用SetWindowPos设置新位置以使其垂直竖立中间的ComboBox

当控件大小更改时,您需要重新定位它。您还需要使用颜色填充ComboBox的背景。

enter image description here

以下是我使用的代码:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class MyComboBox : ComboBox
{
    public MyComboBox()
    {
        SetStyle(ControlStyles.ResizeRedraw, true);
        DrawMode = DrawMode.OwnerDrawFixed;
        ItemHeight = 40;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
        public int Width { get { return Right - Left; } }
        public int Height { get { return Bottom - Top; } }
    }

    private const int SWP_NOSIZE = 0x0001;
    private const int SWP_NOZORDER = 0x0004;
    private const int SWP_SHOWWINDOW = 0x0040;
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, 
        int X, int Y, int cx, int cy, int uFlags);

    [DllImport("user32.dll")]
    public static extern bool GetComboBoxInfo(IntPtr hWnd, ref COMBOBOXINFO pcbi);

    [StructLayout(LayoutKind.Sequential)]
    public struct COMBOBOXINFO
    {
        public int cbSize;
        public RECT rcItem;
        public RECT rcButton;
        public int stateButton;
        public IntPtr hwndCombo;
        public IntPtr hwndEdit;
        public IntPtr hwndList;
    }
    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);
        SetupEdit();
        Invalidate();
    }
    private int buttonWidth = SystemInformation.HorizontalScrollBarArrowWidth;
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0xF)
        {
            using (var g = this.CreateGraphics())
            {
                var r = new Rectangle(2, 2,
                    ClientRectangle.Width - buttonWidth - 2,
                    ClientRectangle.Height - 4);
                g.FillRectangle(Brushes.White, r);
            }
        }
        base.WndProc(ref m);
    }
    protected override void OnVisibleChanged(EventArgs e)
    {
        base.OnVisibleChanged(e);
        SetupEdit();
    }
    private void SetupEdit()
    {
        var info = new COMBOBOXINFO();
        info.cbSize = Marshal.SizeOf(info);
        GetComboBoxInfo(this.Handle, ref info);
        SetWindowPos(info.hwndEdit, IntPtr.Zero, 3,
            (this.Height - Font.Height) / 2,
            ClientRectangle.Width - buttonWidth - 3,
            ClientRectangle.Height - Font.Height - 4,
            SWP_NOZORDER);
    }
    protected override void OnDrawItem(DrawItemEventArgs e)
    {
        base.OnDrawItem(e);
        e.DrawBackground();
        var txt = "";
        if (e.Index >= 0)
            txt = GetItemText(Items[e.Index]);
        TextRenderer.DrawText(e.Graphics, txt, Font, e.Bounds, 
            ForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
    }
}

enter image description here

答案 1 :(得分:1)

好的,下面的代码没有回答关于Text部分的实际问题;汉斯像往常一样做对了。

我保留了答案,因为我认为它比OP代码做了一些更好的事情。

enter image description here

    if (!DesignMode)
    {
        if (e.Index > -1)
        {
           using (StringFormat fmt = new StringFormat() 
             { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center })
           {

            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            {
                e.Graphics.FillRectangle(SystemBrushes.MenuHighlight, e.Bounds);
                e.Graphics.DrawString(comboBox1.Items[e.Index].ToString(), 
                                        e.Font,SystemBrushes.HighlightText, e.Bounds, fmt);
            }
            else
            {
                e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
                e.Graphics.DrawString(comboBox1.Items[e.Index].ToString(), 
                                        e.Font, SystemBrushes.MenuText,e.Bounds, fmt);
            }
         }
      }
    }

不是计算居中位置,而是使用带有目标矩形的DrawString重载,并在两个方向上添加StringFormat。 {。1}}自.Net 1.1以来就可用,而且确实是StringFormat,所以我们应该创建每个IDisposable子句,最好用using子句。

请注意,对于绘图控件,鼓励使用TextRenderer,但仅使用.Net 2.0。

另请注意,我将Brushes替换为SystemBrushes ..

另外:我的ComboBox不会将文本放在文本部分左上角但左中角。也许旧的.Net1.1控件是罪魁祸首?