【问题标题】:Circular border around another image is not drawing in winforms另一个图像周围的圆形边框未在winforms中绘制
【发布时间】:2019-03-29 23:18:45
【问题描述】:

我有一个 图片框控件,我已将其制成圆形,现在我正在尝试使用它在其周围画一个红色圆圈:

 Graphics gf = pictureBoxLastLogin1.CreateGraphics();
 gf.DrawEllipse(new Pen(Color.Red, 2), new Rectangle(0, 0, pictureBoxLastLogin1.Width+12, pictureBoxLastLogin1.Height+12));

但它没有在图像周围绘制任何东西?我做错了什么?请记住,我已使用此代码 sn-p 将方形图像转换为圆形图像。

System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
gp.AddEllipse(0, 0, pictureBoxLastLogin.Width , pictureBoxLastLogin.Height);
Region rg = new Region(gp);
pictureBoxLastLogin.Region = rg;

【问题讨论】:

  • 对于持久绘图,请使用 Paint 事件,它是 e.Graphics obejtct。对于非持久性绘图不要使控件无效!
  • paint 事件只触发一次,如果我想改变边框颜色怎么办?
  • 如果您使用 Paint 事件,您应该更改它使用的颜色,然后对控件执行 Invalidate。
  • 永远不要使用 CreateGraphics() 来绘制,你飞溅的像素有一个有限的生命周期。当您在图片框的外部 进行绘制时,必须是父级的 Paint 事件来完成这项工作。确保 pb 的 LocationChanged 和 SizeChanged 事件强制对父级调用 Invalidate()。父级还需要将其 ResizeRedraw 属性设置为 true。显然,当您让 PB 在 PB 内部 绘制边界时,这将更容易进行。
  • 此外,区域不允许抗锯齿,这在低分辨率显示器上往往非常明显。当您使用圆形剪辑自己绘制所有内容时,它看起来会好很多。

标签: c# winforms system.drawing


【解决方案1】:

一旦您使其无效,windows 将重新绘制它,这反过来又会删除您在其上所做的任何绘制。

使用Paint事件,你要在paint事件中绘制的任何东西都会保留在那里。

【讨论】:

    【解决方案2】:

    当我们在 Control 上绘图并且希望绘图持续存在时,我们需要订阅该 Control 的 Paint() 事件。或者,如果它是自定义控件(从现有对象派生的自定义类),则覆盖它的 OnPaint() 方法。

    控制 DC 经常被重绘。当另一个 Window 移到它上面时,当它的 Form 容器被最小化/最大化或调整大小时,如果它触及控制可见区域等等。

    当需要重绘时,会引发 Paint() 事件。
    只有在Paint() 事件处理程序(或OnPaint() 方法)中编码的绘图才会被保留。
    还需要注意的是,大多数使用的对象都实现了IDisposable()
    他们都需要Disposed()。这里是GraphicsPath 对象和绘图Pen
    应用于PicturBoxRegion 也应该被释放。它可以在类范围内声明并在 Form 关闭时释放。

    一个示例,使用(或多或少)问题中使用的相同设置。


    一个 Form 包含一个 PictureBox 和 2 个 Buttons:
    当单击Button1 时,它将为PictureBox 创建一个椭圆形Region
    Button2Invalidate()PictureBox,导致重绘被计划时间>。将引发 Paint() 事件。
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Windows.Forms;
    
    bool PaintBorder = false;
    int RegionInSet = 8;
    
    private void button1_Click(object sender, EventArgs e)
    {
        using (GraphicsPath path = new GraphicsPath())
        {
            path.AddEllipse(RegionInSet, RegionInSet, pictureBox1.Width - (RegionInSet * 2), 
                            pictureBox1.Height - (RegionInSet * 2));
            Region region = new Region(path);
            pictureBox1.Region = region;
        }
    }
    
    private void button2_Click(object sender, EventArgs e)
    {
        PaintBorder = true;
        pictureBox1.Invalidate();
    }
    
    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        if (!PaintBorder) return;
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        e.Graphics.CompositingMode = CompositingMode.SourceOver;
        e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
    
        using (Pen penRed = new Pen(Color.Red, 12))
        {
            int PenRedOffset = (int)(penRed.Width / 2) + (penRed.Width % 2 == 0 ? -1 : 0);
            e.Graphics.DrawEllipse(penRed,
                new RectangleF(RegionInSet + PenRedOffset, RegionInSet + PenRedOffset,
                               pictureBox1.Width - (PenRedOffset * 2) - (RegionInSet * 2),
                               pictureBox1.Height - (PenRedOffset * 2) - (RegionInSet * 2)));
        }
    }
    

    视觉效果:

    【讨论】:

    • 感谢您的回答,但我可以将您的绘画事件逻辑更改为这条简单的行。 e.Graphics.DrawEllipse(new Pen(Color.Red, 10), 0, 0, pictureBox.Width, pictureBox.Height);
    • @Muhammad Faizan Khan 不,你不能 :) (new Pen(Color.Red, 10) Pen 是一个 Graphics 对象。它需要被隐式处理(调用.Dispose())或隐式处理(将其包装在using 语句中)。您想要使用它的方式是,每次引发Paint() 时(很多次),您都会泄漏GDI 资源。 3) Graphics.DrawEllipse() 在矩形边界的内侧和一半外侧绘制边框。你会损失一半。
    • @Muhammad Faizan Khan 4) 假设您需要更薄的框架。如果你打算放弃这个地区,你会怎么做?如果位图变大了怎么办?还是屏幕 DPI 变化?简单的 DrawEllipse 如何适应这些变化。好吧,它不会。
    猜你喜欢
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-31
    相关资源
    最近更新 更多