在扩展玻璃框架中绘制文本框(不使用 WPF)

发布于 2024-09-03 14:44:55 字数 3124 浏览 3 评论 0原文

我正在尝试在表单的扩展玻璃框架上绘制一个文本框。我不会描述这个技术,它是众所周知的。对于那些还没有听说过的人来说,这是一个示例: http:// /www.danielmoth.com/Blog/Vista-Glass-In-C.aspx

问题是,在这个玻璃框架上绘图很复杂。由于黑色被认为是 0-alpha 颜色,因此任何黑色都会消失。

显然有一些方法可以解决这个问题:绘制复杂的 GDI+ 形状不受这种 alpha 的影响。例如,此代码可用于在玻璃上绘制标签(注意:使用 GraphicsPath 代替 DrawString 是为了解决可怕的 ClearType 问题):

public class GlassLabel : Control
{
    public GlassLabel()
    {
        this.BackColor = Color.Black;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        GraphicsPath font = new GraphicsPath();

        font.AddString(
            this.Text,
            this.Font.FontFamily,
            (int)this.Font.Style,
            this.Font.Size,
            Point.Empty,
            StringFormat.GenericDefault);

        e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
        e.Graphics.FillPath(new SolidBrush(this.ForeColor), font);
    }
}

同样,这种方法可用于在玻璃区域上创建容器。请注意使用多边形而不是矩形 - 使用矩形时,其黑色部分被视为 Alpha。

public class GlassPanel : Panel
{
    public GlassPanel()
    {
        this.BackColor = Color.Black;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        Point[] area = new Point[]
            {
                new Point(0, 1),
                new Point(1, 0),
                new Point(this.Width - 2, 0),
                new Point(this.Width - 1, 1),
                new Point(this.Width -1, this.Height - 2),
                new Point(this.Width -2, this.Height-1),
                new Point(1, this.Height -1),
                new Point(0, this.Height - 2)
            };

        Point[] inArea = new Point[]
            {
                new Point(1, 1),
                new Point(this.Width - 1, 1),
                new Point(this.Width - 1, this.Height - 1),
                new Point(this.Width - 1, this.Height - 1),
                new Point(1, this.Height - 1)
            };

        e.Graphics.FillPolygon(new SolidBrush(Color.FromArgb(240, 240, 240)), inArea);
        e.Graphics.DrawPolygon(new Pen(Color.FromArgb(55, 0, 0, 0)), area);

        base.OnPaint(e);
    }
}

