Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Combobox mit Bitmaps (https://www.delphipraxis.net/104259-combobox-mit-bitmaps.html)

Bomberbb 30. Nov 2007 11:33


Combobox mit Bitmaps
 
Hallo,

Ich will eine Combobox erweitern. Es sollten Bilder vor die Einträge gezeichnet werden. Das wird auch schon gemacht.
Delphi-Quellcode:
Procedure TForm4.TntComboBox1DrawItem(Control : TWinControl;Index : Integer;
  Rect : TRect;State : TOwnerDrawState);
Var
  Bitmap                          : TBitmap;
  Offset                          : Integer;
  Colorloc                        : TColor;
Begin
  offset := 0;
  With TNTComboBox1.Canvas Do
  Begin
    Colorloc := Color;
    FillRect(Rect);
    If tLayer(TNTComboBox1.Items.Objects[index]).IsVisible Then
      Bitmap := Layerlist.BmpLayerOn
    Else
      Bitmap := Layerlist.BmpLayerOff;
    //copy bitmap to combobox coordinate
    BrushCopy(Bounds(Rect.Left +2, Rect.Top , 16, 16), Bitmap, Bounds(0, 0, 16, 16), clred);

    //Set a caption to each item
    Font.size := 10;
    TextOut(Rect.Left + 40, Rect.Top, TNTCombobox1.Items[Index]);

    Brush.Color := tLayer(TNTComboBox1.Items.Objects[index]).GetColor;
    FillRect(Bounds(Rect.Left + 20, Rect.Top + 1, 14, 14));
  End;
End;
Allerdings möchte ich bei einem Klick auf die verschiedenen Elemente eines Items unterschiedliche Sachen ausführen.
Leider habe ich keine Ahnung wie ich herausfinden kann auf welchen Bereich geklickt wurde...

Hat jemand eine Idee???

Reinhardtinho 30. Nov 2007 12:17

Re: Combobox mit Bitmaps
 
Hi,

ich verstehe die Frage nicht ganz, was für Bereiche hast du?

Die Combobox hat dafür nur ein Event "OnChange", wenn ein Eintrag ausgewählt wurde.

Bomberbb 30. Nov 2007 12:24

Re: Combobox mit Bitmaps
 
Ich habe vor jedem Listeneintrag je zwei Bitmaps und will auf einen Klick auf die Bitmap anders reagieren als beim Klick auf den Listeneintrag.

Bernhard Geyer 30. Nov 2007 12:26

Re: Combobox mit Bitmaps
 
Da wirst du dir schon für jeden Eintrag merken müssen wie groß die Bitmap ist und welche x-Bereich sie damit einnimmt.

Bomberbb 30. Nov 2007 12:30

Re: Combobox mit Bitmaps
 
Ja das ist nicht das Problem, aber ich weiß nicht mit welcher Funktion ich das abfangen kann. Es gibt kein onMousedown bei TCombobox.

Tyrael Y. 30. Nov 2007 12:41

Re: Combobox mit Bitmaps
 
OnMouseDown gibt es auch bei TComboBox.

Bei TControl ist das OnMouseDown als protected deklariert.
Mach es public bei deinem Control und go.... ;)

Bomberbb 30. Nov 2007 12:51

Re: Combobox mit Bitmaps
 
Das hab ich auch schon probiert. Das funzt leider auch nur bei dem grauen Feld rechts und nicht bei den Items.

Muetze1 30. Nov 2007 13:04

Re: Combobox mit Bitmaps
 
Und was funktioniert dabei nicht?
Delphi-Quellcode:
...
  published
    property OnMouseDown;
  end;

Deep-Sea 30. Nov 2007 13:06

Re: Combobox mit Bitmaps
 
Ich bezweifel, dass das so einfach geht.
Eine ComboBox ist nun mal nicht dafür gedacht in ihrer DropDown-Liste "Pseudo-Buttons" zu handhaben.

Tyrael Y. 30. Nov 2007 13:10

Re: Combobox mit Bitmaps
 
Wieso sollte es nicht gehen?
Er muss es doch nur verwalten.
Bei OnMouseDown kennt er x und y.
Wenn er in einer ObjectListe feshält, welcher Eintrag welche Daten bekommen hat, kann er anhand davon bestimmen ob er gerade auf einem Bild geklickt hat oder auf den Textbereich.

