【问题标题】:draw filled circle in WinForms C#在 WinForms C# 中绘制实心圆
【发布时间】:2019-01-21 01:26:45
【问题描述】:

我有一个与连接交互的 WinForms 应用程序。如果连接正常,我想显示一个绿色(“一切正常”)实心圆圈,否则我想显示一个红色实心圆圈。

我在工具箱中没有找到圆形元素,所以我想我必须自己绘制它。

我创建了一个名为picBoxClientState 的图片框并从这段代码开始

public partial class FrmMain : Form
{
    public void CheckSignedInState()
    {
        // some other code

        DrawClientStateIcon(client.IsSignedIn);
    }

    private void DrawClientStateIcon(bool isSignedIn)
    {
        Point rectangleLocation = picBoxClientState.Location;
        Size rectangleSize = picBoxClientState.Size;
        Rectangle rectangle = new Rectangle(rectangleLocation, rectangleSize);

        Color iconColor = isSignedIn ? Color.Green : Color.Red;
        SolidBrush iconBrush = new SolidBrush(iconColor);

        Graphics graphics = picBoxClientState.CreateGraphics();
        graphics.FillEllipse(iconBrush, rectangle);
    }
}

当我打电话给CheckSignedInState() 时,如何在这个图片框上画画?

也许有更好的方法来代替绘图? (我不想切换两个图像,因为可能需要绘制更多状态)

【问题讨论】:

  • 您可以使用power pack 轻松创建椭圆形
  • 对不起,我只是想在这个画框上画画。尽管调试器到达了这段代码,但上面没有绘制任何内容。
  • 永远不要使用 CreateGraphics() 来绘制。 iconColor 变量必须是类的一个字段。使用 pb 的 Paint 事件进行绘制。当您更改 iconColor 时,然后调用 pb 的 Invalidate() 方法使其重新绘制。
  • 所以如果我想再画一次,我就打电话给Invalidate()?
  • 是的。更改绘制时使用的数据,并在应该绘制的控件上调用 Invalidate。

标签: c# winforms graphics gdi+ picturebox


【解决方案1】:

使用Label 控件绘制椭圆的简单示例。
您可以使用任何具有Paint event 的控件来绘制形状。
也可以是PanelPictureBoxButton...

在 Class 范围内声明的 bool 变量 (clientIsSignedIn) 用于跟踪当前状态,正如您的 client.IsSignedIn 值所报告的那样。

当状态改变时,更新clientIsSignedInInvalidate() 提供视觉帮助的控件。

bool clientIsSignedIn = false;

public void CheckSignedInState()
{
    // some other code
    clientIsSignedIn = client.IsSignedIn;
    lblVisualStatus.Invalidate();
}

private void lblVisualStatus_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    e.Graphics.FillEllipse((clientIsSignedIn) ? Brushes.Green : Brushes.Red, ((Control)sender).ClientRectangle);
}

