文本框自定义onPaint

问题描述:

我正在尝试为我的文本框创建自定义的onPaint,它正在工作... it is working但是,当我尝试输入内容时,a textbox is rendering above the textbox文本框自定义onPaint

这是我的构造函数:

public TextBox() 
{ 
    Font = new Font("Segoe UI", 11F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0))); 
    BackColor = Color.White; 
    BorderColor = Color.Gray; 
    BorderStyle = BorderStyle.None; 
    SetStyle(ControlStyles.UserPaint, true); 
} 

而且OnPaint中:

protected override void OnPaint(PaintEventArgs e) 
{ 
    Graphics g = e.Graphics; 
    g.FillRectangle(backgroundBrush, 0, 0, this.Width, this.Height); 

    SizeF fontSize = g.MeasureString(Text, Font); 
    g.DrawString(Text, Font, new SolidBrush(ForeColor), new PointF(5, 5), cFormat); 

    g.DrawRectangle(borderPen, borderPen.Width/2, borderPen.Width/2, 
        this.Width - borderPen.Width, this.Height - borderPen.Width); 
} 
+1

TextBox控件不使用Paint事件,所以你看到的控件的版本和你自己的。 – LarsTech

+0

对,所以我需要做我自己的控制?还是有另一种方式? – gerard

+0

如果你所要做的只是制作一个边框,试着把TextBox放在一个带有2像素填充的Panel中,并将TextBox设置为Dock.Fill和MultiLine = true。否则,目前尚不清楚*为什么*您正在尝试绘制TextBox。 – LarsTech

如果你只是想自定义TextBox一些自定义的边框(宽度和颜色),我有2个解决方案,在这里:

  1. 使用ControlPaint,这将让你博士AW边境的一些样式和颜色,但不能用Brush吸引更多的不同(如HatchBrush可以做):

    public class CustomTextBox : TextBox 
    { 
        [DllImport("user32")] 
        private static extern IntPtr GetWindowDC(IntPtr hwnd); 
        struct RECT 
        { 
         public int left, top, right, bottom; 
        } 
        struct NCCALSIZE_PARAMS 
        { 
         public RECT newWindow; 
         public RECT oldWindow; 
         public RECT clientWindow; 
         IntPtr windowPos; 
        }    
        float clientPadding = 2; 
        float actualBorderWidth = 4; 
        Color borderColor = Color.Red;  
        protected override void WndProc(ref Message m) 
        { 
         //We have to change the clientsize to make room for borders 
         //if not, the border is limited in how thick it is. 
         if (m.Msg == 0x83) //WM_NCCALCSIZE 
         { 
         if (m.WParam == IntPtr.Zero) 
         { 
          RECT rect = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT)); 
          rect.left += clientPadding; 
          rect.right -= clientPadding; 
          rect.top += clientPadding; 
          rect.bottom -= clientPadding; 
          Marshal.StructureToPtr(rect, m.LParam, false); 
         } 
         else 
         { 
          NCCALSIZE_PARAMS rects = (NCCALSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(NCCALSIZE_PARAMS)); 
          rects.newWindow.left += clientPadding; 
          rects.newWindow.right -= clientPadding; 
          rects.newWindow.top += clientPadding; 
          rects.newWindow.bottom -= clientPadding; 
          Marshal.StructureToPtr(rects, m.LParam, false); 
         } 
         } 
         if (m.Msg == 0x85) //WM_NCPAINT  
         {   
         IntPtr wDC = GetWindowDC(Handle); 
         using(Graphics g = Graphics.FromHdc(wDC)){              
          ControlPaint.DrawBorder(g, new Rectangle(0,0,Size.Width, Size.Height), borderColor, actualBorderWidth, ButtonBorderStyle.Solid, 
         borderColor, actualBorderWidth, ButtonBorderStyle.Solid, borderColor, actualBorderWidth, ButtonBorderStyle.Solid, 
         borderColor, actualBorderWidth, ButtonBorderStyle.Solid); 
         } 
         return;   
         } 
         base.WndProc(ref m); 
        } 
    } 
    

    这里是文本框快照:使用FillRegion

  2. 方法Graphics用各种Brush来绘制边框,这里我用HatchBrush

    public class CustomTextBox : TextBox 
    { 
        [DllImport("user32")] 
        private static extern IntPtr GetWindowDC(IntPtr hwnd); 
        struct RECT 
        { 
        public int left, top, right, bottom; 
        } 
        struct NCCALSIZE_PARAMS 
        { 
        public RECT newWindow; 
        public RECT oldWindow; 
        public RECT clientWindow; 
        IntPtr windowPos; 
        }   
        int clientPadding = 2; 
        int actualBorderWidth = 4;  
        protected override void WndProc(ref Message m) 
        { 
         //We have to change the clientsize to make room for borders 
         //if not, the border is limited in how thick it is. 
         if (m.Msg == 0x83) //WM_NCCALCSIZE 
         { 
         if (m.WParam == IntPtr.Zero) 
         { 
          RECT rect = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT)); 
          rect.left += clientPadding; 
          rect.right -= clientPadding; 
          rect.top += clientPadding; 
          rect.bottom -= clientPadding; 
          Marshal.StructureToPtr(rect, m.LParam, false); 
         } 
         else 
         { 
          NCCALSIZE_PARAMS rects = (NCCALSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(NCCALSIZE_PARAMS)); 
          rects.newWindow.left += clientPadding; 
          rects.newWindow.right -= clientPadding; 
          rects.newWindow.top += clientPadding; 
          rects.newWindow.bottom -= clientPadding; 
          Marshal.StructureToPtr(rects, m.LParam, false); 
         } 
         } 
         if (m.Msg == 0x85) //WM_NCPAINT 
         {     
         IntPtr wDC = GetWindowDC(Handle); 
         using(Graphics g = Graphics.FromHdc(wDC)){             
          Rectangle rect = new Rectangle(0,0,Width,Height); 
          Rectangle inner = new Rectangle(0, 0, Width, Height); 
          inner.Offset(actualBorderWidth + 2, actualBorderWidth + 2); 
          inner.Width -= 2 * actualBorderWidth + 4; 
          inner.Height -= 2 * actualBorderWidth + 4; 
          Region r = new Region(rect); 
          r.Xor(inner); 
          using (System.Drawing.Drawing2D.HatchBrush brush = new System.Drawing.Drawing2D.HatchBrush(System.Drawing.Drawing2D.HatchStyle.SmallCheckerBoard, Color.Green, Color.Red)) 
          {      
          g.FillRegion(brush, r); 
          } 
         } 
         return; 
         } 
         base.WndProc(ref m); 
        } 
    } 
    

    这里是文本框快照:
    with scrollbars

+0

我试过了代码,但它不起作用:System.ArgumentException是未处理的,无效的参数。在第62行(g.ReleaseHdc(wDC))。它也说它不能将float转换为int,所以我将actualBorderWidth更改为int。 – gerard

+0

@gerard哪些代码不起作用?第一个还是第二个? 'actualBorderWidth'应该在第二个代码中声明为'int',我更新它,对不起,但在第一个代码中它应该是'float'。 –

+0

@gerard请参阅我的更新,只删除'g.ReleaseHdc ...'行并添加'return;'行。我不知道它为什么会起作用,但在这种情况下,我们不需要ReleaseDC,如果你想使用'ReleaseDC' win32 api函数,它不会抛出任何异常。 'return;'是必须的,以便默认的非客户区域绘画不被执行。 –