11 Stimmen

DwmExtendFrameIntoClientArea ohne Aero Glass

Die Verwendung des DwmExtendFrameIntoClientArea Der API-Aufruf mit aktiviertem Aero Glass funktioniert einwandfrei. Ich möchte jedoch, dass es auch funktioniert, wenn Aero Glass deaktiviert ist, so wie es in der Windows-Systemsteuerung funktioniert:

enter image description here

Haben Sie bemerkt, dass der Rahmen in den Clientbereich hineinragt, obwohl Aero Glass deaktiviert ist? Wenn ich die DwmExtendFrameIntoClientArea API-Aufruf in meiner Anwendung ist der zurückgegebene HRESULT definitiv kein Erfolg, und meine Anwendung sieht dann so aus:

http://img197.imageshack.us/img197/9629/clientapplication.png

Normalerweise erstreckt sich der Rahmen bei aktiviertem Aero Glass bis unter die Navigationsschaltflächen, wie in der Systemsteuerung. Wie kann ich das tun? DwmExtendFrameIntoClientArea funktioniert eindeutig nicht.

Übrigens, wenn es relevant ist, ist meine Anwendung eine WPF-Anwendung.

7voto

Ian Boyd Punkte 232380

Die Antwort von Nir ist richtig; wenn die Komposition deaktiviert ist, müssen Sie den Bereich selbst zeichnen.

Ich kann Ihnen den Code zeigen, den ich im Paint-Handler des Panels am oberen Rand meines Formulars habe - das Panel, das normalerweise für das Zeichnen des transparenten schwarzen 0x00000000 verantwortlich ist, um das Glas erscheinen zu lassen:

Psuedo-Code:

procedure DrawGlassHeaderArea(g: Graphics; r: Rectangle; IsFormFocused: Boolean);
const
   clFakeGlassColor = $00EAD1B9;  //(185, 209, 234) This is the fake foreground glass color (for use when composition is disabled)
   clFakeGlassColorUnfocused = $00F2E4D7; //(215, 228, 242) This is the fake background glass color (for use when composition is disabled)