Ich seh grad nicht wieso das nicht lösbar sein soll.

Muetze1 30. Nov 2007 13:12

Re: Combobox mit Bitmaps
 
Eine ComboBox ist nur eine Kombination aus einem Editfeld und einer Listbox (intern) und ich weiss nicht, ob er bei den Mousereignissen diese auch liefert, wenn er sich auf dem ListBoxbereich befindet. Aber das war hier nicht die Frage...

Deep-Sea 30. Nov 2007 13:15

Re: Combobox mit Bitmaps
 
Zitat:

Zitat von Tyrael Y.
Wieso sollte es nicht gehen?
Er muss es doch nur verwalten.
Bei OnMouseDown kennt er x und y.
Wenn er in einer ObjectListe feshält, welcher Eintrag welche Daten bekommen hat, kann er anhand davon bestimmen ob er gerade auf einem Bild geklickt hat oder auf den Textbereich.

Ich seh grad nicht wieso das nicht lösbar sein soll.

Darum:
Zitat:

Zitat von Bomberbb
Das hab ich auch schon probiert. Das funzt leider auch nur bei dem grauen Feld rechts und nicht bei den Items.

Ich habe es extra noch einmal getestet. Es stimmt.

uligerhardt 30. Nov 2007 14:14

Re: Combobox mit Bitmaps
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Deep-Sea
Ich bezweifel, dass das so einfach geht.
Eine ComboBox ist nun mal nicht dafür gedacht in ihrer DropDown-Liste "Pseudo-Buttons" zu handhaben.

Ich hab mal eine Combo mit Checkboxen zur Bearbeitung von Sets gebaut (siehe Bild), bei der ich vor einem ähnlichen Problem stand. Ich hab mal (hoffentlich alle) relevanten Teile rausgeklaubt:
Delphi-Quellcode:
type
  TRehCheckComboBox = class(TRehCustomComboBox)
  private
    FListInstance: Pointer;
    FDefListProc: Pointer;
    procedure ListWndProc(var Message: TMessage);
    // ...
   end;

constructor TRehCheckComboBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FListInstance := MakeObjectInstance(ListWndProc);
end;

destructor TRehCheckComboBox.Destroy;
begin
  FreeObjectInstance(FListInstance);
  inherited;
end;

procedure TRehCheckComboBox.CreateWnd;
var
  cbi: TComboBoxInfo;
  pListHandle: ^HWND;
begin
  inherited CreateWnd;
  FillChar(cbi, SizeOf(cbi), 0);
  cbi.cbSize := SizeOf(cbi);
  pListHandle := @ListHandle;
  if GetComboBoxInfo(Handle, cbi) then
  begin
    pListHandle^ := cbi.hwndList;
    FDefListProc := Pointer(GetWindowLong(ListHandle, GWL_WNDPROC));
    SetWindowLong(ListHandle, GWL_WNDPROC, Longint(FListInstance));
  end
  else
  begin
    //OutputDebugString(PChar(SysErrorMessage(GetLastError)));
    pListHandle^ := 0;
  end;
end;

procedure TRehCheckComboBox.ListWndProc(var Message: TMessage);
var
  X, Y, Index: Integer;
begin
  case Message.Msg of
    WM_LBUTTONDOWN:
      begin
        X := TWMMouse(Message).XPos;
        Y := TWMMouse(Message).YPos;
        Index := ItemAtPos(Point(X, Y), True);
        if Index <> -1 then
        begin
          if not UseRightToLeftAlignment then
          begin
            if X - ItemRect(Index).Left < GetCheckWidth then
            begin
              ToggleClickCheck(Index);
              Exit;
            end;
          end
          else
          begin
            Dec(X, ItemRect(Index).Right - GetCheckWidth);
            if (X > 0) and (X < GetCheckWidth) then
            begin
              ToggleClickCheck(Index);
              Exit;
            end;
          end;
        end;
      end;
  end;

  Message.Result := CallWindowProc(FDefListProc, ListHandle, Message.Msg,
    Message.WParam, Message.LParam);
end;
HTH,
Uli.

Deep-Sea 30. Nov 2007 14:22

Re: Combobox mit Bitmaps
 
Zitat:

Zitat von uligerhardt
Zitat:

