Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   ListView Header Farbe (Win32) (https://www.delphipraxis.net/191441-listview-header-farbe-win32.html)

EWeiss 17. Jan 2017 07:55


ListView Header Farbe (Win32)
 
Wie kann ich die Hintergrundfarbe des ListView Headers ändern?
Nicht die der Columns sondern den Hintergrund davon.

Am besten wäre Transparent .. ka ob das geht.
Wenn ich an den Bereich herankäme könnte ich den Hintergrund des ListViews dort hinein kopieren um einen
Transparenten Effekt zu emulieren.

gruss

TiGü 17. Jan 2017 10:38

AW: ListView Header Farbe (Win32)
 
Du brauchst also nur das Handle davon?
Vielleicht reicht es aus, wenn du WM_PARENTNOTIFY abgreifst und dir wie unten gezeigt das Headerhandle holst?!

Delphi-Quellcode:
  TWMParentNotify = record
    Msg: Cardinal;
    MsgFiller: TDWordFiller;
    case Word of
      WM_CREATE, WM_DESTROY: (
        Unused1: Word;
        ChildID: Word;
        EventChildIDFiller: TDWordFiller;
        ChildWnd: HWnd);
      WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN: (
        Unused2: Word;
        Value: Word;
        EventValueFiller: TDWordFiller;
        XPos: Smallint;
        YPos: Smallint;
        XYPosFiller: TDWordFiller);
      0: (
        Event: Word;
        Value1: Word;
        EventValue1Filler: TDWordFiller;
        Value2: LPARAM;
        Result: LRESULT);
  end;

...

procedure WMParentNotify(var Message: TWMParentNotify); message WM_PARENTNOTIFY;

...

procedure TCustomListView.WMParentNotify(var Message: TWMParentNotify);
begin
  with Message do
    if (Event = WM_CREATE) and (FHeaderHandle = 0) then
    begin
      FHeaderHandle := ChildWnd;
      FDefHeaderProc := TWindowProcPtr(GetWindowLong(FHeaderHandle, GWL_WNDPROC));
{$IFDEF CLR}
      SetWindowLong(FHeaderHandle, GWL_WNDPROC, FLVInstances.FHeaderInstance);
{$ELSE}
      SetWindowLong(FHeaderHandle, GWL_WNDPROC, Winapi.Windows.LPARAM(FHeaderInstance));
{$ENDIF}
    end;
  inherited;
end;

EWeiss 17. Jan 2017 10:53

AW: ListView Header Farbe (Win32)
 
Zitat:

TCustomListView
Win32

Danke. Nein das Handle kann man einfacher erfahren eine Zeile Code.
Delphi-Quellcode:
  HeaderHandle := ListView_GetHeader(WinHandle);


btw. komplett.
Delphi-Quellcode:
procedure TSkinListView.SubClass(WinHandle: hWnd);
begin

  FClientInstance := MakeObjectInstance(ClientWndProc);

  FPrevClientProc := Pointer(GetWindowLong(WinHandle, GWL_WNDPROC));
  SetWindowLong(WinHandle, GWL_WNDPROC, Integer(FClientInstance));

  FHeaderInstance := MakeObjectInstance(HeaderClientWndProc);
  HeaderHandle := ListView_GetHeader(WinHandle);
  FPrevHeaderProc := Pointer(GetWindowLong(HeaderHandle , GWL_WNDPROC));
  SetWindowLong(HeaderHandle , GWLP_WNDPROC, Integer(FHeaderInstance));
end;
Ich habe Columns auf der ListView ich benötige den Hintergrund von allen Columns. (Scheint irgendein Frame zu sein.
Der schwarze Bereich wie gezeigt. ;)

Nebenbei:
Ein Qual ein ListView selbst zu zeichnen. (Na was soll's hab sonst nix zu tun). ;)
Muss ich wohl irgendwie selbst lösen.

gruss

TiGü 17. Jan 2017 13:08

AW: ListView Header Farbe (Win32)
 
Zitat:

Zitat von EWeiss (Beitrag 1359038)
Zitat:

TCustomListView
Win32

Danke. Nein das Handle kann man einfacher erfahren eine Zeile Code.
Delphi-Quellcode:
  HeaderHandle := ListView_GetHeader(WinHandle);

Ja nun, es geht ja um die prinzipielle Vorgehensweise, wie man das Handle holen kann.
Die TCustomListView ist ja auch nichts weiter als ein Objekt-orientierter Wrapper um die entsprechenden Windowsfunktion-/SendMessage-Aufrufe. Was anderes bastelst du ja auch nicht.

Bei mir kommt nur 0 zurück, wenn man das Handle der ListView in ListView_GetHeader übergibt.
Das funktioniert bei dir?

Zitat:

Zitat von EWeiss (Beitrag 1359038)
Ich habe Columns auf der ListView ich benötige den Hintergrund von allen Columns. (Scheint irgendein Frame zu sein.
Der schwarze Bereich wie gezeigt. ;)

Prinzipiell geht das von dir gewünschte, hast du eine Delphiversion höher als XE2? Dann könntest du dir mal in den ComCtrls.TListViewStyleHook anschauen. Mit aktivierten VCL-Styles werden auch die Columns mitgeskinnt und es wird über diese Hook-Klasse gezeichnet.

Wie zeichnest du denn die Column-Header links vom schwarzen Bereich im von dir angehängten Bild?
Da wo Time steht. Hier hast du doch schon den Hintergrund selbst gezeichnet, oder?
Warum wendest du diese Vorgehensweise nicht auch auf den Column-Header daneben an?

EWeiss 17. Jan 2017 17:16

AW: ListView Header Farbe (Win32)
 
Zitat:

Bei mir kommt nur 0 zurück, wenn man das Handle der ListView in ListView_GetHeader übergibt.
Das funktioniert bei dir?
Ja das funktioniert so wie gezeigt weil das ListView gesubclassed ist.

Delphi-Quellcode:
function TSkinListView.CreateWindow(ParentHandle: hWnd): hWnd;
begin

  InitCommonControlsEx(iccex);

  if Visible then
  begin
    LStyle := WS_CHILD or LVS_REPORT or WS_CLIPCHILDREN or WS_CLIPSIBLINGS
      or LVS_SHOWSELALWAYS or LVS_SHAREIMAGELISTS or LVS_OWNERDRAWFIXED or WS_VISIBLE;
  end
  else
    LStyle := WS_CHILD or LVS_REPORT or WS_CLIPCHILDREN or WS_CLIPSIBLINGS
      or LVS_SHOWSELALWAYS or LVS_SHAREIMAGELISTS or LVS_OWNERDRAWFIXED;

  FHListView := CreateWindowEx(WS_EX_TRANSPARENT, WC_LISTVIEW, nil, LStyle,
    Left, Top, Width, Height, ParentHandle, DlgItemID, hInstance, nil);

  if FHListView <> 0 then
  begin
    SubClass(Handle);

    ImgBack := SkinEngine.skCreateImageFromFile(SelectedImg);
   
    if not assigned(PropList) then
      PropList := TStringList.Create;

    SetProperty(Handle, PROP_IMAGE_SELECTED, ImgBack);
    ShowWindow(Handle, Integer(Visible));

    ListView_SetExtendedListViewStyle(Handle, LVS_EX_FULLROWSELECT);

    HookedScrollbar(ParentHandle);
  end;

  Result := FHListView;
end;
Zitat:

Warum wendest du diese Vorgehensweise nicht auch auf den Column-Header daneben an?
Weil es keinen Column Header daneben gibt.
Dieser erstreckt sich über den gesamten Bereich der ListView hinter den eigentlichen Columns.

Zeichnen tue ich ihn so.
Headerproc..

Delphi-Quellcode:
function TSkinListView.ListViewHeaderProc(WinHandle: hWnd; Msg: UINT; wP: WParam; lP: LParam)
  : LRESULT;
var
  ps: TPaintstruct;
  rc, rcHeader: TRect;
  Dc: Hdc;
  ItemCount: Integer;
  IntI: Integer;
begin

  case Msg of
    WM_ERASEBKGND:
      begin
        Result := 1;
        exit;
      end;

    WM_LBUTTONDBLCLK:
      begin
        SkinEngine.FInvalidateRect(WinHandle, True);
      end;

    WM_PAINT:
      begin
        GetClientRect(WinHandle, rc);

        Dc := BeginPaint(WinHandle, ps);

        if not SkinEngine.Composited(WinHandle) then
          Dc := SkinEngine.DoubleBuffer(ps.Hdc, rc.Right, rc.bottom, CreateBuffer);

        ItemCount := Header_GetItemCount(WinHandle);
        for IntI := 0 to ItemCount do
        begin
          Header_GetItemRect(WinHandle, IntI, @rcHeader);

          DrawHeaderItem(WinHandle, DC, IntI, rcHeader, True);
        end;

        if not SkinEngine.Composited(WinHandle) then
          SkinEngine.DoubleBuffer(0, 0, 0, DestroyBuffer)
        else
          ReleaseDC(WinHandle, Dc);

        EndPaint(WinHandle, ps);
        Result := 0;
        exit;
      end;

  end;
  Result := CallWindowProc(FPrevHeaderProc, WinHandle, Msg, wP, lP);
end;
DrawHeaderItem
Delphi-Quellcode:
procedure TSkinListView.DrawHeaderItem(WinHandle: hWnd; Dc: Hdc; Index: Integer; Rect: TRect;
  Selected: Bool);
var
  Text: PWideChar;
  buf: array [0 .. 255] of Char;
  Item: THDItem;
  rcHeader: TRect;
  Img: Cardinal;
  Graphics: Cardinal;
  rc: TRect;
begin
  Item.mask := HDI_TEXT or HDI_FORMAT or HDI_WIDTH;
  Item.pszText := buf;
  Item.fmt := HDF_LEFT and HDF_OWNERDRAW and HDF_STRING;
  Item.cchTextMax := sizeof(buf);

  Header_GetItemRect(WinHandle, Index, @rcHeader);

  ZeroMemory(@buf, sizeof(buf));
  Header_GetItem(WinHandle, Index, Item);
  Text := buf;

  SetBkMode(Dc, TRANSPARENT);

  if GetShadow then
  begin
    if IsWindowEnabled(WinHandle) then
      Color := GetShadowColor
    else
    Color := RGB(255, 255, 255);

    Rect.Top := ((rcHeader.Bottom - FPointSize) div 2) div 2 + 1;
    DrawTextToDC(DC, Text, Rect, Color, FFontName, FPointSize, FFontStyle, 0, 0);

    if IsWindowEnabled(WinHandle) then
    begin
      if Selected then
        Color := AktForecolor
      else
      Color := InAktForecolor;
    end
    else
    Color := RGB(140, 140, 140);

    DrawTextToDC(DC, Text, Rect, Color, FFontName, FPointSize, FFontStyle,
      FShadowOffset, 0);

    if GdipCreateFromHDC(DC, Graphics) = OK then
    begin
      Img := Cardinal(GetProperty(Handle, PROP_IMAGE_SELECTED));
      GetClientRect(WinHandle, rc);
      // Hintergrund der Columns (Zeichne ich hier die Farbe anstelle des Button dann werden die Columns übermalt.)
      // bsp. FillRect.. bla. bla.
      SkinEngine.PaintButton(Graphics, 4, Img, rc.Left, rc.Top, rc.Right, rc.bottom, BS_PUSHBUTTON);
      // Columns
      SkinEngine.PaintButton(Graphics, 4, Img, rcHeader.Left, rcHeader.Top, rcHeader.Right - rcHeader.Left,
        rcHeader.bottom, BS_PUSHBUTTON);

      GdipDeleteGraphics(Graphics);
    end;
  end;
end;
Zitat:

hast du eine Delphiversion höher als XE2?
Nein D2010.

gruss

EWeiss 17. Jan 2017 17:38

AW: ListView Header Farbe (Win32)
 
Das Problem ist folgendes.
Ich habe ja nur ein DC das vom HeaderHandle das mit DrawHeaderItem übergeben wird.
Das bedeutet will ich den Hintergrund des Header ausmalen muss ich in Reihenfolge vorgehen.

Also erst den Hintergrund zeichnen und dann die Columns.
Delphi-Quellcode:
    if GdipCreateFromHDC(DC, Graphics) = OK then
     begin
       Img := Cardinal(GetProperty(Handle, PROP_IMAGE_SELECTED));
       GetClientRect(WinHandle, rc);
       // Hintergrund der Columns (Zeichne ich hier die Farbe anstelle des Button dann werden die Columns übermalt.)
       // bsp. FillRect.. bla. bla.
       SkinEngine.PaintButton(Graphics, 4, Img, rc.Left, rc.Top, rc.Right, rc.bottom, BS_PUSHBUTTON);
       // Columns
       SkinEngine.PaintButton(Graphics, 4, Img, rcHeader.Left, rcHeader.Top, rcHeader.Right - rcHeader.Left,
         rcHeader.bottom, BS_PUSHBUTTON);

       GdipDeleteGraphics(Graphics);
     end;
Das mache ich ja auch.

Ich kann aber nicht auf den Hintergrund selbst zeichnen dafür benötige ich ein eigenes DC für den Columns Hintergrund.
Scheint es wohl nicht zu geben.

Auch der erste Button wird von den Columns übermalt deshalb die Farbunterschiede.
Die Columns bekommen dann kräftigere Farben da sich diese durch den Hintergrund und weil sie Transparent sind duplizieren.

gruss

EWeiss 17. Jan 2017 18:17

AW: ListView Header Farbe (Win32)
 
Geänderte Version. So wie es aussehen sollte.
Ich kopiere jetzt den Hintergrund in ein temporäres DC um die Transparenz zu emulieren.
Das Problem ist aber genauso wie vorher ich kann das Window nicht aktualisieren
deshalb wird das DC immer wieder mit dem gleichen Inhalt übermalt.

Ich kann innerhalb des Threads WM_PAINT kein Invalidate aufrufen.
Krise hoch 3.

Delphi-Quellcode:
procedure TSkinListView.DrawHeaderItem(WinHandle: hWnd; Dc: Hdc; Index: Integer; Rect: TRect;
  Selected: Bool);
var
  Text: PWideChar;
  buf: array [0 .. 255] of Char;
  Item: THDItem;
  rcHeader: TRect;
  Img: Cardinal;
  Graphics: Cardinal;
  rc: TRect;
  rw: TRect;
  hDCBack: HDC;
  lp: TPoint;
begin
  Item.mask := HDI_TEXT or HDI_FORMAT or HDI_WIDTH;
  Item.pszText := buf;
  Item.fmt := HDF_LEFT and HDF_OWNERDRAW and HDF_STRING;
  Item.cchTextMax := sizeof(buf);

  Header_GetItemRect(WinHandle, Index, @rcHeader);

  ZeroMemory(@buf, sizeof(buf));
  Header_GetItem(WinHandle, Index, Item);
  Text := buf;

  SetBkMode(Dc, TRANSPARENT);
// Neu
  hDCBack := CreateCompatibleDC(DC);
  GetClientRect(WinHandle, rc);

  GetWindowRect(WinHandle, rw);
  lp.x := rw.Left;
  lp.y := rw.Top;
  ScreenToClient(GetParent(Handle), lp);

  SelectObject(hDCBack, SkinEngine.GetBackBitmap(GetParent(Handle)));
  BitBlt(DC, 0, 0, rc.Right, rc.Bottom, hDCBack, lp.x, lp.y, SRCCOPY);
// end Neu
  if GetShadow then
  begin
    if IsWindowEnabled(WinHandle) then
      Color := GetShadowColor
    else
    Color := RGB(255, 255, 255);

    Rect.Top := (((rcHeader.Bottom - FPointSize) div 2) div 2 + 1) + lp.y;
    Rect.Left := Rect.Left + lp.x; // Neu
    DrawTextToDC(hDCBack, Text, Rect, Color, FFontName, FPointSize, FFontStyle, 0, 0);

//    Rect.Top := (((rcHeader.Bottom - FPointSize) div 2) div 2 + 1);
//    DrawTextToDC(DC, Text, Rect, Color, FFontName, FPointSize, FFontStyle, 0, 0);

    if IsWindowEnabled(WinHandle) then
    begin
      if Selected then
        Color := AktForecolor
      else
      Color := InAktForecolor;
    end
    else
    Color := RGB(140, 140, 140);

    DrawTextToDC(hDCBack, Text, Rect, Color, FFontName, FPointSize, FFontStyle,
      FShadowOffset, 0);

//    DrawTextToDC(DC, Text, Rect, Color, FFontName, FPointSize, FFontStyle,
//      FShadowOffset, 0);

//    if GdipCreateFromHDC(DC, Graphics) = OK then
    if GdipCreateFromHDC(hDCBack, Graphics) = OK then
    begin
      Img := Cardinal(GetProperty(Handle, PROP_IMAGE_SELECTED));
      GetClientRect(WinHandle, rc);
//      SkinEngine.PaintButton(Graphics, 4, Img, rc.Left, rc.Top, rc.Right, rc.bottom, BS_PUSHBUTTON);

      SkinEngine.PaintButton(Graphics, 4, Img, rc.Left + lp.x, lp.y, rc.Right, rc.bottom, BS_PUSHBUTTON);
//      SkinEngine.PaintButton(Graphics, 4, Img, rcHeader.Left, rcHeader.Top, rcHeader.Right - rcHeader.Left,
//        rcHeader.bottom, BS_PUSHBUTTON);
      SkinEngine.PaintButton(Graphics, 4, Img, rcHeader.Left + lp.x, lp.y, rcHeader.Right - rcHeader.Left,
        rcHeader.bottom, BS_PUSHBUTTON);

      GdipDeleteGraphics(Graphics);
    end;
    DeleteDC(hDCBack);
  end;
end;

gruss

EWeiss 19. Jan 2017 10:01

AW: ListView Header Farbe (Win32)
 
Funktioniert jetzt wollte nur das Ergebnis mitteilen.
Subclass Header
Delphi-Quellcode:
    WM_PAINT:
      begin
        GetClientRect(WinHandle, rc);

        Dc := BeginPaint(WinHandle, ps);

        if not SkinEngine.Composited(WinHandle) then
          Dc := SkinEngine.DoubleBuffer(ps.Hdc, rc.Right, rc.Bottom, CreateBuffer);

        hDCBack := CreateCompatibleDC(Dc);

        GetWindowRect(WinHandle, rw);
        p.x := rw.Left;
        p.y := rw.Top;
        ScreenToClient(GetParent(Handle), p);

        SelectObject(hDCBack, SkinEngine.GetBackBitmap(GetParent(Handle)));
        BitBlt(Dc, 0, 0, rcHeader.Right, rcHeader.Bottom, hDCBack, p.x, p.y, SRCCOPY);

        ItemCount := Header_GetItemCount(WinHandle);
        for IntI := 0 to ItemCount - 1 do
        begin
          Header_GetItemRect(WinHandle, IntI, @rcHeader);

          DrawHeaderItem(WinHandle, Dc, IntI, rcHeader, True);
        end;
        DeleteDC(hDCBack);

        if not SkinEngine.Composited(WinHandle) then
          SkinEngine.DoubleBuffer(0, 0, 0, DestroyBuffer)
        else
          ReleaseDC(WinHandle, Dc);

        EndPaint(WinHandle, ps);
        Result := 0;
        exit;
      end;

  end;
  Result := CallWindowProc(FPrevHeaderProc, WinHandle, Msg, wP, lP);
end;
Drawitems
Delphi-Quellcode:
procedure TSkinListView.DrawHeaderItem(WinHandle: hWnd; Dc: Hdc; Index: Integer; Rect: TRect;
  Selected: Bool);
var
  Text: PWideChar;
  buf: array [0 .. 255] of Char;
  Item: THDItem;
  rcHeader: TRect;
  Img: Cardinal;
  Graphics: Cardinal;
  rc: TRect;
  rw: TRect;
  lP: TPoint;
begin
  Item.mask := HDI_TEXT or HDI_FORMAT { or HDI_BITMAP } or HDI_WIDTH;
  Item.pszText := buf;
  Item.fmt := HDF_LEFT or HDF_OWNERDRAW { or HDF_BITMAP } or HDF_STRING;
  Item.cchTextMax := sizeof(buf);

  Header_GetItemRect(WinHandle, Index, @rcHeader);

  ZeroMemory(@buf, sizeof(buf));
  Header_GetItem(WinHandle, Index, Item);
  Text := buf;

  SetBkMode(Dc, TRANSPARENT);

  if GetShadow then
  begin
    if IsWindowEnabled(WinHandle) then
      Color := GetShadowColor
    else
      Color := RGB(255, 255, 255);

    Rect.Top := (((rcHeader.Bottom - FPointSize) div 2) div 2 + 1);
    DrawTextToDC(Dc, Text, Rect, Color, FFontName, FPointSize, FFontStyle, 0, 0);

    if IsWindowEnabled(WinHandle) then
    begin
      if Selected then
        Color := AktForecolor
      else
        Color := InAktForecolor;
    end
    else
      Color := RGB(140, 140, 140);

    DrawTextToDC(Dc, Text, Rect, Color, FFontName, FPointSize, FFontStyle, FShadowOffset, 0);

    if GdipCreateFromHDC(Dc, Graphics) = OK then
    begin
      Img := Cardinal(GetProperty(Handle, PROP_IMAGE_SELECTED));
      GetClientRect(WinHandle, rc);

      GetWindowRect(WinHandle, rw);
      lP.x := rw.Left;
      lP.y := rw.Top;
      ScreenToClient(GetParent(Handle), lP);

      SkinEngine.PaintButton(Graphics, 4, Img, rc.Left, rc.Top, rc.Right, rc.Bottom, BS_PUSHBUTTON);

      SkinEngine.PaintButton(Graphics, 4, Img, rcHeader.Left, rcHeader.Top,
        rcHeader.Right - rcHeader.Left, rcHeader.Bottom, BS_PUSHBUTTON);

      GdipDeleteGraphics(Graphics);
    end;
  end;
end;
Ergebnis siehe Pic.
Kann mich jetzt mit den Header Icons beschäftigen.

gruss

eholzer 8. Okt 2017 20:48

AW: ListView Header Farbe (Win32)
 
Hallo,

könntet ihr vielleicht zu dem Thema (ListView Header Farbe setzen) ein kleines Demoprogramm anhängen?

Gruß,
Eric


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:10 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz