【问题标题】:Delphi - ListView or similar with owner draw buttonDelphi - ListView 或类似的所有者绘制按钮
【发布时间】:2010-04-20 12:36:57
【问题描述】:

如何在每行创建一个带有按钮的列表视图(或类似视图)?按钮需要能够根据需要在每行上具有不同的文本/颜色。

我确信 Virtual Treeview 非常适合这个,但我对它有点迷茫。

谢谢

-布拉德

【问题讨论】:

    标签: delphi virtualtreeview


    【解决方案1】:

    使用 virtualtreeview ......将 vstButton 添加到您的用途中,并在对象检查器中选择您的 Virtualtreeview 并为您的树设置以下事件:

    procedure TForm1.VSTCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; out EditLink: IVTEditLink);
    begin
      EditLink:=TStringEditLink.Create;
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      VST.NodeDataSize := SizeOf(TTreeData);
      AddRandomNodesToTree(Vst);
    end;
    
    procedure TForm1.VSTFreeNode(Sender: TBaseVirtualTree;
      Node: PVirtualNode);
    var
     Data: PTreeData;
    begin
     Data:=VST.GetNodeData(Node);
     if Assigned(Data) then begin
       Data^.Column0 := '';
       Data^.Column1 := '';
       Data^.Column2 := '';
     end;
    end;
    
    procedure TForm1.VSTGetText(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
      var CellText: string);
    var
      Data: PTreeData;
    begin
      Data := VST.GetNodeData(Node);
      case Column of
        0: CellText := Data^.Column0;
        1: CellText := Data^.Column1;
        2: CellText := Data^.Column2;
      end;
    end;
    
    procedure TForm1.VSTNewText(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; NewText: string);
    Var
      Data: PTreeData;
    begin
      Data := VST.GetNodeData(Node);
      Case Column of
         0: Data^.Column0:= NewText;
         1: Data^.Column1:= NewText;
         2: Data^.Column2:= NewText;
      End;
    end;
    
    procedure TForm1.VSTPaintText(Sender: TBaseVirtualTree;
      const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
      TextType: TVSTTextType);
    Var
     Data: PTreeData;
    begin
      if Odd(Node.Index) then 
        TargetCanvas.Font.Color:= clRed;
    end;
    

    ...这假设记录是:

    type
      PTreeData = ^TTreeData;
      TTreeData = record
        Column0: String;
        Column1: String;
        Column2: String;
      end;
    

    ...添加以下单位:

    unit vstButton;
    
    
    interface
    
    uses
      Classes, SysUtils, Forms, Controls, Graphics, Dialogs, VirtualTrees,
      messages, windows, StdCtrls, ShlObj;
    
    type
      TStringEditLink = class(TInterfacedObject, IVTEditLink)
      private
        FEdit: TWinControl;
        FTree: TVirtualStringTree;
        FNode: PVirtualNode;
        FColumn: Integer;
        FSelectedFolder: string;
      protected
        procedure ButtonClick(Sender: TObject);
      public
        destructor Destroy; override;
        function BeginEdit: Boolean; stdcall;
        function CancelEdit: Boolean; stdcall;
        function EndEdit: Boolean; stdcall;
        function GetBounds: TRect; stdcall;
        function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall;
        procedure ProcessMessage(var Message: TMessage); stdcall;
        procedure SetBounds(R: TRect); stdcall;
      end;
    
      function GetFolderDialog(Handle: Integer; Caption: string; var strFolder: string): Boolean;
    
    implementation
    
    destructor TStringEditLink.Destroy;
    begin
      FEdit.Free;
      inherited;
    end;
    
    procedure TStringEditLink.ButtonClick(Sender: TObject);
    var
      s: string;
    begin
      s := 'c:\';
      if GetFolderDialog(Application.Handle, 'Select a folder', s) then
        FSelectedFolder := s;
    
      FTree.EndEditNode;
      FTree.setfocus;
    end;
    
    function TStringEditLink.BeginEdit: Boolean;
    begin
      Result := True;
      FSelectedFolder := FTree.Text[FNode, FColumn];
      TButton(FEdit).CAption := FTree.Text[FNode, FColumn];
      FEdit.Show;
      FEdit.SetFocus;
    end;
    
    function TStringEditLink.CancelEdit: Boolean;
    begin
      Result := True;
      FEdit.Hide;
      FTree.EndEditNode;
      FTree.setfocus;
    end;
    
    function TStringEditLink.EndEdit: Boolean;
    var
      S: WideString;
    begin
      Result := True;
      FTree.Text[FNode, FColumn] := FSelectedFolder;
    
      FTree.InvalidateNode(FNode);
      FEdit.Hide;
      FTree.SetFocus;
    end;
    
    function TStringEditLink.GetBounds: TRect;
    begin
      Result := FEdit.BoundsRect;
    end;
    
    function TStringEditLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean;
    begin
      Result := True;
      FTree := Tree as TVirtualStringTree;
      FNode := Node;
      FColumn := Column;
    
      FEdit.Free;
      FEdit := nil;
    
      FEdit := TButton.Create(nil);
       with FEdit as TButton do
         begin
              Visible := False;
              Parent := Tree;
              Font.Color := FTree.Colors.HeaderHotColor;
              OnClick := ButtonClick;
          end;
    end;
    
    procedure TStringEditLink.ProcessMessage(var Message: TMessage);
    begin
      FEdit.WindowProc(Message);
    end;
    
    procedure TStringEditLink.SetBounds(R: TRect);
    var
      Dummy: Integer;
    begin
      FTree.Header.Columns.GetColumnBounds(FColumn, Dummy, R.Right);
      FEdit.BoundsRect := R;
    end;
    
    //------------------------------------------------------------------------------\\
    
    function BrowseCallbackProc(hwnd: HWND; uMsg: UINT; lParam: LPARAM; lpData: LPARAM): Integer; stdcall;
    begin
      if (uMsg = BFFM_INITIALIZED) then
        SendMessage(hwnd, BFFM_SETSELECTION, 1, lpData);
      BrowseCallbackProc := 0;
    end;
    
    function GetFolderDialog(Handle: Integer; Caption: string; var strFolder: string): Boolean;
    const
      BIF_STATUSTEXT           = $0004;
      BIF_NEWDIALOGSTYLE       = $0040;
      BIF_RETURNONLYFSDIRS     = $0080;
      BIF_SHAREABLE            = $0100;
      BIF_USENEWUI             = BIF_EDITBOX or BIF_NEWDIALOGSTYLE;
    
    var
      BrowseInfo: TBrowseInfo;
      ItemIDList: PItemIDList;
      JtemIDList: PItemIDList;
      Path: PChar;
    begin
      Result := False;
      Path := StrAlloc(MAX_PATH);
      SHGetSpecialFolderLocation(Handle, CSIDL_DRIVES, JtemIDList);
      with BrowseInfo do
      begin
        hwndOwner := GetActiveWindow;
        pidlRoot := JtemIDList;
        SHGetSpecialFolderLocation(hwndOwner, CSIDL_DRIVES, JtemIDList);
    
        { return display name of item selected }
        pszDisplayName := StrAlloc(MAX_PATH);
    
        { set the title of dialog }
        lpszTitle := PChar(Caption);//'Select the folder';
        { flags that control the return stuff }
        lpfn := @BrowseCallbackProc;
        { extra info that's passed back in callbacks }
        lParam := LongInt(PChar(strFolder));
      end;
    
      ItemIDList := SHBrowseForFolder(BrowseInfo);
    
      if (ItemIDList <> nil) then
        if SHGetPathFromIDList(ItemIDList, Path) then
        begin
          strFolder := Path;
          Result := True
        end;
    end;
    
    End.
    

    以上代码基于本网站上的代码: http://wiki.freepascal.org/VirtualTreeview_Example_for_Lazarus 如果您查看单元 vstButton,要获得 TEdit 或 TCombo...等...只需将任何 TButton 引用替换为 TEdit 或 TCombo 等...为其调整事件等...上面的链接代码实际上使用了综合体

    那个网站帮助我学习了如何使用 virtualtreeview 上面的代码将在每个单元格中插入一个 Tbutton,当您单击该按钮时,它将打开一个 BrowseForFolder 对话框并将结果插入到 virtualtreeview 单元格中 希望这会有所帮助

    您是否希望始终在单元格列中显示一个按钮?可以用图像模拟按钮...就像单元格一侧的下拉标记

    【讨论】:

    • 这应该可以工作... :) 我没想到要查看 Lazarus wiki
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-28
    • 1970-01-01
    相关资源
    最近更新 更多