Рисование текстового поля в расширенной стеклянной рамке без WPF

Я пытаюсь нарисовать TextBox на расширенной стеклянной рамке моей формы. Описывать эту технику не буду, она всем известна. Вот пример для тех, кто об этом не слышал: http://www.danielmoth.com/Blog/Vista-Glass-In-C.aspx

Дело в том, что нарисовать эту стеклянную раму сложно. Поскольку черный считается цветом 0-альфа, все черное исчезает.

Очевидно, есть способы решения этой проблемы: на рисование сложных форм GDI + эта альфа не влияет. Например, этот код можно использовать для рисования метки на стекле (примечание: 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);
    }
}

Точно так же такой подход можно использовать для создания тары на площади стекла. Обратите внимание на использование многоугольников вместо прямоугольника - при использовании прямоугольника его черные части считаются альфа-каналом.

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? После долгих поисков в Google я пришел к следующим решениям:

  • Создание подкласса метода OnPaint TextBox. Это возможно, хотя мне не удалось заставить его работать должным образом. Это должно включать в себя рисование некоторых волшебных вещей, которые я еще не умею делать.
  • Делаю свой собственный 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, клянусь, что я сделаю простую DLL со всеми стандартными элементами управления Windows Forms, которые можно рисовать на стекле.


person Lazlo    schedule 29.05.2010    source источник
comment
Ответил себе в другом потоке: stackoverflow.com/questions/7061531/   -  person Lazlo    schedule 12.01.2012


Ответы (1)


Некоторое время назад я потратил некоторое время на эту тему. В основном вам нужно прозрачное текстовое поле. Мой первоначальный подход заключался в использовании кода проекта 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;
        }
    }
}
person volody    schedule 29.05.2010
comment
Это полностью прозрачно в стекле - бесполезно. Я скорее надеялся на что-нибудь непрозрачное. - person Lazlo; 01.06.2010
comment
@Lazlo вы можете поставить любой градиентный фон позади - person volody; 01.06.2010