在 C#.NET 中,我尝试以编程方式更改组框中边框的颜色。
更新:在我们切换到.NET之前,我在winforms系统上工作时问了这个问题。
只需添加绘画事件。
private void groupBox1_Paint(object sender, PaintEventArgs e)
{
GroupBox box = sender as GroupBox;
DrawGroupBox(box, e.Graphics, Color.Red, Color.Blue);
}
private void DrawGroupBox(GroupBox box, Graphics g, Color textColor, Color borderColor)
{
if (box != null)
{
Brush textBrush = new SolidBrush(textColor);
Brush borderBrush = new SolidBrush(borderColor);
Pen borderPen = new Pen(borderBrush);
SizeF strSize = g.MeasureString(box.Text, box.Font);
Rectangle rect = new Rectangle(box.ClientRectangle.X,
box.ClientRectangle.Y + (int)(strSize.Height / 2),
box.ClientRectangle.Width - 1,
box.ClientRectangle.Height - (int)(strSize.Height / 2) - 1);
// Clear text and border
g.Clear(this.BackColor);
// Draw text
g.DrawString(box.Text, box.Font, textBrush, box.Padding.Left, 0);
// Drawing Border
//Left
g.DrawLine(borderPen, rect.Location, new Point(rect.X, rect.Y + rect.Height));
//Right
g.DrawLine(borderPen, new Point(rect.X + rect.Width, rect.Y), new Point(rect.X + rect.Width, rect.Y + rect.Height));
//Bottom
g.DrawLine(borderPen, new Point(rect.X, rect.Y + rect.Height), new Point(rect.X + rect.Width, rect.Y + rect.Height));
//Top1
g.DrawLine(borderPen, new Point(rect.X, rect.Y), new Point(rect.X + box.Padding.Left, rect.Y));
//Top2
g.DrawLine(borderPen, new Point(rect.X + box.Padding.Left + (int)(strSize.Width), rect.Y), new Point(rect.X + rect.Width, rect.Y));
}
}
基于之前的答案,一个更好的解决方案,包括组框的标签:
groupBox1.Paint += PaintBorderlessGroupBox;
private void PaintBorderlessGroupBox(object sender, PaintEventArgs p)
{
GroupBox box = (GroupBox)sender;
p.Graphics.Clear(SystemColors.Control);
p.Graphics.DrawString(box.Text, box.Font, Brushes.Black, 0, 0);
}
您可能想要调整文本的 x/y,但对于我的使用来说,这恰到好处。
FWIW,这是我使用的实现。它是 GroupBox 的子项,但不仅允许设置 BorderColor,还允许设置边框的厚度和圆角的半径。此外,您还可以设置 GroupBox 标签所需的缩进量,并使用负缩进从右侧缩进。
using System;
using System.Drawing;
using System.Windows.Forms;
namespace BorderedGroupBox
{
public class BorderedGroupBox : GroupBox
{
private Color _borderColor = Color.Black;
private int _borderWidth = 2;
private int _borderRadius = 5;
private int _textIndent = 10;
public BorderedGroupBox() : base()
{
InitializeComponent();
this.Paint += this.BorderedGroupBox_Paint;
}
public BorderedGroupBox(int width, float radius, Color color) : base()
{
this._borderWidth = Math.Max(1,width);
this._borderColor = color;
this._borderRadius = Math.Max(0,radius);
InitializeComponent();
this.Paint += this.BorderedGroupBox_Paint;
}
public Color BorderColor
{
get => this._borderColor;
set
{
this._borderColor = value;
DrawGroupBox();
}
}
public int BorderWidth
{
get => this._borderWidth;
set
{
if (value > 0)
{
this._borderWidth = Math.Min(value, 10);
DrawGroupBox();
}
}
}
public int BorderRadius
{
get => this._borderRadius;
set
{ // Setting a radius of 0 produces square corners...
if (value >= 0)
{
this._borderRadius = value;
this.DrawGroupBox();
}
}
}
public int LabelIndent
{
get => this._textIndent;
set
{
this._textIndent = value;
this.DrawGroupBox();
}
}
private void BorderedGroupBox_Paint(object sender, PaintEventArgs e) =>
DrawGroupBox(e.Graphics);
private void DrawGroupBox() =>
this.DrawGroupBox(this.CreateGraphics());
private void DrawGroupBox(Graphics g)
{
Brush textBrush = new SolidBrush(this.ForeColor);
SizeF strSize = g.MeasureString(this.Text, this.Font);
Brush borderBrush = new SolidBrush(this.BorderColor);
Pen borderPen = new Pen(borderBrush,(float)this._borderWidth);
Rectangle rect = new Rectangle(this.ClientRectangle.X,
this.ClientRectangle.Y + (int)(strSize.Height / 2),
this.ClientRectangle.Width - 1,
this.ClientRectangle.Height - (int)(strSize.Height / 2) - 1);
Brush labelBrush = new SolidBrush(this.BackColor);
// Clear text and border
g.Clear(this.BackColor);
// Drawing Border (added "Fix" from Jim Fell, Oct 6, '18)
int rectX = (0 == this._borderWidth % 2) ? rect.X + this._borderWidth / 2 : rect.X + 1 + this._borderWidth / 2;
int rectHeight = (0 == this._borderWidth % 2) ? rect.Height - this._borderWidth / 2 : rect.Height - 1 - this._borderWidth / 2;
// NOTE DIFFERENCE: rectX vs rect.X and rectHeight vs rect.Height
g.DrawRoundedRectangle(borderPen, rectX, rect.Y, rect.Width, rectHeight, (float)this._borderRadius);
// Draw text
if (this.Text.Length > 0)
{
// Do some work to ensure we don't put the label outside
// of the box, regardless of what value is assigned to the Indent:
int width = (int)rect.Width, posX;
posX = (this._textIndent < 0) ? Math.Max(0-width,this._textIndent) : Math.Min(width, this._textIndent);
posX = (posX < 0) ? rect.Width + posX - (int)strSize.Width : posX;
g.FillRectangle(labelBrush, posX, 0, strSize.Width, strSize.Height);
g.DrawString(this.Text, this.Font, textBrush, posX, 0);
}
}
#region Component Designer generated code
/// <summary>Required designer variable.</summary>
private System.ComponentModel.IContainer components = null;
/// <summary>Clean up any resources being used.</summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
base.Dispose(disposing);
}
/// <summary>Required method for Designer support - Don't modify!</summary>
private void InitializeComponent() => components = new System.ComponentModel.Container();
#endregion
}
}
为了使其工作,您还必须扩展基本 Graphics 类(注意:这是从我在尝试创建圆角面板控件时在这里找到的一些代码派生的,但我找不到原始的发帖链接到这里):
static class GraphicsExtension
{
private static GraphicsPath GenerateRoundedRectangle(
this Graphics graphics,
RectangleF rectangle,
float radius)
{
float diameter;
GraphicsPath path = new GraphicsPath();
if (radius <= 0.0F)
{
path.AddRectangle(rectangle);
path.CloseFigure();
return path;
}
else
{
if (radius >= (Math.Min(rectangle.Width, rectangle.Height)) / 2.0)
return graphics.GenerateCapsule(rectangle);
diameter = radius * 2.0F;
SizeF sizeF = new SizeF(diameter, diameter);
RectangleF arc = new RectangleF(rectangle.Location, sizeF);
path.AddArc(arc, 180, 90);
arc.X = rectangle.Right - diameter;
path.AddArc(arc, 270, 90);
arc.Y = rectangle.Bottom - diameter;
path.AddArc(arc, 0, 90);
arc.X = rectangle.Left;
path.AddArc(arc, 90, 90);
path.CloseFigure();
}
return path;
}
private static GraphicsPath GenerateCapsule(
this Graphics graphics,
RectangleF baseRect)
{
float diameter;
RectangleF arc;
GraphicsPath path = new GraphicsPath();
try
{
if (baseRect.Width > baseRect.Height)
{
diameter = baseRect.Height;
SizeF sizeF = new SizeF(diameter, diameter);
arc = new RectangleF(baseRect.Location, sizeF);
path.AddArc(arc, 90, 180);
arc.X = baseRect.Right - diameter;
path.AddArc(arc, 270, 180);
}
else if (baseRect.Width < baseRect.Height)
{
diameter = baseRect.Width;
SizeF sizeF = new SizeF(diameter, diameter);
arc = new RectangleF(baseRect.Location, sizeF);
path.AddArc(arc, 180, 180);
arc.Y = baseRect.Bottom - diameter;
path.AddArc(arc, 0, 180);
}
else path.AddEllipse(baseRect);
}
catch { path.AddEllipse(baseRect); }
finally { path.CloseFigure(); }
return path;
}
/// <summary>
/// Draws a rounded rectangle specified by a pair of coordinates, a width, a height and the radius
/// for the arcs that make the rounded edges.
/// </summary>
/// <param name="brush">System.Drawing.Pen that determines the color, width and style of the rectangle.</param>
/// <param name="x">The x-coordinate of the upper-left corner of the rectangle to draw.</param>
/// <param name="y">The y-coordinate of the upper-left corner of the rectangle to draw.</param>
/// <param name="width">Width of the rectangle to draw.</param>
/// <param name="height">Height of the rectangle to draw.</param>
/// <param name="radius">The radius of the arc used for the rounded edges.</param>
public static void DrawRoundedRectangle(
this Graphics graphics,
Pen pen,
float x,
float y,
float width,
float height,
float radius)
{
RectangleF rectangle = new RectangleF(x, y, width, height);
GraphicsPath path = graphics.GenerateRoundedRectangle(rectangle, radius);
SmoothingMode old = graphics.SmoothingMode;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.DrawPath(pen, path);
graphics.SmoothingMode = old;
}
/// <summary>
/// Draws a rounded rectangle specified by a pair of coordinates, a width, a height and the radius
/// for the arcs that make the rounded edges.
/// </summary>
/// <param name="brush">System.Drawing.Pen that determines the color, width and style of the rectangle.</param>
/// <param name="x">The x-coordinate of the upper-left corner of the rectangle to draw.</param>
/// <param name="y">The y-coordinate of the upper-left corner of the rectangle to draw.</param>
/// <param name="width">Width of the rectangle to draw.</param>
/// <param name="height">Height of the rectangle to draw.</param>
/// <param name="radius">The radius of the arc used for the rounded edges.</param>
public static void DrawRoundedRectangle(
this Graphics graphics,
Pen pen,
int x,
int y,
int width,
int height,
int radius)
{
graphics.DrawRoundedRectangle(
pen,
Convert.ToSingle(x),
Convert.ToSingle(y),
Convert.ToSingle(width),
Convert.ToSingle(height),
Convert.ToSingle(radius));
}
}
只需将任何对象(不仅仅是按钮)上的绘制动作设置为此方法即可绘制边框。
private void UserControl1_Paint(object sender, PaintEventArgs e)
{
ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle, Color.Red, ButtonBorderStyle.Solid);
}
它仍然不会像原来那样漂亮和圆润,但它更简单。
我不确定这是否适用于所有情况,但多亏了这个线程,我们很快就以编程方式连接到了 Paint 事件:
GroupBox box = new GroupBox();
[...]
box.Paint += delegate(object o, PaintEventArgs p)
{
p.Graphics.Clear(someColorHere);
};
干杯!
我已经实现了相同的边界,对于新手来说可能更容易理解:
private void groupSchitaCentru_Paint(object sender, PaintEventArgs e)
{
Pen blackPen = new Pen(Color.Black, 2);
Point pointTopLeft = new Point(0, 7);
Point pointBottomLeft = new Point(0, groupSchitaCentru.ClientRectangle.Height);
Point pointTopRight = new Point(groupSchitaCentru.ClientRectangle.Width, 7);
Point pointBottomRight = new Point(groupSchitaCentru.ClientRectangle.Width, groupSchitaCentru.ClientRectangle.Height);
e.Graphics.DrawLine(blackPen, pointTopLeft, pointBottomLeft);
e.Graphics.DrawLine(blackPen, pointTopLeft, pointTopRight);
e.Graphics.DrawLine(blackPen, pointBottomRight, pointTopRight);
e.Graphics.DrawLine(blackPen, pointBottomLeft, pointBottomRight);
}
我不知道,也许它可以帮助那些想要实现边界调整的人。
对 Jim Fell 代码的调整让边框对我来说更好了一些,但作为评论添加太长了
...
Rectangle rect = new Rectangle(this.ClientRectangle.X,
this.ClientRectangle.Y + (int)(strSize.Height / 2),
this.ClientRectangle.Width,
this.ClientRectangle.Height - (int)(strSize.Height / 2));
Brush labelBrush = new SolidBrush(this.BackColor);
// Clear text and border
g.Clear(this.BackColor);
int drawX = rect.X;
int drawY = rect.Y;
int drawWidth = rect.Width;
int drawHeight = rect.Height;
if (this._borderWidth > 0)
{
drawX += this._borderWidth / 2;
drawY += this._borderWidth / 2;
drawWidth -= this._borderWidth;
drawHeight -= this._borderWidth;
if (this._borderWidth % 2 == 0)
{
drawX -= 1;
drawWidth += 1;
drawY -= 1;
drawHeight += 1;
}
}
g.DrawRoundedRectangle(borderPen, drawX, drawY, drawWidth, drawHeight, (float)this._borderRadius);
在测试了其中一些代码后,我创建了一个适合我的版本。在现有边框上进行简单的绘制。从类 GroupBox 派生并添加这些值。
private Color borderColor = Color.LightGray;
public Color BorderColor {
get { return borderColor; }
set { borderColor = value; }
}
public Init() {
FlatStyle = FlatStyle.Flat;
// Paint new color border over current border
Paint += OnGroupBox_Paint;
}
private void OnGroupBox_Paint(object sender, PaintEventArgs e) {
if (sender is GroupBox box) {
var g = e.Graphics;
using (var p = new Pen(borderColor)) {
// Measure Text or defaultText
var addText = !string.IsNullOrEmpty(Text);
var txt = addText ? box.Text : "H";
SizeF strSize = g.MeasureString(txt, box.Font);
Rectangle rect = new Rectangle(
box.ClientRectangle.X,
box.ClientRectangle.Y + (int)(strSize.Height / 2),
box.ClientRectangle.Width - 1,
box.ClientRectangle.Height - (int)(strSize.Height / 2) - 1
);
var paddingLeft = addText ? box.Padding.Left : (int)strSize.Width;
// Drawing Border
//Left
g.DrawLine(p, rect.Location, new Point(rect.X, rect.Y + rect.Height));
//Right
g.DrawLine(p, new Point(rect.X + rect.Width, rect.Y), new Point(rect.X + rect.Width, rect.Y + rect.Height));
//Bottom
g.DrawLine(p, new Point(rect.X, rect.Y + rect.Height -1), new Point(rect.X + rect.Width, rect.Y + rect.Height-1));
if (addText) {
//Top1
g.DrawLine(p, new Point(rect.X, rect.Y), new Point(rect.X + box.Padding.Left, rect.Y));
//Top2
g.DrawLine(p, new Point(rect.X + box.Padding.Left + (int)(strSize.Width), rect.Y), new Point(rect.X + rect.Width, rect.Y));
} else {
//Top1
g.DrawLine(p, new Point(rect.X, rect.Y), new Point(rect.X + box.Width, rect.Y));
}
}
}
}