2010-12-04 64 views
5

Je traduis le composant C++ suivant à Delphi:Pouvez-vous aider à traduire ce très petit composant C++ en Delphi?

http://borland.newsgroups.archived.at/public.delphi.vcl.components.using.win32/200708/0708225318.html

Mais cela ne fonctionne pas ... Je joins le code traduit, pourrait l'un des pros jeter un oeil?

Merci!

Voici le code:

unit ComboBoxPlus; 

interface 

uses 
    SysUtils, Classes, Controls, StdCtrls, Messages, Types, Windows, Graphics; 

type 
    TComboBoxPlus = class(TComboBox) 
    private 
    FClickedItem: Integer; 
    FListHandle: HWND; 
    ListWndProcPtr: Longint; 
    OldListWndProc: Pointer; 

    function GetIsEnabled(Index: Integer): Boolean; 
    procedure SetIsEnabled(Index: Integer; Value: Boolean); 
    protected 
    procedure WndProc(var Message: TMessage); 
    procedure ListWndProc(var Message: TMessage); virtual; 
    procedure DrawItem(Index: Integer; Rect: TRect; 
     State: TOwnerDrawState); 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    property Enabled[Index: Integer]: Boolean read GetIsEnabled write SetIsEnabled; 
    published 
    { Published declarations } 
    end; 

procedure Register; 

implementation 

procedure Register; 
begin 
    RegisterComponents('Win32', [TComboBoxPlus]); 
end; 

constructor TComboBoxPlus.Create(AOwner: TComponent); 
begin 
    inherited Create(AOwner); 
    Style := csOwnerDrawFixed; 
    Height := 21; 
    ItemHeight := 17; 
    ListWndProcPtr := Longint(Classes.MakeObjectInstance(ListWndProc)); 
end; 

destructor TComboBoxPlus.Destroy; 
begin 
    if FListHandle <> 0 then 
    SetWindowLong(FListHandle, GWL_WNDPROC, Longint(OldListWndProc)); 

    FreeObjectInstance(Pointer(ListWndProcPtr)); 

    inherited Destroy; 
end; 

function TComboBoxPlus.GetIsEnabled(Index: Integer): Boolean; 
begin 
    if Boolean(Items.Objects[Index]) then Result := false 
    else Result := true; 
end; 

procedure TComboBoxPlus.SetIsEnabled(Index: Integer; Value: Boolean); 
begin 
    if Value then 
    Items.Objects[Index] := TObject(false) 
    else 
    Items.Objects[Index] := TObject(true); 
end; 

procedure TComboBoxPlus.DrawItem(Index: Integer; Rect: TRect; 
    State: TOwnerDrawState); 
begin 
    if odSelected in State then 
    begin 
    if not Boolean(Items.Objects[Index]) then 
    begin 
     Canvas.Brush.Color := clHighlight; 
     Canvas.Font.Color := clHighlightText; 
     Canvas.FillRect(Rect); 
    end else 
    begin 
     Canvas.Brush.Color := Color; 
     Canvas.Font.Color := clGrayText; 
     Canvas.FillRect(Rect); 
     Canvas.DrawFocusRect(Rect); 
    end; 
    end else 
    begin 
    if not Boolean(Items.Objects[Index]) then 
    begin 
     Canvas.Brush.Color := Color; 
     Canvas.Font.Color := Font.Color; 
    end else 
    begin 
     Canvas.Brush.Color := Color; 
     Canvas.Font.Color := clGrayText; 
    end; 
    Canvas.FillRect(Rect); 
    end; 
    Canvas.TextOut(Rect.Left + 3, Rect.Top + (((Rect.Bottom - Rect.Top) div 2) - 
    (Canvas.TextHeight('Wg') div 2)), Items.Strings[Index]); 
end; 

procedure TComboBoxPlus.WndProc(var Message: TMessage); 
begin 
    if (Message.Msg = WM_CTLCOLORLISTBOX) then 
    begin 
    if FListHandle = 0 then 
    begin 
     FListHandle := HWnd(Message.LParam); 
     inherited WndProc(Message); 
     OldListWndProc := Pointer(SetWindowLong(FListHandle, GWL_WNDPROC, ListWndProcPtr)); 
     exit; 
    end; 
    end; 

    inherited WndProc(Message); 
