【问题标题】:C# Transparent Panels Refresh ProblemsC#透明面板刷新问题
【发布时间】:2011-09-08 15:50:06
【问题描述】:

我目前正在处理一个需要在透明面板上显示动画的项目。我已经能够创建一个透明面板并在其上绘图,但是当我刷新面板时,我用钢笔工具绘制的位置并没有被重绘为透明。这是留下我之前画在面板上的最后一个位置。

我认为有一种简单的方法可以覆盖 OnPaint 或 Refresh 以将面板上的所有像素重绘为透明,但我无法在线找到解决方案或自己弄清楚。

这是我用来使背景透明的代码:

public class TransparentPanel : Panel
{
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x20;
            return cp;
        }
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
    }
 }

这是我将背景重绘为透明的最失败的尝试:

protected override void OnPaint(PaintEventArgs pe)
{
        pe.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(100,255,255,255)), this.ClientRectangle);
}

这个解决方案的问题是在几次刷新后背景变成不透明的白色。

谁能帮我弄清楚如何做到这一点?我对图形和动画非常陌生,我认为这有一个相当简单的答案。提前致谢。


***编辑*** 根据 Dyppl 的回复,我更改了将图形绘制到面板的方式。这是我当前的代码:

    public TransparentPanel fighterPanel;
...
    fighterPanel.Paint +=new PaintEventHandler(fighterPanel_Paint);
...
    fighterPanel = new TransparentPanel();
    fighterPanel.Location = new System.Drawing.Point(600, 300);
    fighterPanel.Size = new System.Drawing.Size(400, 400);
    gameArenaForm.Controls.Add(fighterPanel);
    fighterPanel.BringToFront();        
...
    private void fighterPanel_Paint(object sender, PaintEventArgs e)
    {
        using (Pen blackPen = new Pen(Color.Black, 3), redPen = new Pen(Color.Red, 3), bluePen = new Pen(Color.Blue, 3))
        {
            //head     
            e.Graphics.DrawEllipse
                (blackPen,
                head.DrawPoint(torso.GetTorsoAngle(), torso.neck.getLocationX(), torso.neck.getLocationY()).X,
                head.DrawPoint(torso.GetTorsoAngle(), torso.neck.getLocationX(), torso.neck.getLocationY()).Y,
                head.radius * 2,
                head.radius * 2
                );
            //torso
            e.Graphics.DrawLine(blackPen, torso.neck.getLocationX(), torso.neck.getLocationY(), torso.shoulders.getLocationX(), torso.shoulders.getLocationY());
            e.Graphics.DrawLine(blackPen, torso.shoulders.getLocationX(), torso.shoulders.getLocationY(), torso.hips.getLocationX(), torso.hips.getLocationY());
            //right arm
            e.Graphics.DrawLine(blackPen, torso.shoulders.getLocationX(), torso.shoulders.getLocationY(), rightArm.elbow.getLocationX(), rightArm.elbow.getLocationY());
            e.Graphics.DrawLine(redPen, rightArm.elbow.getLocationX(), rightArm.elbow.getLocationY(), rightArm.attachHand.getLocationX(), rightArm.attachHand.getLocationY());
            //left arm
            e.Graphics.DrawLine(blackPen, torso.shoulders.getLocationX(), torso.shoulders.getLocationY(), leftArm.elbow.getLocationX(), leftArm.elbow.getLocationY());
            e.Graphics.DrawLine(bluePen, leftArm.elbow.getLocationX(), leftArm.elbow.getLocationY(), leftArm.attachHand.getLocationX(), leftArm.attachHand.getLocationY());
            //right leg
            e.Graphics.DrawLine(blackPen, torso.hips.getLocationX(), torso.hips.getLocationY(), rightLeg.knee.getLocationX(), rightLeg.knee.getLocationY());
            e.Graphics.DrawLine(redPen, rightLeg.knee.getLocationX(), rightLeg.knee.getLocationY(), rightLeg.attachFoot.getLocationX(), rightLeg.attachFoot.getLocationY());
            //left leg
            e.Graphics.DrawLine(blackPen, torso.hips.getLocationX(), torso.hips.getLocationY(), leftLeg.knee.getLocationX(), leftLeg.knee.getLocationY());
            e.Graphics.DrawLine(bluePen, leftLeg.knee.getLocationX(), leftLeg.knee.getLocationY(), leftLeg.attachFoot.getLocationX(), leftLeg.attachFoot.getLocationY());
        }
    }

