开发者

MouseDown event using dynamic buttons in Delphi

I am dynamically creating buttons from an array that is dynamically loaded. I am storing a piece of needed information in the buttons hint.

    procedure TForm3.CreateAppButton(sBtnCapt: string);
var
    hIcon: THandle;
    nIconId: DWORD;
    Icon: TIcon;
    NewButton: TSpeedButton;
    PicConvert: TBitmap;
    sPathNew: string;
    AppData: TAppDetails;
begin
    AppData := TAppDetails.Create(sBtnCapt);
    NewButton := TSpeedButton.Create(self);
    with NewButton do
    begin

        Width := 67;
        Height := 50;
        Left := (Width + 5) * (self.ControlCount - 1);

        Top := 5;
        Parent := self;
        Caption := AppData.Caption;
        Name := AppData.ButtonName;
        Font.Size := 7;
        // extract a 16x16 icon for display on the buttom
        sPathNew := '';
        sPathNew := sPath + AppData.Exe;
        if PrivateExtractIcons(PChar(sPathNew), 0, 16, 16, @hIcon, @nIconId, 1, LR_LOADFROMFILE)
          <> 0 then
            try
                PicConvert := TBitmap.Create;
                Icon := TIcon.Create;
                try
                    Icon.Handle := hIcon;
                    PicConvert.Width := Icon.Width;
                    PicConvert.Height := Icon.Height;
                    PicConvert.Canvas.Draw(0, 0, Icon);
                    Glyph := PicConvert;
                finally
                    Icon.Free;
                    PicConvert.Free;
                end;
            finally
                DestroyIcon(hIcon);

            end;
        OnMouseDown := btnMouseDown;
        Hint := AppData.Exe;
        ShowHint := False;
        Layout := blGlyphTop;
        AppData.Free;
    end;
end;

Where my issue arises is on the mouse down event. I want to somehow use the information stored in the buttons hint property to trigger the needed action. You can see what I am trying to in the left click and where I am coming from in the right click. Designing the right click way would require me to put in ~80 it also requires that I declare each button on the form so that I can build and compile.

procedure TForm3.btnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;
    X, Y: Integer);
var
    sApp: string;
    AppData: TAppDetails;
begin
    sApp := '';
    if Button = mbLeft then
    begin
        sApp := btnFoo.Hint; 
        ShellExecute(sel开发者_StackOverflowf.Handle, 'open', PChar(sApp), nil, nil, SW_SHOWNORMAL);            
    end
    else if Button = mbRight then
    begin
        if Sender = btnCC3 then
        begin
            sApp := 'CaseClaims3.exe';
        end
        else if Sender = btnODBC then
        begin
            sApp := 'ODBCMgr.exe';
        end
        else if Sender = btnCredMaint then
        begin
            sApp := 'CreditorMaint';
        end;
        AppData := TAppDetails.Create(sApp);
        ShellExecute(self.Handle, 'open', PChar(AppData.Wiki), nil, nil, SW_SHOWNORMAL);
        AppData.Free;
    end;
end;

Can anyone point me in a direction to dynamically use the mousedown event without declaring the component ahead of time? Appdata is a separate pas file containing all the needed information on each application in case anyone is wondering.

Also please forgive my rather horrendous code, I know it could use a lot of work.


I agree that you should not use the Hint property. Not least because you may at some point in time wish to use the Hint property for something else. I am also somewhat dubious of solutions that use Tag.

I think I would use an instance of TDictionary<TSpeedButton,TAppPaths> to map between buttons and the application details. Here I'm imagining that TAppPaths is a record containing two strings, one for the left click and one for the right click, e.g.

TAppPaths= record
  Left: string;
  Right: string;
end; 

For sake of argument, let us suppose that this instance is called ButtonDetails.

When ever you add a new button you write code like this:

AppPaths.Left := AppDetails.Exe;
AppPaths.Right := AppDetails.SomeOtherFunction;
ButtonDetails.Add(NewButton, AppPaths);

Then in the form's mouse event handler you write it like this:

AppPaths := ButtonDetails[Sender as TSpeedButton];

And now AppPaths has both paths ready for you to use.

This idea can easily be extended to include as much information as you like in the TAppPaths record.

As an aside, I think you should be handling MouseUp rather than MouseDown since in Windows, buttons are clicked when you release the mouse button rather than when you press it.


The Sender of the event is the button, so save the "appData" into button's tag (when you create it) and then in the mouse event use it, ie

procedure TForm3.CreateAppButton(sBtnCapt: string);
...
begin
    AppData := TAppDetails.Create(sBtnCapt);
    with NewButton do
    begin
       Tag := NativeInt(AppData);
       ...
    end;
    //AppData.Free; // NB! do not free here!
end;

procedure TForm3.btnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;X, Y: Integer);
var AppData: TAppDetails;
begin
    ...
    else if Button = mbRight then
    begin
        AppData := TAppDetails((Sender as TSpeedButton).Tag);
        // use the appData
        ShellExecute(self.Handle, 'open', PChar(AppData.Wiki), nil, nil, SW_SHOWNORMAL);
        //AppData.Free; // NB! do not free here!
    end;
end;

procedure TForm3.DeleteAppButton(aBtn: TSpeedButton);
begin
   TAppDetails(aBtn.Tag).Free;
   aBtn.Free;
end;

Note that you have to free the objects you saved into button's tag when the buttons are freed (unless the buttons are not freed until app terminates, then you don't have to worry about it althought it isn't good style).


I'm not sure I understand the problem completely, but from what I've gathered so far, you probably need to do something like this:

…
sApp := TSpeedButton(Sender).Hint
…

whenever/wherever you need to retrieve the Hint information in the handler.


Do not use hints to store informations, use component Tag property as index on your information data array instead!

EDIT:

When you are creating button than you assign also button data in to button Tag like:

    TButtonData =record
      InfoStr1: string;
      InfoStr2: string;   
      a       : cardinal;
    //...
    end;

    TButtonDataAr = array of TButtonData;

var
  ButtonDataAr: TButtonDataAr;

when you creating button assign...

SetLength(ButtonDataAr, Length(ButtonDataAr) + 1);
ButtonDataAr[Length(ButtonDataAr)].InfoStr1 = 'TEST';
Button[n].Tag := Length(ButtonDataAr);               //Set array index as Tag

When you want to retrive information from sender just use component Tag as ButtonDataAr index,

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