end; 

procedure TComboBoxPlus.ListWndProc(var Message: TMessage); 
var 
    R: TRect; 
    X, Y: Integer; 
begin 
    if (Message.Msg = WM_LBUTTONDOWN) or (Message.Msg = WM_LBUTTONUP) then 
    begin 
    X := Message.LParamLo; 
    Y := Message.LParamHi; 

    Windows.GetClientRect(FListHandle, R); 

    if PtInRect(R, Point(X, Y)) then 
    begin 
     FClickedItem := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) + (Y div ItemHeight); 
     if (not Enabled[FClickedItem]) then 
     begin 
     Message.Result := 0; 
     exit; 
     end; 
    end; 
    end else if (Message.Msg = WM_LBUTTONDBLCLK) then 
    begin 
    Message.Result := 0; 
    exit; 
    end; 

    Message.Result := CallWindowProc(OldListWndProc, FListHandle, Message.Msg, 
    Message.WParam, Message.LParam); 
end; 

end. 
+3

Qu'est-ce que vous avez jusqu'à présent, et comment ça ne marche pas? –

+0

Le code compile et s'exécute sans erreurs. Je pense que DrawItem et SetIsEnabled/GetIsEnabled fonctionnent, mais il y a un problème avec WndProcs puisque les éléments ne sont pas désactivés et que la partie interne des messages n'est pas appelée ... – Steve

Répondre

4

Il est minuit, je suis fatigué - désolé ma stupidité. Il travaille avec les modifications suivantes:

procedure WndProc(var Message: TMessage); override; 
procedure ListWndProc(var Message: TMessage); 
procedure DrawItem(Index: Integer; Rect: TRect; 
    State: TOwnerDrawState); override; 

(ajouter deux remplacements et prendre le virtuel)

La dernière chose à régler est de ne pas laisser la zone de liste déroulante de près si l'élément désactivé est sélectionné sans clavier clés!

+1

si vous ajoutez ou clarifiez votre question initiale, alors cela devrait être un edit ... pas comme une réponse;) –

+1

Oui mais j'ai répondu à ma propre question :-) – Steve

+1

Le compilateur ne vous a-t-il pas averti des dérogations manquantes? Il aurait dû. –

0

@Steve's réponse fonctionne bien, mais avec un ajout simple, vous pouvez créer un séparateur de ligne réelle entre deux éléments.

procedure WndProc(var Message: TMessage); override; 
procedure ListWndProc(var Message: TMessage); 
procedure DrawItem(Index: Integer; Rect: TRect; 
    State: TOwnerDrawState); override; 

Modifier la dernière partie de DrawItem à:

if(not Boolean(Items.Objects[Index])) then 
    Canvas.TextOut(Rect.Left + 3, Rect.Top + (((Rect.Bottom - Rect.Top) div 2) - 
    (Canvas.TextHeight('Wg') div 2)), Items.Strings[Index]) 
else 
begin 
    Canvas.Pen.Color := clSilver; 
    Canvas.Pen.Width := 1; 
    Canvas.Pen.Style := psSolid; 
    Canvas.MoveTo(Rect.Left + 3, Rect.Top + ((Rect.Bottom - Rect.Top) div 2)); 
    Canvas.LineTo(Rect.Right - 3, Rect.Top + ((Rect.Bottom - Rect.Top) div 2)); 
end; 

Il me aide beaucoup quand je peux voir comment la classe peut être utilisée. Donc pour les autres, j'ai ajouté un exemple sur la façon de l'utiliser:

uses 
    Forms, o_comboboxplus; 

var 
fComboPlus: TComboBoxPlus; 

begin 
    fComboPlus := TComboBoxPlus.Create(Form1); 
    with(fComboPlus) do 
    begin 
    Parent := Form1; 
    Left := 10; 
    Top := 10; 
    Items.Add('Test1'); 
    Items.Add('Test2'); 
    Items.Add('Test3'); 
    Items.Add('Test4'); 
    Enabled[2] := false; //'Test3' will become a line seperator 
    end; 
end;