更改WinForms控件的边框颜色和外观

3
当用户将悬停在标签上时,它将向标签添加顶部和底部边框。类似于这个网站的效果:http://ianlunn.github.io/Hover/ -> Border Transitions -> Underline From Center。然而,我只知道如何定义普通的边框,我甚至不能改变边框的颜色、宽度等等...这是我到目前为止所实现的内容: designer.cs:
this.label1.BackColor = System.Drawing.SystemColors.ActiveCaption;
this.label1.Font = new System.Drawing.Font("Arial", 16F, System.Drawing.FontStyle.Bold);
this.label1.Location = new System.Drawing.Point(124, 187);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(217, 65);
this.label1.TabIndex = 0;
this.label1.Text = "Something Cool";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.label1.MouseHover += new System.EventHandler(this.label1_MouseHover);
this.label1.MouseLeave += new System.EventHandler(this.label1_MouseLeave);

cs:

private void label1_MouseHover(object sender, EventArgs e)
{
    label1.BorderStyle = BorderStyle.FixedSingle;
    label1.Font = new Font("Arial", 18, FontStyle.Bold);
}

private void label1_MouseLeave(object sender, EventArgs e)
{
    // initialize
    label1.BorderStyle = BorderStyle.None;
    label1.Font = new Font("Arial", 16, FontStyle.Bold);
}

这比你想象的要复杂得多。你将不得不继承控件并接管“Paint”处理程序,自己进行绘制。你需要响应所有用户输入并相应地做出反应,绘制你希望看到的一切。这不是一个简单的项目。如果你还有选择的话,你会发现WPF使这种事情变得更容易。 - DonBoitnott
2
WinForms 中做这个并不难。你根本不需要涉及继承。 - L. Guthardt
@L.Guthardt你好,谢谢。我使用了 ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, Color.Red, ButtonBorderStyle.Solid);,它确实将整个标签都描边了,但我希望只在上下两端描边,我该怎么做呢? - PNinja
2个回答

6

首先,建议您使用label1_MouseEnter()事件而不是label1_MouseHover()事件。因为当您悬停在label1上时,悬停事件会不断触发。这是不必要的,因为您只需要在进入标签时更改label1的外观,并将其恢复为默认值,一旦您离开它即可。因此,MouseEnter()是您首选的选择。

我们将定义一个bool变量来检查是否应该在label1周围绘制边框。我们在MouseEnter()MouseLeave()事件中更改其值。

bool changeBorder;

在这些事件中,我们将调用 label1.Refresh() 方法,该方法会重新绘制控件,从而触发其 Paint() 事件。
private void label1_MouseEnter(object sender, EventArgs e)
{
    changeBorder = true;
    label1.Refresh();
}

private void label1_MouseLeave(object sender, EventArgs e)
{
    changeBorder = false;
    label1.Refresh();
}

现在我们验证是否需要绘制新的“特殊边框”。如果是,我们使用ControlPaint类及其DrawBorder()方法来绘制与label1Rectangle大小相同的自定义边框。您可以根据需要修改此边框。如果我们不想绘制此“特殊边框”,则绘制一个“默认”边框。它只有Form的背景颜色,因此看起来像label1周围没有任何边框。
private void label1_Paint(object sender, PaintEventArgs e)
{
    if (changeBorder)
    {
        ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle,
                      Color.Red, 0, ButtonBorderStyle.Solid,
                      Color.Red, 2, ButtonBorderStyle.Solid,
                      Color.Red, 0, ButtonBorderStyle.Solid,
                      Color.Red, 2, ButtonBorderStyle.Solid);
    }
    else
        ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, this.BackColor, ButtonBorderStyle.None);
    }

在使用ControlPaint.DrawBorder()方法的参数时,请注意使用0而不是2。该方法的矩形宽度参数如下所示:
  1. int leftWidth
  2. int topWidth
  3. int rightWidth
  4. int bottomWidth
因此,我将第一个和第三个参数设置为0,这样右侧和左侧就不会绘制边框。您可以根据需要进行调整。

非常感谢!我完全理解你的代码和解释。我有一个问题,这些功能(label1_Paint&label1_MouseEnter&label1_MouseLeave)是否可以对所有标签进行良好的处理?我的意思是,如果我有一些标签,我不想对每个标签都这样做。我希望所有三个标签都能处理所有标签,那么我应该怎么做呢?我猜我应该触发哪个标签进入或离开,但我该如何实现呢?谢谢! - PNinja
1
您必须订阅每个单个标签的 myLabel_MouseEnter()myLabel_MouseLeave()myLabel_Paint() 事件。因为只有在特定控件上发生某个操作时才会触发特定事件。但是例如,您可以编写一个所有 Paint() 事件都将调用的方法。因此,您订阅了所有的 Paint() 事件,但所有这些事件都调用了您定义的相同的 extern 方法。该 extern 方法需要 PaintEventArgs e 作为方法参数,以便能够将矩形绘制到特定的控件上。 - L. Guthardt
如果我理解正确的话,创建一个通用的Paint函数,接收PaintEventArgs e作为参数,在每个labelX_paint事件中调用该函数并传递相应的PaintEventArgs e参数。是这样吗?再次感谢。 - PNinja
1
没错。我相信你也可以创建一个自定义控件:public class CustomLabel : Label。然后在这个类中修改它的 Paint 方法。此外,在您的代码中删除此类的命名空间。这样,这个控件将显示在 ToolBox 中,因此您可以像所有默认控件一样将控件拖放到您的 Form 上。您仍然需要执行 labelX.Refresh(),但是边框绘制将已经为您实现了这个自定义控件类中创建的每个标签。而且您也可以像普通的 Label 一样使用这个 CustomLabel - L. Guthardt

2

不要改变边框颜色,而是创建一个带有1像素填充的面板,并将label1放在该面板内。当您想要更改边框颜色时,改变面板的颜色即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接