BigBastis Blog About Me & my Digital Lifestyle

13Jul/101

Windows Aero Glas in eigenen Projekten Nutzen Teil 4 – Formulare ohne Border

Dieses Thema hatten wir hier schon oft, und trotzdem gibt es immer noch was neues zu berichten. Windows Forms Fenster stellen sich ganz schön an wenn es darum geht ihre Steuerelemente und sich selbst richtig darzustellen, zu den Steuerelementen wird bald ein Teil 5 (und hoffentlich der letzte) kommen, hier geht es jetzt erst einmal um das (Boderlose) Formular an sich.

Wenn ihr nämlich mal versucht habt ein Windows Form Formular ohne Border (FormBorderStyle=None) mit der mit Glas-Optik zu nutzen habt ihr wohl innerhalb kürzester Zeit feststellen müssen, dass es nicht geht. Warum ist das so?

Nun, ich denke die meisten von euch benutzen die Win32API Funktion DwmExtendFrameIntoClient um das Fenster in eine Glasscheibe zu verwandeln - was auch vollkommen richtig ist, nur wenn man sich den Namen der Funktion durchließt wird man feststellen, dass deren Aufgabe es ist das Frame (den Rahmen) auf das Formular zu erweitern, was auch super funktioniert, solange man einen Rahmen hat. Stellt man nun aber die Eigenschaft FormBorderStyle auf None, hat die Form keinen Rahmen mehr und dementsprechend kann man diesen auch nicht in die Form erweitern.

Was nun? Es muss doch irgendwie gehen!

Natürlich geht das, dazu müssen wir nur eine andere DWM Funktion aus der Win32API Verwenden, nämlich DwmEnableBlurBehindWindow. Diese Funktion macht genau das selbe, nämlich einen definierten Bereich des Formulars in Glas verwandeln.

Aber diese Funktion bietet noch mehr Spielereien, so kann man auch geometrische Figuren in Glas verwandeln oder nur bestimmte Teile einer Form verglasen. Siehe folgende Bilder:

Bild 1: Ein Paar der Möglichkeiten das Glas zu verteilen. (Natürlich kann man den FormBorderStyle auch auf None stellen, dann würde einfach nur der Rahmen fehlen)

Dazu benötigen wir folgenden Code. 1: Das Befüllen des Fensterinhalts mit Glas:


        //Import der nötigen Funktion aus der DLL
        [System.Runtime.InteropServices.DllImport("dwmapi")]
        private static extern int DwmEnableBlurBehindWindow(
                    System.IntPtr hWnd, ref DWM_BLURBEHIND pBlurBehind);

        //Funktion um ein Rechtek auf dem Formular zu malen
        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        static extern IntPtr CreateRectRgn(int x1, int y1, int x2, int y2);

Wie ihr sehen könnt, ist der Letzte Parameter vom Typ DWM_BLURBEHIND - dies ist ein Struct, welches wir nun erstmal anlegen müssen. (Auf die zweite Funktion komme ich gleich zu sprechen)


        public struct DWM_BLURBEHIND
        {
            public int dwFlags;
            public bool fEnable;
            public System.IntPtr hRgnBlur;//HRGN
            public bool fTransitionOnMaximized;
        }

Nun müssen wir nur noch das Struct anlegen, mit Parametern füllen und der Funktion übergeben:


        private void Form1_Load(object sender, EventArgs e)
        {
            //Das Rechteck vorbereiten, dieses soll so groß sein
            //wie die Fläche die mit Glas befüllt werde soll
            //in diesem Fall soll es die gesamte Form füllen
            hr = CreateRectRgn(0, 0, this.Width, this.Height); 

            //Anlegen des Scructs
            DWM_BLURBEHIND dbb;
            dbb.fEnable = true;
            dbb.dwFlags = 1 | 2;    //Konstanten mehr in der API
            dbb.hRgnBlur = hr;
            dbb.fTransitionOnMaximized = true;

            //Aufruf der Funktion
            DwmEnableBlurBehindWindow(this.Handle, ref dbb);
        }

Zum Schluss sollte man noch dafür sorgen, dass die Form schwarz bemalt wird, damit wir das Glas überhaupt zu Gesicht bekommen. Hierfür überschreiben wir einfach die OnPaintBackground Methode der Form:


        protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
        {
            e.Graphics.FillRectangle(
              new System.Drawing.SolidBrush(System.Drawing.Color.Black),
              this.ClientRectangle);
        }

Das war es auch schon, gar nicht mal so komplex finde ich. Wenn ihr das Rechte Bild aus Bild 1 erzeugen wollt geht ihr genauso vor nur benutzt ihr eine andere Funktion im die Fläche für das Glas anzugeben:


        [System.Runtime.InteropServices.DllImport("gdi32")]
        private static extern System.IntPtr CreateEllipticRgn(
          int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);

Mit dieser Funktion lassen sich Elliptische Figuren malen, um diese zu verwenden einfach die Zuweisungs Zeile ersetzen:


            hr = CreateEllipticRgn(30, 30, 170, 170);

Natürlich kann man auch den Border deaktivieren, um einfach nur die reine Clientoberfläche des Formulars zu bekommen:

Bild 2: Sieht nicht allzu spannend aus

Wie man sieht haben wir nun das was wir wollten, nur hebt das Fenster sich kaum vom Hintergrund ab, obwohl es aktiv ist. Leider können wir dem Formular keinen so schönen Schatten geben wie man es von Windows Vista/7 gewohnt ist, da es keinen Rahmen hat. Wenn man das Formular dennoch etwas hervorheben will, kann man das machen in dem man eine Grafik mit einem Transparentem Verlauf auf der Form platziert und somit den Schatten emuliert, oder man benutzt einen kleinen Trick und weist dem Formular den Schatten der Windows Menüs zu:


        private const int CS_DROPSHADOW = 0x00020000;

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams p = base.CreateParams;
                p.ClassStyle |= CS_DROPSHADOW;
                return p;
            }
        }

Hier überschreiben wir die CreateParams und sagen, dass das Formular einen Schatten werfen soll. Das ganze sieht dann so aus:

Bild 3: Der Schatten hebt das Fenster etwas vom Hintergrund ab

Diesen Schatten sollte man aber mit Vorsicht genießen, denn das ist der Schatten der Windows Menüs. (Der kommt wenn ihr zB. in irgendeinem Programm auf "Datei" klickt, das erscheinende Menü wird diesen Schatten haben.) Diesen kann man in den Einstellungen deaktivieren, also bitte achten dass der folgende Haken gesetzt ist:

Bild 4: Aktivieren der Menüschatten

Soviel dazu, ich hoffe dieser Artikel hat euch gefallen oder konnte euch weiter helfen, wie oben erwähnt werde ich in den nächsten Tagen einen 5en Teil schreiben, in dem es darum geht wie man GDI+ Steuerelemente möglichst gut auf Glas darstellen kann.

Wie gewohnt gibt es hier das Demoprojekt:

Quellen:
Blog von Kenny Kerr
The Code Project

<< Teil 3 des Tutorials | Teil 5 des Tutorials >>

Be Sociable, Share!

    hat dir dieser Artikel gefallen?

    Dann abonniere doch diesen Blog per RSS Feed!

    Get Adobe Flash player