我在.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();
}
}
}
}
在所有者图纸ComboBox
中,无论Edit
的高度如何,控件的ItemHeight
部分的文本将始终显示在左上方。
[将Edit
部分垂直放置在中间,您可以使用Edit
找到GetComboBoxInfo
元素,然后使用SetWindowPos
设置一个新位置使其垂直站立在ComboBox
的中间。
当控件大小更改时,您需要重新放置它。另外,您需要用颜色填充ComboBox
的背景。
这是我使用的代码:
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);
}
}
好的,下面的代码不能回答有关文本部分的实际问题;汉斯照常做对了。
我保留答案,因为我认为它比OP代码做得更好。.>
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
。从.Net 1.1开始,StringFormat
可用,并且实际上是IDisposable
,因此最好将每个创建的内容都放在using
子句中。.>注意,对于图形控件,鼓励使用
TextRenderer
,但仅随.Net 2.0提供。
还请注意,我用Brushes
代替了SystemBrushes
..
[另外:我的ComboBox不在其文本部分的左上角,而是在左中角放置文本。也许旧的.Net1.1控件是元凶?