当用户单击或聚焦文本框时,我该如何更改其BorderColor?
TextBox
的WM_NCPAINT
消息,在控件的非客户区绘制边框,如果控件获得了焦点。你可以使用任何颜色来绘制边框:using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class ExTextBox : TextBox
{
[DllImport("user32")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);
private const int WM_NCPAINT = 0x85;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_NCPAINT && this.Focused)
{
var dc = GetWindowDC(Handle);
using (Graphics g = Graphics.FromHdc(dc))
{
g.DrawRectangle(Pens.Red, 0, 0, Width - 1, Height - 1);
}
}
}
}
结果
控件聚焦时绘制边框完全不闪烁:
文本框的边框颜色属性
在本篇文章中,我只是在聚焦时更改了边框颜色。您还可以为控件添加一个BorderColor
属性。然后,您可以根据设计时或运行时的要求更改边框颜色。我在下一篇文章中发布了一个更完整版本的TextBox
,其中包含BorderColor
属性:
BufferedGraphics
进行双缓冲? - 8749236试试这个
bool focus = false;
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (focus)
{
textBox1.BorderStyle = BorderStyle.None;
Pen p = new Pen(Color.Red);
Graphics g = e.Graphics;
int variance = 3;
g.DrawRectangle(p, new Rectangle(textBox1.Location.X - variance, textBox1.Location.Y - variance, textBox1.Width + variance, textBox1.Height +variance ));
}
else
{
textBox1.BorderStyle = BorderStyle.FixedSingle;
}
}
private void textBox1_Enter(object sender, EventArgs e)
{
focus = true;
this.Refresh();
}
private void textBox1_Leave(object sender, EventArgs e)
{
focus = false;
this.Refresh();
}
Form1_Paint
中设置断点。现在,对于在Form1上绘制的每个控件,都会绘制在textBox1
周围的边框。更好的做法是创建一个自定义控件,从TextBox继承,以确保只在需要时绘制一次边框,而不是不必要地多次绘制,这会大大增加渲染时间,特别是在具有更多自定义onpaint作业时。 - Mike de Klerk以下是一种设置文本框边框颜色的终极解决方案:
public class BorderedTextBox : UserControl
{
TextBox textBox;
public BorderedTextBox()
{
textBox = new TextBox()
{
BorderStyle = BorderStyle.FixedSingle,
Location = new Point(-1, -1),
Anchor = AnchorStyles.Top | AnchorStyles.Bottom |
AnchorStyles.Left | AnchorStyles.Right
};
Control container = new ContainerControl()
{
Dock = DockStyle.Fill,
Padding = new Padding(-1)
};
container.Controls.Add(textBox);
this.Controls.Add(container);
DefaultBorderColor = SystemColors.ControlDark;
FocusedBorderColor = Color.Red;
BackColor = DefaultBorderColor;
Padding = new Padding(1);
Size = textBox.Size;
}
public Color DefaultBorderColor { get; set; }
public Color FocusedBorderColor { get; set; }
public override string Text
{
get { return textBox.Text; }
set { textBox.Text = value; }
}
protected override void OnEnter(EventArgs e)
{
BackColor = FocusedBorderColor;
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e)
{
BackColor = DefaultBorderColor;
base.OnLeave(e);
}
protected override void SetBoundsCore(int x, int y,
int width, int height, BoundsSpecified specified)
{
base.SetBoundsCore(x, y, width, textBox.PreferredHeight, specified);
}
}
WinForms在这方面一直表现不佳,有点麻烦。
你可以尝试的一种方法是在Panel中嵌入一个TextBox,然后根据焦点管理绘图:
public class BorderTextBox : Panel {
private Color _NormalBorderColor = Color.Gray;
private Color _FocusBorderColor = Color.Blue;
public TextBox EditBox;
public BorderTextBox() {
this.DoubleBuffered = true;
this.Padding = new Padding(2);
EditBox = new TextBox();
EditBox.AutoSize = false;
EditBox.BorderStyle = BorderStyle.None;
EditBox.Dock = DockStyle.Fill;
EditBox.Enter += new EventHandler(EditBox_Refresh);
EditBox.Leave += new EventHandler(EditBox_Refresh);
EditBox.Resize += new EventHandler(EditBox_Refresh);
this.Controls.Add(EditBox);
}
private void EditBox_Refresh(object sender, EventArgs e) {
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.Clear(SystemColors.Window);
using (Pen borderPen = new Pen(this.EditBox.Focused ? _FocusBorderColor : _NormalBorderColor)) {
e.Graphics.DrawRectangle(borderPen, new Rectangle(0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1));
}
base.OnPaint(e);
}
}
OnPaint
在控件上绘制自定义边框是可以的。但要知道如何使用OnPaint
保持效率,并将渲染时间降至最低。如果您在使用自定义绘图例程时遇到GUI卡顿的情况,请阅读此内容:什么是在 .Net 应用程序中使用 OnPaint 的正确方式?
因为PraVn的被接受的答案可能看起来很简单,但实际上效率很低。像上面答案中发布的自定义控件一样使用会更好。OnPaint
例程的大型应用程序来说,使用PraVn所示的方式是错误的方法。这是我完整的扁平化文本框控件,支持主题包括正常和聚焦状态下的自定义边框颜色。
该控件使用与Reza Aghaeihttps://dev59.com/i2kw5IYBdhLWcg3wm70h#38405319提到的相同概念,但FlatTextBox控件更具可定制性且无闪烁。
该控件以更好的方式处理WM_NCPAINT
窗口消息,以帮助消除闪烁。
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = WindowMessage.WM_NCPAINT AndAlso _drawBorder AndAlso Not DesignMode Then 'Draw the control border
Dim w As Integer
Dim h As Integer
Dim clip As Rectangle
Dim hdc As IntPtr
Dim clientRect As RECT = Nothing
GetClientRect(Handle, clientRect)
Dim windowRect As RECT = Nothing
GetWindowRect(Handle, windowRect)
w = windowRect.Right - windowRect.Left
h = windowRect.Bottom - windowRect.Top
clip = New Rectangle(CInt((w - clientRect.Right) / 2), CInt((h - clientRect.Bottom) / 2), clientRect.Right, clientRect.Bottom)
hdc = GetWindowDC(Handle)
Using g As Graphics = Graphics.FromHdc(hdc)
g.SetClip(clip, CombineMode.Exclude)
Using sb = New SolidBrush(BackColor)
g.FillRectangle(sb, 0, 0, w, h)
End Using
Using p = New Pen(If(Focused, _borderActiveColor, _borderNormalColor), BORDER_WIDTH)
g.DrawRectangle(p, 0, 0, w - 1, h - 1)
End Using
End Using
ReleaseDC(Handle, hdc)
Return
End If
MyBase.WndProc(m)
End Sub
我已删除默认的BorderStyle
属性,并用一个简单的布尔型DrawBorder
属性替代它,该属性控制是否在控件周围绘制边框。
使用BorderNormalColor
属性指定TextBox没有焦点时的边框颜色,使用BorderActiveColor
属性指定控件接收焦点时的边框颜色。
FlatTextBox有两个主题:VS2019 Dark和VS2019 Light,使用Theme
属性在它们之间切换。
完整的FlatTextBox控件代码是用VB.NET编写的。 https://gist.github.com/ahmedosama007/37fe2004183a51a4ea0b4a6dcb554176
With PictureBox1
.Visible = False
.Width = TextBox1.Width + 4
.Height = TextBox1.Height + 4
.Left = TextBox1.Left - 2
.Top = TextBox1.Top - 2
.SendToBack()
.Visible = True
End With
private void Form1_Paint(object sender, PaintEventArgs e)
{
System.Drawing.Rectangle rect = new Rectangle(TextBox1.Location.X,
TextBox1.Location.Y, TextBox1.ClientSize.Width, TextBox1.ClientSize.Height);
rect.Inflate(1, 1); // border thickness
System.Windows.Forms.ControlPaint.DrawBorder(e.Graphics, rect,
Color.DeepSkyBlue, ButtonBorderStyle.Solid);
}
BorderColor
属性的TextBox
,请查看更改TextBox
边框颜色。 - Reza Aghaei