c# - 在 C# 中构造一个带有文本的 3 色按钮
问题描述
我正在尝试扩展 C# Button 类,以便我可以根据提供的百分比为按钮着色,最多 3 种颜色。除了未显示按钮文本外,它似乎也可以工作。请有人建议如何显示文本?另外,我不确定 Refresh() 是否是在 Setter 方法中调用以使用提供的新百分比触发重绘的正确方法?非常感谢。
class TriColorsButton : Button
{
private double percentOfLeftColor, percentOfRightColor;
public TriColorsButton(String text, double percentOfLeftColor, double percentOfRightColor)
{
this.Text = text;
this.percentOfLeftColor = percentOfLeftColor;
this.percentOfRightColor = percentOfRightColor;
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
Brush brush;
RectangleF rectFirst, rectSecond, rectThird;
Color c1, c2, c3;
// create the first rectangle
rectFirst = new RectangleF(0, 0, this.Width, this.Height);
// create the second rectangle
int callWidth = (int)(this.Width * (100 - percentOfRightColor) / 100);
rectSecond = new RectangleF(0, 0, callWidth, this.Height);
// create the third rectangle
int leftWidth = (int)(this.Width * percentOfLeftColor / 100);
rectThird = new RectangleF(0, 0, leftWidth, this.Height);
// create the colors
c1 = Constants.altFoldColor;
c2 = Constants.altCallColor;
c3 = Constants.altRaiseColor;
// create the brush
brush = new SolidBrush(c1);
// fill the segment
pe.Graphics.FillRectangle(brush, rectFirst);
// create the brush
brush = new SolidBrush(c2);
// fill the segment
pe.Graphics.FillRectangle(brush, rectSecond);
// create the brush
brush = new SolidBrush(c3);
// fill the segment
pe.Graphics.FillRectangle(brush, rectThird);
// dispose of the brush
brush.Dispose();
}
public void SetPercentOfLeftColor(double percentOfLeftColor)
{
this.percentOfLeftColor = percentOfLeftColor;
Refresh();
}
public double GetPercentOfLeftColor()
{
return percentOfLeftColor;
}
public void SetPercentOfRightColor(double percentOfRightColor)
{
this.percentOfRightColor = percentOfRightColor;
Refresh();
}
public double GetPercentOfRightColor()
{
return percentOfRightColor;
}
}
此外,虽然这绘制了我想要的颜色,但我失去了标准按钮的原始外观和感觉。我想保留标准按钮的外观和感觉,例如标准按钮的悬停突出显示和边框。我怎样才能做到这一点?
编辑:根据建议,我尝试为按钮绘制背景图像。这产生了一种奇怪的效果,导致我的大部分身体都变白了。如果我在屏幕上移动表单,它会重绘并看起来更好,但其他更新不会适当地发生。这是我尝试过的:
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
Image bmp = new Bitmap(Width, Height);
using (Graphics g = Graphics.FromImage(bmp))
{
Brush brush;
RectangleF rectFirst, rectSecond, rectThird;
Color c1, c2, c3;
// create the first rectangle
rectFirst = new RectangleF(0, 0, this.Width, this.Height);
// create the second rectangle
int callWidth = (int)(this.Width * (100 - percentOfRightColor) / 100);
rectSecond = new RectangleF(0, 0, callWidth, this.Height);
// create the third rectangle
int leftWidth = (int)(this.Width * percentOfLeftColor / 100);
rectThird = new RectangleF(0, 0, leftWidth, this.Height);
// create the colors
c1 = Constants.altFoldColor;
c2 = Constants.altCallColor;
c3 = Constants.altRaiseColor;
// create the brush
brush = new SolidBrush(c1);
// fill the segment
g.FillRectangle(brush, rectFirst);
// create the brush
brush = new SolidBrush(c2);
// fill the segment
g.FillRectangle(brush, rectSecond);
// create the brush
brush = new SolidBrush(c3);
// fill the segment
g.FillRectangle(brush, rectThird);
// dispose of the brush
brush.Dispose();
}
this.BackgroundImage = bmp;
}
EDIT2:我想出了如何实现我想要的。我添加了一个绘制和设置背景的方法,并从构造函数中调用它。OnPaint 方法不再需要覆盖:
private void SetBackgroundImage()
{
Image bmp = new Bitmap(Width, Height);
using (Graphics g = Graphics.FromImage(bmp))
{
Brush brush;
RectangleF rectFirst, rectSecond, rectThird;
Color c1, c2, c3;
// create the first rectangle
rectFirst = new RectangleF(0, 0, this.Width, this.Height);
// create the second rectangle
int callWidth = (int)(this.Width * (100 - percentOfRightColor) / 100);
rectSecond = new RectangleF(0, 0, callWidth, this.Height);
// create the third rectangle
int leftWidth = (int)(this.Width * percentOfLeftColor / 100);
rectThird = new RectangleF(0, 0, leftWidth, this.Height);
// create the colors
c1 = Constants.altFoldColor;
c2 = Constants.altCallColor;
c3 = Constants.altRaiseColor;
// create the brush
brush = new SolidBrush(c1);
// fill the segment
g.FillRectangle(brush, rectFirst);
// create the brush
brush = new SolidBrush(c2);
// fill the segment
g.FillRectangle(brush, rectSecond);
// create the brush
brush = new SolidBrush(c3);
// fill the segment
g.FillRectangle(brush, rectThird);
// dispose of the brush
brush.Dispose();
}
this.BackgroundImage = bmp;
}
解决方案
OnPaint
在 Windows 窗体中覆盖主要是全有或全无的事情。即,如果您需要自定义绘图,则需要绘制所有内容,包括文本。在这方面,WPF 稍微好一点,因为它允许更好的模块化。
这应该很容易通过在 OnPaint 方法的末尾Graphics.DrawString
或TextRendered.DrawText
末尾插入调用来解决,其中 TextRendered.DrawText 应该与其他控件更加一致。您可能还需要一些方法来确保足够的对比度,例如添加阴影或背景矩形。请注意,绘制的顺序与调用的顺序相同,即稍后的绘制调用将在之前的调用之上,因此base.OnPaint(pe);
如果它完全透支,您的调用可能是多余的。
另外,我不确定 Refresh() 是否是在 Setter 方法中调用以使用提供的新百分比触发重绘的正确方法?
我通常使用.Invalidate()
. 如果我正确理解文档,区别在于 Invalidate 稍后重绘控件,而 Refresh 立即重绘它。
推荐阅读
- javascript - 如何创建一个每次都生成一个新变量的 for 循环
- presto - Presto SQL 是否像 SQL Server 一样支持使用 CTE 进行递归查询?例如员工层级
- twilio - 添加 Studio Flow 后,Twilio REST 客户端停止工作?
- python-3.x - 没有名为“bitmex_websocket”的模块
- python - 查找更改整数以匹配列表中其他人的最小移动次数
- c# - Telerik WinForm RadGridView 清除过滤
- javascript - 故事书行动——他们到底在叫什么?
- python - 如何将两个列表的子列表作为单个实体进行比较?
- tensorflow-federated - Tensorflow Federated 是否支持强化学习
- java - 为什么在演示中同步工作时 ReentrantLock 不起作用?