【问题标题】:Using C# Pens and Brushes in WinApi?在 WinApi 中使用 C# 笔和画笔?
【发布时间】:2014-04-09 05:15:12
【问题描述】:

如何从Brush 获得HBRUSH 和从Pen 获得HPEN
我想知道这两者之间有什么联系吗?

(我想使用 .NET's System.Drawing 中未实现的 WinApi 函数,例如 DrawRoundRect/CreateRoundRectRgn,并且我想使用 .NET 中的画笔,而不是自己创建它们。)

【问题讨论】:

    标签: c# winforms winapi gdi


    【解决方案1】:

    Brush 类确实有一个名为 nativeBrush 的私​​有字段,它将 HBRUSH 句柄保存为 IntPtr。

    因为它是一个私有字段,它可能会随着对 .Net 的任何修订而改变,但如果你不介意使用一些狡猾、脆弱的反射来获得它的价值,你可以做一些像这样令人讨厌的事情:

    Brush brush = ...the brush that you want to get at the handle for
    FieldInfo field = typeof(Brush).GetField("nativeBrush",BindingFlags.NonPublic|BindingFlags.Instance);
    IntPtr hbrush = (IntPtr)field.GetValue(brush);
    

    Pen 有一个类似的字段nativePen,您可以使用类似的反射代码访问它。

    但是,如果您可以使用上面 Don 所示的 GraphicsPath,那么风险会小得多。

    也可以查看this article on creating rounded rectangles using GraphicsPath

    【讨论】:

    • 我找到了hbrush 值,它看起来像是一个有效的指针地址,但我无法让 WinApi 用我画笔中的颜色填充任何内容。 .NET 可以正确填写。
    【解决方案2】:

    我不再有原始来源,甚至可能是一个 SO 项目。无论如何,这是我使用的不久前有人提供的课程:

    /// <summary>
    /// Collection of often-used classes and methods for easy access.
    /// </summary>
    public class RoundedDrawing
    {
        private static GraphicsPath GetRoundedRectanglePath(Int32 x, Int32 y, Int32 width, Int32 height, Int32 radius)
        {
            GraphicsPath path = new GraphicsPath();
            path.AddLine(x + radius, y, x + width - radius, y);
            if (radius > 0)
                path.AddArc(x + width - 2 * radius, y, 2 * radius, 2 * radius, 270.0f, 90.0f);
            path.AddLine(x + width, y + radius, x + width, y + height - radius);
            if (radius > 0)
                path.AddArc(x + width - 2 * radius, y + height - 2 * radius, 2 * radius, 2 * radius, 0.0f, 90.0f);
            path.AddLine(x + width - radius, y + height, x + radius, y + height);
            if (radius > 0)
                path.AddArc(x, y + height - 2 * radius, 2 * radius, 2 * radius, 90.0f, 90.0f);
            path.AddLine(x, y + height - radius, x, y + radius);
            if (radius > 0)
                path.AddArc(x, y, 2 * radius, 2 * radius, 180.0f, 90.0f);
            return path;
        }
    
        /// <summary>
        /// Fills the interior of a rounded rectangle.
        /// </summary>
        public static void FillRoundedRectangle(Graphics graphics, Brush brush, float x, float y, float width, float height, float radius)
        {
            FillRoundedRectangle(graphics, brush, (Int32)x, (Int32)y, (Int32)width, (Int32)height, (Int32)radius);
        }
    
        /// <summary>
        /// Fills the interior of a rounded rectangle.
        /// </summary>
        public static void FillRoundedRectangle(Graphics graphics, Brush brush, Rectangle rect, Int32 radius)
        {
            FillRoundedRectangle(graphics, brush, rect.Left, rect.Top, rect.Width, rect.Height, radius);
        }
    
        /// <summary>
        /// Fills the interior of a rounded rectangle.
        /// </summary>
        public static void FillRoundedRectangle(Graphics graphics, Brush brush, RectangleF rect, float radius)
        {
            FillRoundedRectangle(graphics, brush, (Int32)rect.Left, (Int32)rect.Top, (Int32)rect.Width, (Int32)rect.Height, (Int32)radius);
        }
    
        /// <summary>
        /// Fills the interior of a rounded rectangle.
        /// </summary>
        public static void FillRoundedRectangle(Graphics graphics, Brush brush, Int32 x, Int32 y, Int32 width, Int32 height, Int32 radius)
        {
            using (GraphicsPath path = GetRoundedRectanglePath(x, y, width, height, radius))
                graphics.FillPath(brush, path);
        }
    
        /// <summary>
        /// Draws the outline of a rounded rectangle.
        /// </summary>
        public static void DrawRoundedRectangle(Graphics graphics, Pen pen, float x, float y, float width, float height, float radius)
        {
            DrawRoundedRectangle(graphics, pen, (Int32)x, (Int32)y, (Int32)width, (Int32)height, (Int32)radius);
        }
    
        /// <summary>
        /// Draws the outline of a rounded rectangle.
        /// </summary>
        public static void DrawRoundedRectangle(Graphics graphics, Pen pen, Rectangle rect, Int32 radius)
        {
            DrawRoundedRectangle(graphics, pen, rect.Left, rect.Top, rect.Width, rect.Height, radius);
        }
    
        /// <summary>
        /// Draws the outline of a rounded rectangle.
        /// </summary>
        public static void DrawRoundedRectangle(Graphics graphics, Pen pen, RectangleF rect, float radius)
        {
            DrawRoundedRectangle(graphics, pen, (Int32)rect.Left, (Int32)rect.Top, (Int32)rect.Width, (Int32)rect.Height, (Int32)radius);
        }
    
        /// <summary>
        /// Draws the outline of a rounded rectangle.
        /// </summary>
        public static void DrawRoundedRectangle(Graphics graphics, Pen pen, Int32 x, Int32 y, Int32 width, Int32 height, Int32 radius)
        {
            using (GraphicsPath path = GetRoundedRectanglePath(x, y, width, height, radius))
                graphics.DrawPath(pen, path);
        }
    }
    

    只需在您收到Graphics 对象的任何PaintPaintBackground 事件中进行调用。将它与其他任何东西一起传递,并绘制圆形的东西。

    可以选择将其全部保存在 .NET 中,无需外部 P/Invokes。

    【讨论】:

    • 这是我现在所追求的一个很好的替代方案。但这不能是这个问题的答案(关于刷子和手柄)。谢谢分享!
    • 我想我想说的是,为什么要走 P/invoke 路线?似乎没有更好的结果需要很多额外的麻烦。更聪明地工作,而不是更努力地工作?
    • 对我来说“取消调用”我的项目为时已晚。我有一个为我导入 WinApi 的大库。我通过导入 lib 来启动一个新项目。但是你的回答很好,帮助了我。这不是我要求的。 :)
    猜你喜欢
    • 2010-09-30
    • 1970-01-01
    • 2021-08-15
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    • 1970-01-01
    • 2011-04-30
    • 1970-01-01
    相关资源
    最近更新 更多