Zitat von Deep-Sea
Ich bezweifel, dass das so einfach geht.
Eine ComboBox ist nun mal nicht dafür gedacht in ihrer DropDown-Liste "Pseudo-Buttons" zu handhaben.

Ich hab mal eine Combo mit Checkboxen zur Bearbeitung von Sets gebaut [...]

Gibt es einen Grund, warum du dich auf mein Post beziehst? Denn so einfach mit "OnMouseDown published machen" geht es wie gesagt nicht.
Aber nichts desto trotz: Schöner Code :wink:

uligerhardt 30. Nov 2007 14:51

Re: Combobox mit Bitmaps
 
Zitat:

Zitat von Deep-Sea
Zitat:

Zitat von uligerhardt
Zitat:

Zitat von Deep-Sea
Ich bezweifel, dass das so einfach geht.
Eine ComboBox ist nun mal nicht dafür gedacht in ihrer DropDown-Liste "Pseudo-Buttons" zu handhaben.

Ich hab mal eine Combo mit Checkboxen zur Bearbeitung von Sets gebaut [...]

Gibt es einen Grund, warum du dich auf mein Post beziehst?

Ja. Die Checkboxen in meiner Liste funktionieren wie "Pseudo-Buttons", obwohl sie sich in der DropDown-Liste befinden. Davon sprachst du doch?

Zitat:

Zitat von Deep-Sea
Denn so einfach mit "OnMouseDown published machen" geht es wie gesagt nicht.

In meinem Code kommt auch kein OnMouseDown vor. :?:

Zitat:

Zitat von Deep-Sea
Aber nichts desto trotz: Schöner Code :wink:

Danke. Ich war auch begeistert, als ich ihn grad nach langem mal wieder angesehen habe. :wink:

uligerhardt 30. Nov 2007 14:57

Re: Combobox mit Bitmaps
 
Nochmal ein lauffähiges Beispiel:
Delphi-Quellcode:
unit MyCombo;

interface

uses
  Windows,
  Messages,
  Classes,
  StdCtrls;

type
  TRehCheckComboBox = class(TComboBox)
  private
    FListInstance: Pointer;
    FDefListProc: Pointer;
    procedure ListWndProc(var Message: TMessage);
    // List box simulation:
    function ItemAtPos(Pos: TPoint; Existing: Boolean): Integer;
    function ItemRect(Index: Integer): TRect;
  protected
    procedure CreateWnd; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

uses
  SysUtils;

constructor TRehCheckComboBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FListInstance := MakeObjectInstance(ListWndProc);
end;

destructor TRehCheckComboBox.Destroy;
begin
  FreeObjectInstance(FListInstance);
  inherited;
end;

procedure TRehCheckComboBox.CreateWnd;
var
  cbi: TComboBoxInfo;
  pListHandle: ^HWND;
begin
  inherited CreateWnd;
  FillChar(cbi, SizeOf(cbi), 0);
  cbi.cbSize := SizeOf(cbi);
  pListHandle := @ListHandle;
  if GetComboBoxInfo(Handle, cbi) then
  begin
    pListHandle^ := cbi.hwndList;
    FDefListProc := Pointer(GetWindowLong(ListHandle, GWL_WNDPROC));
    SetWindowLong(ListHandle, GWL_WNDPROC, Longint(FListInstance));
  end
  else
  begin
    //OutputDebugString(PChar(SysErrorMessage(GetLastError)));
    pListHandle^ := 0;
  end;
end;

procedure TRehCheckComboBox.ListWndProc(var Message: TMessage);
const
  cCheckWidth = 20;
var
  X, Y, Index: Integer;
begin
  case Message.Msg of
    WM_LBUTTONDOWN:
      begin
        X := TWMMouse(Message).XPos;
        Y := TWMMouse(Message).YPos;
        Index := ItemAtPos(Point(X, Y), True);
        if Index <> -1 then
        begin
          if X - ItemRect(Index).Left < cCheckWidth then
          begin
            Beep; //ToggleClickCheck(Index);
            Exit;
          end;
        end;
      end;
  end;

  Message.Result := CallWindowProc(FDefListProc, ListHandle, Message.Msg,
    Message.WParam, Message.LParam);
end;

function TRehCheckComboBox.ItemAtPos(Pos: TPoint; Existing: Boolean): Integer;
var
  Count: Integer;
  ItemRect, ClientRect: TRect;
