WinForm控件透明度

9
我有一个表单,上面有一些控件(btnCreateReport、pnlDarkLayer)。我有一个适合于该表单的面板(Dock = Fill),并且它位于所有控件的后面。当用户点击btnCreateReport按钮时,我调用pnlDarkLayer的BringToFront方法,并在一些计算之后调用按钮的SendToBack()方法。我想在表单控件上绘制一个暗层,并禁用表单上的所有控件。这可能吗?谢谢。
也许这段代码可以帮助您理解我的目的:
private void btnCreateReport_Click(object sender, EventArgs e)
{
    pnlDarkLayer.BackColor = Color.FromArgb(100, Color.Gray);         

    pnlDarkLayer.BringToFront();
    btnCreateReport.Enabled = false;

    Thread ProcessReport = new Thread(new ThreadStart(ProcessingReport));
    ProcessReport.Start();
    while (ProcessReport.IsAlive)
    {
        Application.DoEvents();
    }
    pnlDarkLayer.SendToBack();

    btnCreateReport.Enabled = true;

}

这段代码可以隐藏所有控件,但我不想在表单上隐藏它们。我想在它们上面绘制一个暗色层。用户必须能够看到控件。

我需要像对于表单的透明度属性一样对其控件进行设置。

我尝试了以下代码:

pnlDarkLayer.CreateGraphics().CompositingMode=System.Drawing.Drawing2D.CompositingMode.SourceOver;

更新:我尝试了以下代码(使用表单而非面板):

private void btnCreateReport_Click(object sender, EventArgs e)
{          

    btnCreateReport.Enabled = false;

    frmProgress ProgressForm = new frmProgress();
    ProgressForm.TopLevel = false;
    ProgressForm.Parent = this;
    ProgressForm.BringToFront();
    this.Controls.Add(ProgressForm);
    ProgressForm.Show();

    Thread ProcessReport = new Thread(new ThreadStart(ProcessingReport));
    ProcessReport.Start();

    while (ProcessReport.IsAlive)
    {
        Application.DoEvents();
    }
    ProgressForm.Close();
    btnCreateReport.Enabled = true;

}

但我无法在我的表单中看到ProgressForm。

3
除了不透明度之外,请不要使用那种调用DoEvents的循环。要么为ProcessingReport提供某种钩子以在完成时调用一些代码,要么仅将最后一部分代码放在ProcessingReport方法的末尾,并记得使用BeginInvoke确保它在UI线程上执行。在几乎所有情况下,应避免使用Application.DoEvents - Jon Skeet
线程完成任务后,我该如何执行某些操作? - Saleh
要禁用所有控件,您也可以尝试执行以下操作:foreach (Control item in Controls){item.Enabled = false;} - Renatas M.
2个回答

8

如果我理解正确,您想在操作运行时“加深”表单的内容。

正如其他人在这里所说的那样,这很难做到。但是有一种简单的方法可以完成它,只有一个保留(见下文)。

请查看此源代码:

public partial class Form1 : Form
{
    private Bitmap _background;
    private bool _isShrouded;

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        if (true == _isShrouded && null!=_background)
            e.Graphics.DrawImage(_background, 0, 0);
    }

    public void Shroud()
    {
        if (false == _isShrouded)
        {
            CreateScreenshot();

            HideControls();

            _isShrouded = true;

            this.Invalidate();
        }
    }

    public void Unshroud()
    {
        if (true == _isShrouded)
        {
            ShowControls();

            _isShrouded = false;

            this.Invalidate();
        }


    }

    private void HideControls()
    {
        foreach (Control control in this.Controls)
            control.Visible = false;
    }

    private void ShowControls()
    {
        foreach (Control control in this.Controls)
            control.Visible = true;
    }

    private void CreateScreenshot()
    {
        Rectangle area = this.RectangleToScreen(this.ClientRectangle);
        Bitmap screenGrab = new Bitmap(area.Width, area.Height);

        Brush dark = new SolidBrush(Color.FromArgb(128, Color.Black));

        Graphics g = Graphics.FromImage(screenGrab);
        g.CopyFromScreen(area.Location, Point.Empty, area.Size);
        g.FillRectangle(dark, 0, 0, area.Width, area.Height);
        g.Dispose();

        _background = screenGrab;
    }
}

Form1类有两个主要方法,Shroud()和Unshroud()。

Shroud()方法拍摄表单的快照,并将其复制到位图中,然后“变暗”。控件随后被隐藏,并在表单上绘制位图。

UnShroud()方法恢复控件,并告诉表单不再绘制位图。

它需要两个私有变量:一个用于存储位图,另一个是维护当前状态的标志。

它还覆盖了OnPaint(),因为它需要在“遮蔽”时绘制背景图像。

注意:遮蔽通过对表单进行屏幕截图来实现。这意味着在遮蔽时,表单必须是最上面的表单。如果表单被其他表单遮挡,则它们将包含在屏幕截图中。希望这不会给您带来问题。

注意:如前所述,在Windows中实现透明度的唯一方法是所有涉及控件的完全合作,这是一项艰巨的任务。任何其他方法(包括此解决方案)都只是把戏。


8
http://support.microsoft.com/kb/943454
WinForms中的透明控件是相对于其父控件而言透明,而不是相对于其他控件。WinForms中的透明更像是伪装而非真正的透明。透明控件实际上并不能让您透过窗体看到它后面的控件。它会要求其父控件在“透明”控件上绘制自己的背景。这就是为什么透明控件显示其后面的窗体,但覆盖了任何其他控件。
要相对于其他控件实现透明度,需要在更大的范围内执行相同的操作:控件不仅要要求父控件在前景控件的背景上绘制,还需要要求其后面的所有控件在其背景上绘制。这仅适用于提供某些方法以请求绘制的控件,并且当后面的控件图像更改时不会自动更新。页面还提供了一个代码示例(可惜是vb)来展示如何完成此操作。

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