使用Delphi中的动态按钮的MouseDown事件

时间:2011-08-05 01:25:05

标签: delphi delphi-2010

我从动态加载的数组动态创建按钮。我在按钮提示中存储了一条所需信息。

    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;

我的问题出现在鼠标按下事件上。我想以某种方式使用按钮提示属性中存储的信息来触发所需的操作。你可以看到我在左键单击中尝试的内容以及右键单击的来源。设计正确的单击方式需要我输入~80它还要求我声明表单上的每个按钮,以便我可以构建和编译。

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(self.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;

有人能指出我在没有提前声明组件的情况下动态使用mousedown事件的方向吗? Appdata是一个单独的pas文件,包含每个应用程序所需的所有信息,以防有人想知道。

另外请原谅我可怕的代码,我知道它可以用很多工作。

4 个答案:

答案 0 :(得分:4)

我同意您不应使用Hint属性。尤其是因为您可能在某个时间点希望将Hint属性用于其他内容。我也有点怀疑使用Tag的解决方案。

我想我会使用TDictionary<TSpeedButton,TAppPaths>的实例在按钮和应用程序详细信息之间进行映射。在这里,我想象TAppPaths是一个包含两个字符串的记录,一个用于左键单击,另一个用于右键单击,例如。

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

为了论证,让我们假设这个实例叫做ButtonDetails

当您添加新按钮时,您可以编写如下代码:

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

然后在表单的鼠标事件处理程序中,您可以这样写:

AppPaths := ButtonDetails[Sender as TSpeedButton];

现在AppPaths已准备好让您使用这两条路径。

可以轻松扩展此提示,以便在TAppPaths记录中包含尽可能多的信息。

顺便说一句,我认为您应该处理MouseUp而不是MouseDown,因为在Windows中,当您松开鼠标按钮而不是按下按钮时,会单击按钮。

答案 1 :(得分:2)

事件的Sender是按钮,所以将“appData”保存到按钮的标签中(当你创建它时),然后在鼠标事件中使用它,即

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;

请注意,当释放按钮时,您必须将保存的对象释放到按钮的标记中(除非在应用程序终止之前不释放按钮,然后您不必担心它不是好的样式)

答案 2 :(得分:2)

我不确定我是否完全理解这个问题,但是从目前为止我收集的内容来看,你可能需要这样做:

…
sApp := TSpeedButton(Sender).Hint
…

随时随地需要检索处理程序中的Hint信息。

答案 3 :(得分:0)

不要使用提示来存储信息,而是使用组件标记属性作为信息数据数组的索引!

编辑:

当您创建按钮时,您还将按钮数据分配到按钮Tag,如:

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

    TButtonDataAr = array of TButtonData;

var
  ButtonDataAr: TButtonDataAr;

创建按钮时...

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

如果您想从发件人那里检索信息,只需将标记作为 ButtonDataAr 索引,