next to explain I wrote a custom textbox, first of all talk about writing this control encountered several difficulties: First, the associated input method; Second, draw strings and focus lines
casually on the first two renderings it:
following three classes derived from certain skilled network, do not remember the name, used to use, the code looked at some places no comments to add a comment.
/// <summary>
/// 提供Unmanaged方法处理Windows Message并接收输入法的输入信号。
/// </summary>
public class ImeWinMessageHandler
{
private Control _tarForm = null;
private IntPtr _tarHandle = IntPtr.Zero;
private IntPtr _hIMC = IntPtr.Zero;
/// <summary>
/// 取得一个值。这个值会指示哪一个辅助按键(Modifier Key)(Shift、Ctrl和Alt)处于按下的状态。
/// </summary>
public static Keys ModifierKeys
{
get
{
Keys m_Result = Keys.None;
if (NativeMethods.GetKeyState(0x10) < 0)
m_Result |= Keys.Shift;
if (NativeMethods.GetKeyState(0x11) < 0)
m_Result |= Keys.Control;
if (NativeMethods.GetKeyState(0x12) < 0)
m_Result |= Keys.Alt;
return m_Result;
}
}
/// <summary>
/// 初始化OptimistSutdioDll.Win32APIs.ImeWinMessageHandler的执行个体。
/// </summary>
/// <param name="form">用于处理Windows Message的 System.Windows.Forms.Form 执行个体。</param>
public ImeWinMessageHandler(Control form)
{
_tarForm = form;
}
private Boolean _Enabled = false;
/// <summary>
/// 取得或设置Handler是否启用。
/// </summary>
public Boolean Enabled
{
get { return _Enabled; }
set
{
if (Enabled != value)
{
_Enabled = value;
if (value)
{
_tarHandle = _tarForm.Handle;
_hIMC = NativeMethods.ImmGetContext(_tarHandle);
}
else
{
NativeMethods.ImmReleaseContext(_tarHandle, _hIMC);
_tarHandle = IntPtr.Zero;
_hIMC = IntPtr.Zero;
}
}
}
}
/// <summary>
/// 将Windows Message资料送入处理器进行处理。
/// </summary>
/// <param name="m">要处理 System.Windows.Forms.Message。</param>
public void InputMessage(ref Message m)
{
bool m_handled = false;
WndProc(m.HWnd, m.Msg, m.WParam, m.LParam, ref m_handled);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (Enabled)
{
if (msg == NativeContansts.WM_IME_SETCONTEXT && wParam.ToInt32() == 1)
NativeMethods.ImmAssociateContext(_tarHandle, _hIMC);
else if (msg == NativeContansts.WM_CHAR)
{
char m_Reult = (char)(new KeyEventArgs(((Keys)((int)(wParam))) | ImeWinMessageHandler.ModifierKeys).KeyData);
this.OnCharacterInputted(m_Reult);
}
}
return IntPtr.Zero;
}
private void OnCharacterInputted(char c)
{
if (this.CharacterInputted != null)
this.CharacterInputted(this, new CharacterInputtedEventArgs(c));
}
/// <summary>
/// 当Handler收到输入法输入字元进入应用程式时引发此事件。
/// </summary>
public event EventHandler<CharacterInputtedEventArgs> CharacterInputted;
}
/// <summary>
/// 提供 CharacterInputted的事件资料。
/// </summary>
public class CharacterInputtedEventArgs : EventArgs
{
/// <summary>
/// 取得输入法输入的字元。
/// </summary>
public Char Character { get; private set; }
internal CharacterInputtedEventArgs(char c)
{
this.Character = c;
}
}
internal static class NativeMethods
{
/// <summary>
/// 获取当前正在输入的窗口的输入法句柄
/// </summary>
/// <param name="hWnd">要获取输入法的窗口句柄</param>
/// <returns></returns>
[DllImport("Imm32.dll")]
public static extern IntPtr ImmGetContext(IntPtr hWnd);
/// <summary>
/// 将指定的窗口和指定的输入法联系起来
/// </summary>
/// <param name="hWnd">指定的窗口</param>
/// <param name="hIMC">指定的输入法</param>
/// <returns></returns>
[DllImport("Imm32.dll")]
public static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC);
/// <summary>
/// 释放输入法和解锁相关联的内存
/// </summary>
/// <param name="hWnd">指定的有输入法的窗口</param>
/// <param name="hIMC">关联的输入法</param>
/// <returns></returns>
[DllImport("Imm32.dll")]
public static extern Boolean ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);
/// <summary>
/// 指定虚拟键的状态
/// </summary>
/// <param name="keyCode">GetKeyState(VK_SHIFT) > 0 没按下GetKeyState(VK_SHIFT)小于0被按下</param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern short GetKeyState(int keyCode);
}
internal static class NativeContansts
{
public const int WM_IME_SETCONTEXT = 0x0281;
public const int WM_IME_COMPOSITION = 0x010F;
public const int WM_CHAR = 0x0102;
public const int GCS_COMPSTR = 0x0008;
}
these three classes to help us put the input method associated with the control, in which the four API calls I have notes, should not be difficult to understand!
code is basically the comment parts of the Notes, there do not understand that we can reply to you on time!
Looktook control code:
first, how to call input controls associated with the three classes
ImeWinMessageHandler ImeHandler;
public TxtBox()
{
InitializeComponent();
ImeHandler = new ImeWinMessageHandler(this);
ImeHandler.CharacterInputted += new EventHandler<CharacterInputtedEventArgs>(ImeHandler_CharacterInputted);
ImeHandler.Enabled = true;
}
private void ImeHandler_CharacterInputted(object sender, CharacterInputtedEventArgs e)
{
if (e.Character == '\b' && this.Text.Length > 0)
{
if (this.Text != prompt)
{
this.Text = this.Text.Remove(this.Text.Length - 1);
}
if (this.Text.Length == 0)
{ this.Text = prompt; }
}
else
{
if (e.Character != (char)3)//双击会产生3的ASCII码
{
if (this.Text.Length >= maxLength && maxLength != 0)
{
//this.Text = this.Text.Substring(this.Text.Length - 16, 16);
this.Text = this.Text;
}//这里可以设置最多输入多少个字符
else
{ this.Text += e.Character; }
}
}
}
second, set the control's properties
#region property
private int alpha;
[CategoryAttribute("A参数设置"), Description("设置控件的透明度(0-255)!")]
public int Alpha
{
get { return alpha; }
set
{
if (value >= 0 && value <= 255)
{
if (alpha == value) return;
alpha = value;
this.Invalidate();
}
else
{ MessageBox.Show("透明度应该是0到255的整数"); }
}
}
private Color alphaBackColor;
[CategoryAttribute("A参数设置"), Description("设置控件的透明颜色!")]
public Color AlphaBackColor
{
get { return alphaBackColor; }
set {
if (alphaBackColor == value) return;
alphaBackColor = value;
this.Invalidate();
}
}//没用背景色,原因是用背景色会出现运行后一直是一种颜色,没找到原因,故自己自定义颜色属性
private int maxLength;
[CategoryAttribute("A参数设置"), Description("设置控件可输入的最大字符数!")]
public int MaxLength
{
get { return maxLength; }
set {
if (maxLength == value) return;
maxLength = value;
}
}
private Char passwordChar;
[CategoryAttribute("A参数设置"), Description("设置控件密码输入显示字符!")]
public Char PasswordChar
{
get { return passwordChar; }
set {
if (passwordChar == value) return;
passwordChar = value;
}
}
private string prompt;
[CategoryAttribute("A参数设置"), Description("设置控件Text!")]
public string Prompt
{
get
{
return this.prompt;
}
set
{
if (prompt == value) return;
prompt = value;
this.Text = prompt;
this.Invalidate();
}
}
private float cornerRadius;
[CategoryAttribute("A参数设置"), Description("设置控件圆角半径大小!")]
public float CornerRadius
{
get { return cornerRadius; }
set {
if (cornerRadius == value) return;
cornerRadius = value;
this.Invalidate();
}
}
[Browsable(false)]
public new Color BackColor
{
get { return base.BackColor; }
set { base.BackColor = value; }
}
[Browsable(false)]
public new string Text
{
get { return base.Text; }
set { base.Text = value; }
}
#_endregion
third rewrite certain events
protected override void OnClick(EventArgs e)
{
this.Focus();
isFocus = true;
if (this.Text == prompt)
{ this.Text = ""; }
this.Invalidate(validRect);//为了只在矩形内显示文字
base.OnClick(e);
}
protected override void OnCreateControl()
{
Thread threadInvalidate = new Thread(methodInvalidate);
threadInvalidate.IsBackground = true;
threadInvalidate.Start();
base.OnCreateControl();
}
protected override void OnLostFocus(EventArgs e)
{
isFocus = false;
if (this.Text == "")
{ this.Text = prompt; }
this.Invalidate();
base.OnLostFocus(e);
}
private void methodInvalidate()
{
try
{
while (true)
{
if (isFocus)
{
this.Invalidate(validRect);//为了只在矩形内显示文字
if (isTwinkle)
{ isTwinkle = false; }
else
{ isTwinkle = true; }
}
Thread.Sleep(500);//每隔500ms就更新一下isTwinkle的布尔值,画焦点线
}
}
catch
{ }
}
Fourth, rewritten onpaint, focus
protected override void OnPaint(PaintEventArgs e)
{
//---------------显示的区域------------------------
GraphicsPath gp = new GraphicsPath();
if (cornerRadius == 0)
{
//gp.AddArc(new Rectangle(0, 0, this.Height, this.Height), 90.0f, 180.0f);
//gp.AddArc(new Rectangle(this.Width - this.Height, 0, this.Height, this.Height), -90.0f, 180.0f);
//gp.CloseFigure();
gp.AddRectangle(new Rectangle(0,0,this.Width,this.Height));
}
else
{
gp = GetRoundedCorner(cornerRadius, new Rectangle(0, 0, this.Width, this.Height));
}
//-------------------------------------------------
//--------------画笔属性---------------------------
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.PageUnit = GraphicsUnit.Pixel;
//-------------------------------------------------
Brush b = new SolidBrush(Color.FromArgb(alpha, AlphaBackColor));//用指定的透明度和颜色定义brush
Pen p=new Pen(b);//用指定的brush定义画笔
g.FillPath(b,gp);//用指定的brush填出要显示的区域
//SizeF sf = g.MeasureString(this.Text, this.Font);//获取字符串的宽度高度
Size s = TextRenderer.MeasureText(this.Text, this.Font);
string tempText = this.Text;//把文本信息赋值给临时变量,画密码符号时用到并且要获取控件的文本信息用Text属性获取也不会变成了密码符号
//---------------------更改文本信息为密码符号----------------------
if (passwordChar != '\0'&&tempText!=prompt)//\0为空字符 char
{
foreach (Char c in tempText.ToCharArray())
{
tempText = tempText.Replace(c, passwordChar);
}
}
//--------------------------------------------------------------
//------------------画字符串-------------------------------------
if (s.Width > this.Width - cornerRadius*2)//如果字符串宽度大于要显示的矩形区域,那么重新计算画字符串的起始坐标点。
{
g.DrawString(tempText, this.Font, Brushes.Ivory,
new PointF(-(s.Width-(this.Width-cornerRadius/2)),(Convert.ToSingle(this.Height)-this.Font.Height)/2));//
}
else
{
g.DrawString(tempText, this.Font, Brushes.Ivory, new PointF(cornerRadius/2, (Convert.ToSingle(this.Height) - this.Font.Height) / 2));
}
//---------------------------------------------------------------
if (this.Focused && isTwinkle)
{
if (s.Width > this.Width - cornerRadius)//此时只在矩形最右侧画线
{
g.DrawLine(Pens.Ivory, new PointF(this.Width - cornerRadius/2-1, 6), new PointF(this.Width - cornerRadius/2-1, this.Height - 6));
}
else
{
g.DrawLine(Pens.Ivory, new PointF(cornerRadius / 2 + s.Width, 6), new PointF(cornerRadius / 2 + s.Width, this.Height - 6));
}
}
base.OnPaint(e);
}
Summary: When a string which when drawn over a rectangular area, hidden front display just write up the character when using SizeF sf = g.MeasureString (this.Text, this.Font); measuring length Painting Society With the change in length of the string line with the focus of increasing the distance between, Size s = TextRenderer.MeasureText (this.Text, this.Font); such measurements did not find any problems.
code in some places we saw certainly do not feel it necessary to amend the United States or areas for improvement, we hope to raise our common progress.
enclose the total project:
http://my.csdn.net/wll929187348 park because they do not know how to upload resources blog, you want the resource to the inside can be downloaded
没有评论:
发表评论