begin
  Windows.GetClientRect(ListHandle, ClientRect);
  if PtInRect(ClientRect, Pos) then
  begin
    Result := SendMessage(ListHandle, LB_GETTOPINDEX, 0, 0);
    Count := Items.Count;
    while Result < Count do
    begin
      SendMessage(ListHandle, LB_GETITEMRECT, Result, Longint(@ItemRect));
      if PtInRect(ItemRect, Pos) then Exit;
      Inc(Result);
    end;
    if not Existing then Exit;
  end;
  Result := -1;
end;

function TRehCheckComboBox.ItemRect(Index: Integer): TRect;
var
  Count: Integer;
begin
  Count := Items.Count;
  if (Index = 0) or (Index < Count) then
    SendMessage(ListHandle, LB_GETITEMRECT, Index, Longint(@Result))
  else if Index = Count then
  begin
    SendMessage(ListHandle, LB_GETITEMRECT, Index - 1, Longint(@Result));
    OffsetRect(Result, 0, Result.Bottom - Result.Top);
  end
  else
    FillChar(Result, SizeOf(Result), 0);
end;

end.
Delphi-Quellcode:
unit MainF;

interface

uses
  Windows,
  Messages,
  SysUtils,
  Variants,
  Classes,
  Graphics,
  Controls,
  Forms,
  Dialogs,
  StdCtrls,
  MyCombo;

type
  TComboBox = class(TRehCheckComboBox);

  TForm1 = class(TForm)
    ComboBox1: TComboBox;
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

end.
Dabei hat ComboBox1 den Style csDropDownList. Wenn du das Programm laufen lässt, die Combo aufklappst und in die linken 20 Pixel klickst, machst's Piep und die Combo bleibt offen. Das ist doch halbwegs das, was der OP möchte.

Deep-Sea 30. Nov 2007 14:57

Re: Combobox mit Bitmaps
 
Zitat:

Zitat von uligerhardt
Zitat:

Zitat von Deep-Sea
Denn so einfach mit "OnMouseDown published machen" geht es wie gesagt nicht.

In meinem Code kommt auch kein OnMouseDown vor. :?:

Schau dir Post #6 und #8 an. Darauf bezog ich mich.
Und dein Code ist ja nun mal nicht soo arg leicht verständlich wie OnMouseDown :-D

Nun gut, langsam wird's OT. Ich geh gleich in den Feierabend und euch allen wünsch ich ein schönes Wochenende :hi:

Bomberbb 30. Nov 2007 15:00

Re: Combobox mit Bitmaps
 
Na an die Lösung die Windowsevents abzugreifen hatte ich auch schon gedacht, aber ich hatte noch gehofft, dass es irgendwie einfacher geht. Nun ja, jetzt ist erst mal Wochenende, werde mir die Vorschläge mal nächste Woche ganz in Ruhe zu gemüte führen, aber auf den ersten Blick gefällt mir der 2. besser, mal schauen. So, der Glühwein wartet...

Ein schönes Wochenende und DANKE!!!!!

uligerhardt 30. Nov 2007 15:30

Re: Combobox mit Bitmaps
 
Zitat:

Zitat von Deep-Sea
Und dein Code ist ja nun mal nicht soo arg leicht verständlich wie OnMouseDown :-D

Ich weiß. :wink: Dafür geht er. :mrgreen: Um's mit deinen Worten zu sagen:
Zitat:

Zitat von Deep-Sea
Ich bezweifel, dass das so einfach geht.
Eine ComboBox ist nun mal nicht dafür gedacht in ihrer DropDown-Liste "Pseudo-Buttons" zu handhaben.

(Hervorhebungen von mir.)

Zitat:

Zitat von Deep-Sea
Nun gut, langsam wird's OT. Ich geh gleich in den Feierabend und euch allen wünsch ich ein schönes Wochenende :hi:

Danke, gleichfalls. :-D

Zitat:

Zitat von Bomberbb
Na an die Lösung die Windowsevents abzugreifen hatte ich auch schon gedacht, aber ich hatte noch gehofft, dass es irgendwie einfacher geht.

Ich fürchte, leichter geht's nicht.

Zitat:

Zitat von Bomberbb
So, der Glühwein wartet...

Prost.


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:09 Uhr.

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