给C#的进度条加上文本
最近在学习使用C#做GUI。其中想在进度条控件上同时显示点文本信息,类似下面的效果:
以下是各种折腾:
尝试1:直接赋值text
ProgressBar控件的属性列表里面是看不到Text属性的,但程序里仍然可以设置:
progressBar1.Text = "test";
编译运行之,啥也没有显示...
尝试2:自定义Paint事件
查阅各种资料得知,控件可以添加自定义的Paint事件:
progressBar1.Paint += new PaintEventHandler(my_paint);
......
private void my_paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawString(......);
}
编译运行之,还是啥也没有显示...
调试发现,my_paint根本就没被调用。这是为什么呢?这是按照微软的例子写的啊!
(https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.paint?view=windowsdesktop-6.0)
再次查找各种资料,在dotnet源码里面发现,ProgressBar控件其实就是对win32的进度条的包装。
所有操作都是通过发消息给进度条窗口来实现的,其本身根本就没有OnPaint事件,自然也不会调用你自己注册的Paint了。
尝试3:重载ProgressBar类
再次查找各种资料。这次主要是看别人如何实现的。基本上都是重载ProgressBar类,然后再重载WndProc,在OnPaint事件里面去画Text。比如这里的一个实现:
https://doogalbellend.blogspot.com/2010/10/winforms-progressbar-with-text.html
这样确实实现了预期的效果,但也有不尽人意的地方。比如不能用设计工具来放置进度条了。或者你先放置好,然后再改代码,改为你重载的新进度条类。
尝试4:使用NativeWindow
偶尔发现有用NativeWindow实现的。这几乎是最优化的实现方案了。NativeWindow是对win32窗口的一个封装,并且它可以使用别人的窗口Handle:
public class ProgresBarExt : NativeWindow
{
private ProgressBar c;
// 创建时,传入一个已有的ProgressBar实例,并使用它的窗口Handle。
public ProgresBarExt(ProgressBar progressBar)
{
c = progressBar;
this.AssignHandle(c.Handle);
}
private const int WmPaint = 15;
protected override void WndProc(ref Message m)
{
// 先画本体
base.WndProc(ref m);
if ((m.Msg == WmPaint))
{
// 再画text
using (var g = Graphics.FromHwnd(Handle))
{
string str = c.Value.ToString();
int x = c.Width / 2 - (int)g.MeasureString(str, SystemFonts.DefaultFont).Width / 2;
int y = c.Height/2 - SystemFonts.DefaultFont.Height / 2;
g.DrawString(str, SystemFonts.DefaultFont, Brushes.Black, x, y);
}
}
}
}
如何使用:
private ProgresBarExt mProgresBar1;
......
public Form1()
{
InitializeComponent();
mProgresBar1 = new ProgresBarExt(progressBar1);
}
以后直接对progressBar1.Text赋值就可以显示你的text了。