begin
   if Dwm.IsCompositionEnabled then
   begin
      g.FillRectangle(r, 0x00000000); //fill rectangle with transparent black
   end
   else
      //Composition disabled; fake it like Microsoft does

      //The color to use depends if the form has focused or not
      Color glassColor;
      if (IsFormFocused) then
         c = clFakeGlassColor 
      else
         c = clFakeGlassColorUnfocused;

      g.FillRectangle(r, glassColor); //fill rectangle with fake color

      //Now we have to draw the two accent lines along the bottom
      Color edgeHighlight = ColorBlend(Colors.White, glassColor, 0.33); //mix 33% of glass color to white
      Color edgeShadow = ColorBlend(Colors.Black, glassColor, 0.33); //mix 33% of glass color to black

      //Draw highlight as 2nd-last row:
      g.DrawLine(edgeHighlight, Point(r.Left, r.Bottom-2), Point(r.Right, r.Bottom-2);

      //Draw shadow on the very last row:
      g.DrawLine(edgeHighlight, Point(r.Left, r.Bottom-1), Point(r.Right, r.Bottom-1);
   end;
end;

Beispielhafte Verwendung

procedure MyForm.PaintBox1Paint(PaintEventArgs e)
begin
   DrawGlassHeaderArea(e.Graphics, PaintBox1.ClientRectangle, this.HasFocus); 
end;

Bonus-Screenshot

enter image description here

Aktualisierung 7/9/2014

@JakePetroules hatte Recht, und ich hatte Unrecht. Die "blau" für unechtes Glas verwendet wird, ist no in Windows fest einprogrammiert. Und es es erreichbar über GetThemeColor .

Ich habe alle verfügbaren Farben kodiert ( TMT_COLOR ) verfügbar für eine Fenster Klasse:

enter image description here

Anmerkung: Weitere Informationen über Klassen, Teile und Staaten finden Sie unter Aero-Style-Klassen, Teile und Staaten

Bei Verwendung:

  • Klasse : Window
  • Teil : WP_CAPTION
  • Staat : n/a (StateID wird nicht für die Bildunterschrift Teil, noch die gesamte Fenster Klasse)

und holen Sie den Farbcode propertyID :

  • TMT_FILLCOLORHINT Wenn das Fenster den Fokus hat
  • TMT_BORDERCOLORHINT für den Fall, dass das Fenster nicht den Fokus hat

erhalten Sie die beiden wichtigsten Farben:

enter image description here

Der Pseudocode, den ich jetzt verwende, um die falsche Glasfarbe zu erhalten:

public Color GetFakeClassColor(Boolean isWindowFocused=true)
{
   static Color fakeGlass= 0x00B8D0E9; //the correct answer anyway

   if ((GetThemeAppProperties() && STAP_ALLOW_CONTROLS) == 0)
      return fakeGlass;

   hTheme = OpenThemeData(GetDesktopWindow(), "Window");
   if (hTheme = 0)
      return fakeGlass;

   Int32 propID;
   if (isWindowFocused)
       propID= TMT_FILLCOLORHINT; //The color used as a fill color hint for custom controls.
   else
       propID= TMT_BORDERCOLORHINT; //The color used as a border color hint for custom controls.

   DWORD rgb;
   if (Failed(GetThemeColor(hTheme, WP_CAPTION, 0, propID, ref rgb))
      return fakeGlass;

   Result = new Color(rgb);
}

In der Realität, da ich Delphi verwende, ist mein tatsächlicher Code:

function GetFakeGlassColor(IsWindowFocused: Boolean=True): TColor;
var
    ted: TThemedElement;
    hTheme: THandle;
    propID: Integer;
    rgb: DWORD;
begin
    Result := $00B8D0E9; //the correct answer anyway

    //We can't use the ThemeServcies.ThemesEnabled, as that mistakenly checks for version 6 of the common controls library
    //Themes can be enabled without using ComCtl V6, or common controls at all
    if not ThemeServices.ThemesAvailable then
        Exit;
    if (GetThemeAppProperties and STAP_ALLOW_CONTROLS) = 0 then
        Exit;

    htheme := ThemeServices.Theme[teWindow];
    if hTheme = 0 then
        Exit;

    if IsWindowFocused then
        propID := TMT_FILLCOLORHINT //The color used as a fill color hint for custom controls.
    else
        propID := TMT_BORDERCOLORHINT; //The color used as a border color hint for custom controls.

    if Failed(GetThemeColor(hTheme, WP_CAPTION, 0, propID, {var}rgb)) then
        Exit;

    Result := rgb;
end;

2voto

Nir Punkte 28685

Sie müssen es selbst so bemalen, dass es wie ein Rahmen aussieht.

Sie müssen Folgendes verwenden DwmIsCompositionEnabled um zu prüfen, ob der DWM aktiviert ist und die WM_DWMCOMPOSITIONCHANGED um eine Änderung des DWM-Status zu erkennen.

Dann müssen Sie das Fenster auf eine andere Weise zeichnen, wenn DWM aktiviert ist, verwenden Sie DwmExtendFrameIntoClientArea Wenn diese Funktion deaktiviert ist, zeichnen Sie den "Rahmen" selbst.

Ich habe keine Ahnung, wie ich den Aero-Rahmen in WPF duplizieren kann (in meiner Anwendung habe ich mein eigenes Farbschema und verwende nicht den Auro-Rahmen).

Das ist ärgerlich, aber wenn der DWM deaktiviert ist, fällt das System auf den XP-Stil zurück und keiner der DWM-Dienste funktioniert - auch nicht die, die nicht mit dem Glaseffekt zusammenhängen.

2voto

Jake Petroules Punkte 22542

Sie müssen den Hintergrund des Fensters selbst streichen. Sie sollten die Farben nicht hart kodieren, wie es in früheren Beiträgen vorgeschlagen wurde, sondern die Funktionen des Themas verwenden, um sie abzurufen, etwa so (Semi-Pseudocode):

DWORD rgb;
HANDLE hTheme = OpenThemeData(GetDesktopWindow(), L"WINDOW");
GetThemeColor(hTheme, WP_CAPTION, CS_ACTIVE,
    <is active window> ? TMT_FILLCOLORHINT : TMT_BORDERCOLORHINT, &rgb);

// Can use these functions to retrieve the individual RGB values
BYTE r = GetRValue(rgb);
BYTE g = GetGValue(rgb);
BYTE b = GetBValue(rgb);

Diese Farben bleiben auch dann korrekt, wenn der Benutzer die Farben der Titelleiste in der Systemsteuerung ändert (im Gegensatz zur Verwendung von COLOR_ACTIVECAPTION / COLOR_GRADIENTACTIVECAPTION). Sie sollten auch überprüfen, ob Themes aktiv sind, indem Sie IsThemeActive() bevor Sie versuchen, Themenfarben zu erhalten.

Die Werte der Konstanten zum schnellen Nachschlagen:

  • WP_CAPTION: 1
  • CS_ACTIVE: 1
  • TMT_FILLCOLORHINT: 3821
  • TMT_BORDERCOLORHINT: 3822

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X