现在我的问题是:如何绘制文本框? 经过大量谷歌搜索后,我想出了以下解决方案:

  • 子类化 TextBox 的 OnPaint 方法。这是可能的,尽管我无法让它正常工作。它应该涉及画一些我还不知道怎么做的神奇的东西。
  • 制作我自己的自定义 TextBox,可能在 TextBoxBase 上。如果有人有好的、有效且可行的示例,并且认为这可能是一个很好的整体解决方案,请告诉我。
  • 使用BufferedPaintSetAlpha。 (http://msdn.microsoft.com/en-us/library/ms649805 .aspx)。这种方法的缺点可能是文本框的角可能看起来很奇怪,但我可以忍受。如果有人知道如何从 Graphics 对象正确实现该方法,请告诉我。我个人不喜欢,但这似乎是迄今为止最好的解决方案。老实说,我发现了一篇很棒的 C++ 文章,但我懒得转换它。 http:// weblogs.asp.net/kennykerr/archive/2007/01/23/controls-and-the-desktop-window-manager.aspx

注意:如果我成功使用 BufferedPaint 方法,我发誓 s/o我将制作一个简单的 DLL,其中包含可在玻璃上绘制的所有常见 Windows 窗体控件。

I am trying to draw a TextBox on the extended glass frame of my form. I won't describe this technique, it's well-known. Here's an example for those who haven't heard of it: http://www.danielmoth.com/Blog/Vista-Glass-In-C.aspx

The thing is, it is complex to draw over this glass frame. Since black is considered to be the 0-alpha color, anything black disappears.

There are apparently ways of countering this problem: drawing complex GDI+ shapes are not affected by this alpha-ness. For example, this code can be used to draw a Label on glass (note: GraphicsPath is used instead of DrawString in order to get around the horrible ClearType problem):

public class GlassLabel : Control
{
    public GlassLabel()
    {
        this.BackColor = Color.Black;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        GraphicsPath font = new GraphicsPath();

        font.AddString(
            this.Text,
            this.Font.FontFamily,
            (int)this.Font.Style,
            this.Font.Size,
            Point.Empty,
            StringFormat.GenericDefault);

        e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
        e.Graphics.FillPath(new SolidBrush(this.ForeColor), font);
    }
}

Similarly, such an approach can be used to create a container on the glass area. Note the use of the polygons instead of the rectangle - when using the rectangle, its black parts are considered as alpha.

public class GlassPanel : Panel
{
    public GlassPanel()
    {
        this.BackColor = Color.Black;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        Point[] area = new Point[]
            {
                new Point(0, 1),
                new Point(1, 0),
                new Point(this.Width - 2, 0),
                new Point(this.Width - 1, 1),
                new Point(this.Width -1, this.Height - 2),
                new Point(this.Width -2, this.Height-1),
                new Point(1, this.Height -1),
                new Point(0, this.Height - 2)
            };

        Point[] inArea = new Point[]
            {
                new Point(1, 1),
                new Point(this.Width - 1, 1),
                new Point(this.Width - 1, this.Height - 1),
                new Point(this.Width - 1, this.Height - 1),
                new Point(1, this.Height - 1)
            };

        e.Graphics.FillPolygon(new SolidBrush(Color.FromArgb(240, 240, 240)), inArea);
        e.Graphics.DrawPolygon(new Pen(Color.FromArgb(55, 0, 0, 0)), area);

        base.OnPaint(e);
    }
}

Now my problem is: How can I draw a TextBox?
After lots of Googling, I came up with the following solutions:

  • Subclassing the TextBox's OnPaint method. This is possible, although I could not get it to work properly. It should involve painting some magic things I don't know how to do yet.
  • Making my own custom TextBox, perhaps on a TextBoxBase. If anyone has good, valid and working examples, and thinks this could be a good overall solution, please tell me.
  • Using BufferedPaintSetAlpha. (http://msdn.microsoft.com/en-us/library/ms649805.aspx). The downsides of this method may be that the corners of the textbox might look odd, but I can live with that. If anyone knows how to implement that method properly from a Graphics object, please tell me. I personally don't, but this seems the best solution so far. To be honest, I found a great C++ article, but I am way too lazy to convert it. http://weblogs.asp.net/kennykerr/archive/2007/01/23/controls-and-the-desktop-window-manager.aspx

Note: If I ever succeed with the BufferedPaint methods, I swear to s/o that I will make a simple DLL with all the common Windows Forms controls drawable on glass.

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

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

发布评论

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

评论(1

白色秋天 2024-09-10 14:44:55

不久前我花了一些时间讨论这个话题。基本上你需要的是一个透明的文本框。我最初的方法是使用 codeproject AlphaBlendTextBox - .NET 的透明/半透明文本框。但我在该控制方面遇到了一些难以解决的问题。一段时间后,我找到了所需的解决方案,它仅适用于 Windows XP 及更高版本。为了使该控件的行为类似于单行文本框,请将 RichTextBox.Multiline 设置为 false。

// Source:
// http://www.dotnetjunkies.com/WebLog/johnwood/archive/2006/07/04/transparent_richtextbox.aspx

// It seems there are 4 versions of the RichEdit control out there - when I'm talking about the 
// RichEdit control, I'm talking about the C DLL that either comes with Windows or some version 
// of Office. The files are named either RICHEDXX.DLL (XX is the version number), or MSFTEDIT.DLL 
// and they're in the System32 folder.

// .Net RichTextBox control is bound to version 2. The biggest problem with this version (at least 
// for me) is that it does not render properly if you try to make the window transparent. Later versions, 
// however, do.

// We can fix that. If you create a control deriving from the original RichTextBox control, but overriding 
// the CreateParams property, you can put in a new Windows class name (this is the window class name, 
// nothing to do with classes in the C# sense). This effectively gives us a free upgrade. When the .Net 
// RichTextBox control instantiates, it will now use the latest RichEdit control and not the old, archaic, 
// version 2.

// There are other benefits too - version 3 and beyond of the RichEdit control support quite an extensive 
// array of layout features, such as tables and full text justification. This is the version of the RichEdit 
// that WordPad uses in Windows XP. To really see what it's capable of displaying you can create documents in 
// Word and save them in RTF, load these into the new RichEdit and in a lot of cases it'll look identical, 
// it's that powerful. A full list of features can be found here:
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/richedit/richeditcontrols/aboutricheditcontrols.asp

// There are a couple of caveats:
// 
// 1. The control that this is bound to was shipped with Windows XP, and so this code won't work in 
//    Windows 2000 or earlier. 
//
// 2. The RichTextBox control in C# only knows about version 2, so the interface doesn't include 
//    all the new features. You can wrap a few of the features yourself through new methods on the 
//    RichEdit class.

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

internal class RichEdit : RichTextBox
{

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr LoadLibrary(string lpFileName);

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams parameters = base.CreateParams;
            if (LoadLibrary("msftedit.dll") != IntPtr.Zero)
            {
                parameters.ExStyle |= 0x020; // transparent
                parameters.ClassName = "RICHEDIT50W";
            }
            return parameters;
        }
    }
}

I have spent some time on this topic a while ago. Basically what you need is a transparent textbox. My initial approach was to use codeproject AlphaBlendTextBox - A transparent/translucent textbox for .NET. But I was having a few difficult to solve issues with that control. After a while I have found required solution, it will work only on Windows XP and up. As well to get this control to behave like single line text box set RichTextBox.Multiline to false.

// Source:
// http://www.dotnetjunkies.com/WebLog/johnwood/archive/2006/07/04/transparent_richtextbox.aspx

// It seems there are 4 versions of the RichEdit control out there - when I'm talking about the 
// RichEdit control, I'm talking about the C DLL that either comes with Windows or some version 
// of Office. The files are named either RICHEDXX.DLL (XX is the version number), or MSFTEDIT.DLL 
// and they're in the System32 folder.

// .Net RichTextBox control is bound to version 2. The biggest problem with this version (at least 
// for me) is that it does not render properly if you try to make the window transparent. Later versions, 
// however, do.

// We can fix that. If you create a control deriving from the original RichTextBox control, but overriding 
// the CreateParams property, you can put in a new Windows class name (this is the window class name, 
// nothing to do with classes in the C# sense). This effectively gives us a free upgrade. When the .Net 
// RichTextBox control instantiates, it will now use the latest RichEdit control and not the old, archaic, 
// version 2.

// There are other benefits too - version 3 and beyond of the RichEdit control support quite an extensive 
// array of layout features, such as tables and full text justification. This is the version of the RichEdit 
// that WordPad uses in Windows XP. To really see what it's capable of displaying you can create documents in 
// Word and save them in RTF, load these into the new RichEdit and in a lot of cases it'll look identical, 
// it's that powerful. A full list of features can be found here:
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/richedit/richeditcontrols/aboutricheditcontrols.asp

// There are a couple of caveats:
// 
// 1. The control that this is bound to was shipped with Windows XP, and so this code won't work in 
//    Windows 2000 or earlier. 
//
// 2. The RichTextBox control in C# only knows about version 2, so the interface doesn't include 
//    all the new features. You can wrap a few of the features yourself through new methods on the 
//    RichEdit class.

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

internal class RichEdit : RichTextBox
{

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr LoadLibrary(string lpFileName);

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams parameters = base.CreateParams;
            if (LoadLibrary("msftedit.dll") != IntPtr.Zero)
            {
                parameters.ExStyle |= 0x020; // transparent
                parameters.ClassName = "RICHEDIT50W";
            }
            return parameters;
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文