C#透明面板刷新问题

发布于 2024-11-12 16:55:49 字数 4203 浏览 3 评论 0原文

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

我认为有一种简单的方法可以覆盖 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());
        }
    }

以下是对象移动和刷新几次之前和之后的一些图片:

之前

之后

对不起,它除非我有 10 个代表,否则不会让我嵌入图像。

I'm currently working on a project that requires animation on a transparent panel. I have been able to create a transparent panel and draw on it, but when I refresh the panel, where I have drawn with the pen tool is not being redrawn as transparent. This is leaves the last position of what I drew previously stained on the panel.

I assume there is a simple way to override OnPaint or Refresh to redraw all of the pixels on the panel as transparent, but I can't find a solution online or figure it out myself.

Here is the code I used to make the background transparent:

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

    protected override void OnPaintBackground(PaintEventArgs e)
    {
    }
 }

This was my best failed attempt to redraw the background as transparent:

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

The problem with this solution is that the background becomes opaque white after a couple refreshes.

Can anyone help me figure out how to do this? I'm super new to graphics and animation, and I assume this has a fairly simple answer. Thanks in advance.


***EDIT***
As per Dyppl's response I have changed the way I draw the graphics to the panel. Here is my current code:

    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());
        }
    }

Here are some pictures of before and after the object moves and refreshes a few times:

Before

After

Sorry, it won't let me embed the images unless I have 10 Rep.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

难忘№最初的完美 2024-11-19 16:55:49

您不应该使用 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 和我的事件处理程序得到的结果:

Result image

更新:问题是您必须在每个绘制周期开始时调用 Graphics.Clear 方法才能删除所有先前的绘图。它会弄乱你的透明背景。 此链接为您提供一些建议关于这个问题。关键点是您还应该使面板的父控件无效以获得“透明”背景。

因此,我保持 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);
    } 

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

You shouldn't use CreateGraphics for your task. Subscribe to the Paint event of your panel and do all your drawing in the event handler using PaintEventArgs.Graphics as a Graphics object instead.

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

Here's what I got using your TransparentPanel and my event handler:

Result image

UPDATE: The problem is that you have to call Graphics.Clear method in the beginning of every draw cycle in order to get rid of all previous drawings. It will mess up your transparent background. This link gives you some advices regarding the problem. The Key point is that you should invalidate the parent control of your panel as well to get your "transparent" background.

So, I left the code of TransparentPanel untouched but changed the code of main form:

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);
}

Now, whenever I click the button on my form the panel gets redrawn and shows one rectangle in random location. If you invalidate the transparantPanel1 itself, it won't clear and you'll see a mess of red rectangles.


UPDATED (By Alex):
This is the code provided in the link from Dyppl that solved the problem. It just needs to be placed in the transparent panel class:

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

I call this code at every refresh on the panel and it keeps the background transparent.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文