// *********************************************************************** // Assembly : HZH_Controls // Created : 08-08-2019 // // *********************************************************************** // // Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com // // // Blog: https://www.cnblogs.com/bfyx // GitHub:https://github.com/kwwwvagaa/NetWinformControl // gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git // // If you use this code, please keep this note. // *********************************************************************** using System; using System.Collections; using System.ComponentModel; using System.Drawing; using System.Data; using System.Windows.Forms; using System.Drawing.Imaging; namespace HZH_Controls.Controls { /// /// Class TextBoxTransparent. /// Implements the /// /// public class TextBoxTransparent : TextBoxEx { #region private variables /// /// My PictureBox /// private uPictureBox myPictureBox; /// /// My up to date /// private bool myUpToDate = false; /// /// My caret up to date /// private bool myCaretUpToDate = false; /// /// My bitmap /// private Bitmap myBitmap; /// /// My alpha bitmap /// private Bitmap myAlphaBitmap; /// /// My font height /// private int myFontHeight = 10; /// /// My timer1 /// private System.Windows.Forms.Timer myTimer1; /// /// My caret state /// private bool myCaretState = true; /// /// My painted first time /// private bool myPaintedFirstTime = false; /// /// My back color /// private Color myBackColor = Color.White; /// /// My back alpha /// private int myBackAlpha = 10; /// /// Required designer variable. /// private System.ComponentModel.Container components = null; #endregion // end private variables #region public methods and overrides /// /// Initializes a new instance of the class. /// public TextBoxTransparent() { // This call is required by the Windows.Forms Form Designer. InitializeComponent(); // TODO: Add any initialization after the InitializeComponent call this.BackColor = myBackColor; this.SetStyle(ControlStyles.UserPaint, false); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); this.SetStyle(ControlStyles.DoubleBuffer, true); myPictureBox = new uPictureBox(); this.Controls.Add(myPictureBox); myPictureBox.Dock = DockStyle.Fill; } /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnResize(EventArgs e) { base.OnResize(e); this.myBitmap = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);//(this.Width,this.Height); this.myAlphaBitmap = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);//(this.Width,this.Height); myUpToDate = false; this.Invalidate(); } //Some of these should be moved to the WndProc later /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnKeyDown(KeyEventArgs e) { base.OnKeyDown(e); myUpToDate = false; this.Invalidate(); } /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnKeyUp(KeyEventArgs e) { base.OnKeyUp(e); myUpToDate = false; this.Invalidate(); } /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnKeyPress(KeyPressEventArgs e) { base.OnKeyPress(e); myUpToDate = false; this.Invalidate(); } /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); this.Invalidate(); } /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnGiveFeedback(GiveFeedbackEventArgs gfbevent) { base.OnGiveFeedback(gfbevent); myUpToDate = false; this.Invalidate(); } /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnMouseLeave(EventArgs e) { //found this code to find the current cursor location //at http://www.syncfusion.com/FAQ/WinForms/FAQ_c50c.asp#q597q Point ptCursor = Cursor.Position; Form f = this.FindForm(); ptCursor = f.PointToClient(ptCursor); if (!this.Bounds.Contains(ptCursor)) base.OnMouseLeave(e); } /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnChangeUICues(UICuesEventArgs e) { base.OnChangeUICues(e); myUpToDate = false; this.Invalidate(); } //-- /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnGotFocus(EventArgs e) { base.OnGotFocus(e); myCaretUpToDate = false; myUpToDate = false; this.Invalidate(); myTimer1 = new System.Windows.Forms.Timer(this.components); myTimer1.Interval = (int)win32.GetCaretBlinkTime(); // usually around 500; myTimer1.Tick += new EventHandler(myTimer1_Tick); myTimer1.Enabled = true; } /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnLostFocus(EventArgs e) { base.OnLostFocus(e); myCaretUpToDate = false; myUpToDate = false; this.Invalidate(); myTimer1.Dispose(); } //-- /// /// 引发 事件。 /// /// 包含事件数据的 。 protected override void OnFontChanged(EventArgs e) { if (this.myPaintedFirstTime) this.SetStyle(ControlStyles.UserPaint, false); base.OnFontChanged(e); if (this.myPaintedFirstTime) this.SetStyle(ControlStyles.UserPaint, true); myFontHeight = GetFontHeight(); myUpToDate = false; this.Invalidate(); } /// /// Handles the event. /// /// The instance containing the event data. protected override void OnTextChanged(EventArgs e) { base.OnTextChanged(e); myUpToDate = false; this.Invalidate(); } /// /// 处理 Windows 消息。 /// /// 一个 Windows 消息对象。 protected override void WndProc(ref Message m) { base.WndProc(ref m); // need to rewrite as a big switch if (m.Msg == win32.WM_PAINT) { myPaintedFirstTime = true; if (!myUpToDate || !myCaretUpToDate) GetBitmaps(); myUpToDate = true; myCaretUpToDate = true; if (myPictureBox.Image != null) myPictureBox.Image.Dispose(); if (string.IsNullOrEmpty(this.Text) && !string.IsNullOrEmpty(this.PromptText)) { Bitmap bit = (Bitmap)myAlphaBitmap.Clone(); Graphics g = Graphics.FromImage(bit); SizeF sizet1 = g.MeasureString(this.PromptText, this.PromptFont); g.DrawString(this.PromptText, this.PromptFont, new SolidBrush(PromptColor), new PointF(3, (bit.Height - sizet1.Height) / 2)); g.Dispose(); myPictureBox.Image = bit; } else { myPictureBox.Image = (Image)myAlphaBitmap.Clone(); } } else if (m.Msg == win32.WM_HSCROLL || m.Msg == win32.WM_VSCROLL) { myUpToDate = false; this.Invalidate(); } else if (m.Msg == win32.WM_LBUTTONDOWN || m.Msg == win32.WM_RBUTTONDOWN || m.Msg == win32.WM_LBUTTONDBLCLK // || m.Msg == win32.WM_MOUSELEAVE ///**** ) { myUpToDate = false; this.Invalidate(); } else if (m.Msg == win32.WM_MOUSEMOVE) { if (m.WParam.ToInt32() != 0) //shift key or other buttons { myUpToDate = false; this.Invalidate(); } } if (m.Msg == 15 || m.Msg == 7 || m.Msg == 8) { base.OnPaint(null); } } /// /// Clean up any resources being used. /// /// 为 true 则释放托管资源和非托管资源;为 false 则仅释放非托管资源。 protected override void Dispose(bool disposing) { if (disposing) { //this.BackColor = Color.Pink; if (components != null) { components.Dispose(); } } base.Dispose(disposing); } #endregion //end public method and overrides #region public property overrides /// /// 获取或设置文本框控件的边框类型。 /// /// The border style. /// /// /// /// /// /// public new BorderStyle BorderStyle { get { return base.BorderStyle; } set { if (this.myPaintedFirstTime) this.SetStyle(ControlStyles.UserPaint, false); base.BorderStyle = value; if (this.myPaintedFirstTime) this.SetStyle(ControlStyles.UserPaint, true); this.myBitmap = null; this.myAlphaBitmap = null; myUpToDate = false; this.Invalidate(); } } /// /// 获取或设置控件的背景色。 /// /// The color of the back. /// /// /// public new Color BackColor { get { return Color.FromArgb(base.BackColor.R, base.BackColor.G, base.BackColor.B); } set { myBackColor = value; base.BackColor = value; myUpToDate = false; } } /// /// 获取或设置一个值,该值指示此控件是否为多行 控件。 /// /// true if multiline; otherwise, false. /// /// /// /// /// /// public override bool Multiline { get { return base.Multiline; } set { if (this.myPaintedFirstTime) this.SetStyle(ControlStyles.UserPaint, false); base.Multiline = value; if (this.myPaintedFirstTime) this.SetStyle(ControlStyles.UserPaint, true); this.myBitmap = null; this.myAlphaBitmap = null; myUpToDate = false; this.Invalidate(); } } #endregion //end public property overrides #region private functions and classes /// /// Gets the height of the font. /// /// System.Int32. private int GetFontHeight() { Graphics g = this.CreateGraphics(); SizeF sf_font = g.MeasureString("X", this.Font); g.Dispose(); return (int)sf_font.Height; } /// /// Gets the bitmaps. /// private void GetBitmaps() { if (myBitmap == null || myAlphaBitmap == null || myBitmap.Width != Width || myBitmap.Height != Height || myAlphaBitmap.Width != Width || myAlphaBitmap.Height != Height) { myBitmap = null; myAlphaBitmap = null; } if (myBitmap == null) { myBitmap = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);//(Width,Height); myUpToDate = false; } if (!myUpToDate) { //Capture the TextBox control window this.SetStyle(ControlStyles.UserPaint, false); win32.CaptureWindow(this, ref myBitmap); this.SetStyle(ControlStyles.UserPaint, true); this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); this.BackColor = Color.FromArgb(myBackAlpha, myBackColor); } //-- Rectangle r2 = new Rectangle(0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height); ImageAttributes tempImageAttr = new ImageAttributes(); //Found the color map code in the MS Help ColorMap[] tempColorMap = new ColorMap[1]; tempColorMap[0] = new ColorMap(); tempColorMap[0].OldColor = Color.FromArgb(255, myBackColor); tempColorMap[0].NewColor = Color.FromArgb(myBackAlpha, myBackColor); tempImageAttr.SetRemapTable(tempColorMap); if (myAlphaBitmap != null) myAlphaBitmap.Dispose(); myAlphaBitmap = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);//(Width,Height); Graphics tempGraphics1 = Graphics.FromImage(myAlphaBitmap); tempGraphics1.DrawImage(myBitmap, r2, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height, GraphicsUnit.Pixel, tempImageAttr); tempGraphics1.Dispose(); //---- if (this.Focused && (this.SelectionLength == 0)) { Graphics tempGraphics2 = Graphics.FromImage(myAlphaBitmap); if (myCaretState) { //Draw the caret Point caret = this.findCaret(); Pen p = new Pen(this.ForeColor, 3); tempGraphics2.DrawLine(p, caret.X + 2, caret.Y + 0, caret.X + 2, caret.Y + myFontHeight); tempGraphics2.Dispose(); } } } /// /// Finds the caret. /// /// Point. private Point findCaret() { /* Find the caret translated from code at * http://www.vb-helper.com/howto_track_textbox_caret.html * * and * * http://www.microbion.co.uk/developers/csharp/textpos2.htm * * Changed to EM_POSFROMCHAR * * This code still needs to be cleaned up and debugged * */ Point pointCaret = new Point(0); int i_char_loc = this.SelectionStart; IntPtr pi_char_loc = new IntPtr(i_char_loc); int i_point = win32.SendMessage(this.Handle, win32.EM_POSFROMCHAR, pi_char_loc, IntPtr.Zero); pointCaret = new Point(i_point); if (i_char_loc == 0) { pointCaret = new Point(0); } else if (i_char_loc >= this.Text.Length) { pi_char_loc = new IntPtr(i_char_loc - 1); i_point = win32.SendMessage(this.Handle, win32.EM_POSFROMCHAR, pi_char_loc, IntPtr.Zero); pointCaret = new Point(i_point); Graphics g = this.CreateGraphics(); String t1 = this.Text.Substring(this.Text.Length - 1, 1) + "X"; SizeF sizet1 = g.MeasureString(t1, this.Font); SizeF sizex = g.MeasureString("X", this.Font); g.Dispose(); int xoffset = (int)(sizet1.Width - sizex.Width); pointCaret.X = pointCaret.X + xoffset; if (i_char_loc == this.Text.Length) { String slast = this.Text.Substring(Text.Length - 1, 1); if (slast == "\n") { pointCaret.X = 1; pointCaret.Y = pointCaret.Y + myFontHeight; } } } return pointCaret; } /// /// Handles the Tick event of the myTimer1 control. /// /// The source of the event. /// The instance containing the event data. private void myTimer1_Tick(object sender, EventArgs e) { //Timer used to turn caret on and off for focused control myCaretState = !myCaretState; myCaretUpToDate = false; this.Invalidate(); } /// /// Class uPictureBox. /// Implements the /// /// private class uPictureBox : PictureBox { /// /// Initializes a new instance of the class. /// public uPictureBox() { this.SetStyle(ControlStyles.Selectable, false); this.SetStyle(ControlStyles.UserPaint, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); this.SetStyle(ControlStyles.DoubleBuffer, true); this.Cursor = null; this.Enabled = true; this.SizeMode = PictureBoxSizeMode.Normal; } //uPictureBox /// /// 处理 Windows 消息。 /// /// 要处理的 Windows。 protected override void WndProc(ref Message m) { if (m.Msg == win32.WM_LBUTTONDOWN || m.Msg == win32.WM_RBUTTONDOWN || m.Msg == win32.WM_LBUTTONDBLCLK || m.Msg == win32.WM_MOUSELEAVE || m.Msg == win32.WM_MOUSEMOVE) { //Send the above messages back to the parent control win32.PostMessage(this.Parent.Handle, (uint)m.Msg, m.WParam, m.LParam); } else if (m.Msg == win32.WM_LBUTTONUP) { //?? for selects and such this.Parent.Invalidate(); } base.WndProc(ref m); } } // End uPictureBox Class #endregion // end private functions and classes #region Component Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { components = new System.ComponentModel.Container(); } #endregion #region New Public Properties /// /// Gets or sets the back alpha. /// /// The back alpha. [ Category("Appearance"), Description("The alpha value used to blend the control's background. Valid values are 0 through 255."), Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible) ] public int BackAlpha { get { return myBackAlpha; } set { int v = value; if (v > 255) v = 255; myBackAlpha = v; myUpToDate = false; Invalidate(); } } #endregion } // End AlphaTextBox Class }