【问题标题】:WinForm Control with Opacity带不透明度的 WinForm 控件
【发布时间】:2011-08-31 16:14:58
【问题描述】:

我有一个表单,它本身有一些控件(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。

【问题讨论】:

  • 除了与不透明度有关的任何事情之外,不要使用那种循环调用DoEvents。要么给ProcessingReport 某种钩子,以便在它完成时调用一些代码,或者简单地将最后一段代码放在ProcessingReport 方法的末尾,记住使用BeginInvoke 以确保它在用户界面线程。在几乎所有情况下,您都应该避免使用Application.DoEvents
  • 那么线程完成工作后我该怎么做呢?
  • 要禁用所有控件,您也可以尝试这样做:foreach (Controls in Controls){item.Enabled = false;}

标签: c# winforms opacity


【解决方案1】:

来自http://support.microsoft.com/kb/943454

WinForms 中的透明控件是 相对于他们的父母是透明的, 而不是其他控件。透明度 WinForms 更类似于伪装 比真正的透明度。透明的 控制实际上并没有让你看到 它背后的控制通过 形式。它要求它的父母画出它的 自己背景上的“透明” 控制。这就是为什么透明 控件显示其背后的形式,但 掩盖任何其他控件。

实现相对于 其他控件也需要这样做 事情,但在更大的范围内:相反 只是要求父母借鉴 前台控件的背景, 控件需要询问所有控件 在它后面绘制它的背景。 这仅适用于控制 提供一些方法来请求 他们被画了,不会 时自动更新 背景控件的图像变化。

该页面还提供了一个代码示例(遗憾的是在 vb 中)来说明这是如何完成的。

【讨论】:

    【解决方案2】:

    如果我理解正确,您想在操作运行时将表单内容“变暗”。

    正如有人在此之前所说,做正确的事情非常棘手。但是有一种方法可以轻松完成,只需一次预订(见下文)。

    看看这个源代码:

    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 中实现透明度的唯一方法是所有相关控件的全面合作,这是一项艰巨的任务。其他任何事情(包括这个解决方案)都是骗人的。

    【讨论】:

      猜你喜欢
      • 2011-01-21
      • 2010-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 2012-03-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多