65.9K
CodeProject 正在变化。 阅读更多。
Home

带半透明边框的启动画面

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.65/5 (20投票s)

2007年11月8日

2分钟阅读

viewsIcon

72381

downloadIcon

3543

本文介绍了如何创建带有alpha通道图像和半透明边框的启动画面。

Screenshot - Article.png

引言

由于我的应用程序启动时间增加,我需要显示加载状态,即启动画面。我检查了几个程序中的启动画面,选择了Adobe Acrobat Reader 6使用的那个。带有透明、有“区域”的启动画面有锐利的边框,就像窗口中的孔洞。
某些类型具有主要特征——屏幕上图片的平滑边框。但它们也有一些错误

  • 当另一个窗口移动到启动画面上方时,图像可能会丢失
  • 如果底层图片(例如窗口的颜色/文本或其他控件)发生了变化,我们可能会看到一个异常边框(启动画面显示时的背景部分)。这种类型的启动画面是由一种算法创建的(IMHO):在显示启动画面之前,程序截取桌面的屏幕截图,在其上绘制带有alpha通道的图片,并将结果放置在启动画面表单上
  • 有时这会表现为应用程序挂起

例如,下面显示了这种类型带有异常边框的启动画面

Example of abnormal border of splash screen

然后我找到了一篇文章,带动画效果的OSD窗口,用C#编写,作者是Mr.Smarty,并得出结论,这是一个好主意。我修改了源代码,增加了在窗口已经在屏幕上时更改文本和图像的功能。
非常感谢您,Mr. Smarty!

Using the Code

在显示之前,SplashScreen 创建应用程序的主窗体,显示一个窗口,并将其传递给主窗体的构造函数。

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    SplashScreen splash = new SplashScreen();
    splash.Show();
    Application.Run(new FormMain(splash));
}

我们可以在主窗体的构造函数中调用 SetProgress 方法来更新启动画面上的状态进度。例如

public partial class FormMain : Form
{
    public FormMain(SplashScreen splash)
    {
        mSplashScreen = splash;
        mSplashScreen.SetProgress("Initialize Components...", 0.0);
        InitializeComponent();
        mSplashScreen.SetProgress("Some task 1...", 0.2);
        Thread.Sleep(1000);
        mSplashScreen.SetProgress("Some task 2...", 0.4);
        Thread.Sleep(1000);
        mSplashScreen.SetProgress("Some task 3...", 0.6);
        Thread.Sleep(1000);
        mSplashScreen.SetProgress("Some task 4...", 0.8);
        Thread.Sleep(1000);
        mSplashScreen.SetProgress("Starting...", 1.0);
    }
    private SplashScreen mSplashScreen;
...

在上面的代码片段中,Thread.Sleep 模拟了持续操作。

当主窗体准备好显示时,我们必须关闭启动画面

private void FormMain_Load(object sender, EventArgs e)
{
    if (mSplashScreen != null)
        mSplashScreen.Hide();
}

启动画面的外观在函数 FormWelcome.PerformPaint 中实现。

protected override void PerformPaint(PaintEventArgs e)
{
    if (base.Handle != IntPtr.Zero)
    {
        Graphics g = e.Graphics;
        g.SmoothingMode = SmoothingMode.HighQuality;

        //background (png with alpha-channel)
        g.FillRectangle(this.mBrush, this.Bound);

        //text
        g.DrawString(String.Format("{0} v{1}", Application.ProductName,
            Application.ProductVersion), mTextFont, mTextBrush, 40, 20);
        g.DrawString(mMessageText, SystemFonts.DialogFont, mTextBrush,
            40, this.Height - 40);

        //progress bar
        float w = this.Width - 10 * 2;
        //g.DrawLine(mPenProgress, 40, this.Height - 20, 40 + w *
            mCompletionFraction, this.Height - 20);
        g.DrawImageUnscaledAndClipped(
            Properties.Resources.image_load_progress_texture,
            new Rectangle(10, 36, (int)(w * mCompletionFraction),
                Properties.Resources.image_load_progress_texture.Height));
    }
}

关注点

  • 在OSD之前,我尝试将启动画面创建为单独线程中的 Form,但是这种方法并没有解决背景变化时出现异常边框的问题。但是,如果我们有一个矩形图像,这种方法可能很有用。
  • 我发现用瓷砖绘制带有渐变的alpha通道图像会产生有趣的效果,并将其应用于绘制进度条。
  • 我还尝试了另一种与启动画面不同的方法:我们可以只创建应用程序的主窗体和进度条,并在主窗体在屏幕上显示后(异步地)在专用的 UserControl 上创建另一个界面。

历史

  • 2007年8月31日 - v1.0 首次发布
© . All rights reserved.