【讨论】:

    【解决方案2】:

    我不认为图片框是必需的。你可以试试这样:

    private void button1_Click(object sender, EventArgs e)
    {
        System.Drawing.SolidBrush myBrush = new 
        System.Drawing.SolidBrush(System.Drawing.Color.Red);
        System.Drawing.Graphics formGraphics;
        formGraphics = this.CreateGraphics();
        formGraphics.FillEllipse(myBrush, new Rectangle(200, 200, 30, 30));
        myBrush.Dispose();
        formGraphics.Dispose();
    }
    

    如果你需要在picturebox上绘图,一定要调用picturebox.Invalidate();

    【讨论】:

    • 你不能在表单的 Load() 方法中调用它,你需要从一个按钮调用它。
    • 但是为什么呢?区别在哪里?我只是调用一个方法,不是吗?
    • 当表单使用 Load() 时,它会在一段时间后重新绘制/无效/绘制,这是您丢失有关您的圈子的信息的地方。为了防止这种情况,您需要在 Paint 事件中绘制您的圆圈。检查这个:Paint
    • 这对我很有效。使用 FillEllipse 并传递一个 Brush。 (相对于 DrawEllipse 和传递一支笔,它只制作一个空心椭圆)。我使用了绘制事件,使用了 (PaintEventArgs e),并做了 e.Graphics.FillEllipse 等。
    【解决方案3】:

    您的代码有效,但它似乎确实有点偏离中心,但您没有处理对象的事实也可能导致问题。尝试使用下面的代码作为您的 DrawClientStateIcon 方法

    编辑:下面的完整代码示例。我添加了一个按钮来切换客户端的状态,这对我有用。

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp1
    {
        public partial class Form1 : Form
        {
            public class Client
            {
                public bool IsSignedIn { get; set; }
            }
    
            Client client = new Client()
            {
                IsSignedIn = false
            };
    
            public Form1()
            {
                InitializeComponent();
            }
    
            public void CheckSignedInState()
            {
                // some other code
    
                DrawClientStateIcon(client.IsSignedIn);
            }
    
            private void DrawClientStateIcon(bool isSignedIn)
            {
                Point rectangleLocation = picBoxClientState.Location;
                Size rectangleSize = picBoxClientState.Size;
                Rectangle rectangle = new Rectangle(rectangleLocation, new Size(rectangleSize.Width / 2, rectangleSize.Height / 2));
    
                Color iconColor = isSignedIn ? Color.Green : Color.Red;
    
                using (SolidBrush iconBrush = new SolidBrush(iconColor))
                {
                    using (Graphics graphics = picBoxClientState.CreateGraphics())
                    {
                        graphics.FillEllipse(iconBrush, rectangle);
                    }
                }
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                client.IsSignedIn = !client.IsSignedIn;
                CheckSignedInState();
            }
        }
    }
    

    【讨论】:

    • 嗯不抱歉,什么都没有画出来
    • 你确定你的代码被命中了吗?我尝试了您的代码,它对我使用按钮切换客户端登录状态很有用,我将编辑我的代码以显示完整示例
    • 是的,调试器命中了代码行。我将在一个新项目中尝试您的代码 sn-p 可能缺少某些东西
    • 我刚刚在一个新项目中测试了你的代码。我在表单上放置了一个按钮和一个图片框并复制粘贴了您的代码。调试器到达代码行但没有绘制任何内容。
    • 从 OP (CreateGraphics) 重复错误没有帮助 Hans 的建议就是所需要的。我认为你应该删除这个误导性的答案!
    【解决方案4】:

    您需要在 Form Shown 事件中调用它。

            private void FrmGraphics_Shown(object sender, EventArgs e)
            {
                DrawClientStateIcon(true);
            }
            private void DrawClientStateIcon(bool isSignedIn)
            {
                Point rectangleLocation = picBoxClientState.Location;
                Size rectangleSize = picBoxClientState.Size;
                Rectangle rectangle = new Rectangle(rectangleLocation, rectangleSize);
    
                Color iconColor = isSignedIn ? Color.Green : Color.Red;
                SolidBrush iconBrush = new SolidBrush(iconColor);
    
                Graphics graphics = base.CreateGraphics();
                graphics.FillEllipse(iconBrush, rectangle);
            }
    

    【讨论】:

    • 从 OP (CreateGraphics) 重复错误没有帮助 Hans 的建议就是所需要的。我认为你应该删除这个误导性的答案!
    • 为什么会误导?它是上述问题的有效解决方案。没看到使用的 _Shown 方法吗?
    • 甚至必须查看Shown 的定义:在表单首次显示时发生。 这意味着它只会工作一次。永远不要将 control.CreateGraphics 用于意味着 tp ersist 的图形!
    • 通过 CreateGraphics 方法检索到的 Graphics 对象通常不应在处理当前 Windows 消息后保留,因为使用该对象绘制的任何内容都将在下一条 WM_PAINT 消息中删除。因此,您不能缓存 Graphics 对象以供重用,除非使用像 Graphics.MeasureString 这样的非可视方法。相反,您必须在每次要使用 Graphics 对象时调用 CreateGraphics,然后在使用完毕后调用 Dispose。
    • 嗯,确实。所以使用它是一个错误。汉斯的评论和吉米的回答是对的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 2013-11-08
    • 1970-01-01
    相关资源
    最近更新 更多