下面是一些物体移动和刷新几次前后的图片:

Before

After

抱歉,除非我有 10 个 Rep,否则它不会让我嵌入图像。

【问题讨论】:

  • 来自一个对图形并不陌生的人:在 GDI+ 和 winforms 方面,透明度从来都不是一件简单的事情......
  • 母羊,那听起来对我来说不是很有希望。你对这个问题有什么想法吗?
  • @Alex:是的,现在就试试
  • @Alex:你是怎么在面板上画画的?
  • @Dyppl2: 私有图形 drawIt; ... drawIt = fighterPanel.CreateGraphics(); ... drawIt.DrawEllipse(blackPen,head.DrawPoint(torso.GetTorsoAngle(),torso.neck.getLocationX(),torso.neck.getLocationY()).X,head.DrawPoint(torso.GetTorsoAngle(),躯干。颈部.getLocationX(), torso.neck.getLocationY()).Y, head.radius * 2, head.radius * 2 ); drawIt.DrawLine(blackPen, torso.neck.getLocationX(), torso.neck.getLocationY(), torso.shoulders.getLocationX(), torso.shoulders.getLocationY());

标签: c# animation transparency picturebox panels


【解决方案1】:

您不应该在您的任务中使用CreateGraphics。订阅面板的Paint 事件,并使用PaintEventArgs.Graphics 作为Graphics 对象在事件处理程序中进行所有绘图。

private void transparentPanel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.DrawRectangle(new Pen(Color.Red,2), 4,4,64,64);
}

这是我使用您的 TransparentPanel 和我的事件处理程序得到的结果:

更新:问题是您必须在每个绘制周期开始时调用Graphics.Clear 方法才能摆脱所有先前的绘制。它会弄乱你的透明背景。 This link 给你一些关于这个问题的建议。关键是您应该使面板的父控件无效,以获得“透明”背景。

所以,我没有修改TransparentPanel 的代码,而是更改了主窗体的代码:

readonly Random _rand =new Random();

private void transparentPanel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.DrawRectangle(new Pen(Color.Red,2), _rand.Next(60),_rand.Next(30),64,64);
}

private void button1_Click(object sender, EventArgs e)
{
   Invalidate(new Rectangle(transparentPanel1.Location, transparentPanel1.Size),true);
}

现在,每当我单击表单上的按钮时,面板都会重新绘制并在随机位置显示一个矩形。如果你使 transparantPanel1 本身无效,它不会被清除,你会看到一堆红色的矩形。


更新(亚历克斯): 这是 Dyppl 的链接中提供的解决问题的代码。只需要放在透明面板类中即可:

public void InvalidateEx()
    {
        if (Parent == null)
            return;
        Rectangle rc = new Rectangle(this.Location, this.Size);
        Parent.Invalidate(rc, true);
    } 

我在面板上的每次刷新时调用此代码,它使背景保持透明。

【讨论】:

  • 太棒了,让我试一试。
  • @Dyppl:我搞砸了很多,它仍然导致与 CreateGraphics 相同的问题。我将使用您对我的问题的建议以及一些屏幕截图来添加我的实际更新代码。
  • @Dyppl:我很确定我也按照您期望的方式实现了这一点。如果我遗漏了什么,你能告诉我在哪里吗?您可以在我的编辑中看到代码和图片。
  • @Dyppl:你太棒了。 InvalidateEx 函数为我解决了这个问题。我的动画现在运行并保持透明。非常感谢您的时间和帮助。
  • @Alex:没问题,如果对您有帮助,请随时将答案标记为已接受并欢迎访问该网站!
猜你喜欢
  • 2011-04-11
  • 2023-03-31
  • 2013-01-12
  • 1970-01-01
  • 2013-06-21
  • 2012-07-09
  • 2017-10-15
  • 2010-12-09
  • 2011-04-16
相关资源
最近更新 更多