2006. december 14., csütörtök

Customize Toolbars at runtime


Problem/Question/Abstract:

Professional applications like Word or Excel let the user design the toolbars and let create new toolbars at runtime. This is't usually done with a little customize dialog and drag & drop functions.

Answer:

Professional applications like Word or Excel let the user design the toolbars and let create new toolbars at runtime. This ist usually done with a little customize dialog and drag & drop functions. This sample shows you, how to get this functionality simple into your program.

First of all, you must make some decissions to your program design. All functions, that can be put on a toolbar must defined in an Actionlist, because we need a list of functions that can be asigned to the toolbuttons. To minimize this work an Actionlist is the right thing, because wie can walk through the functions, have an automatic integration of the images for the toolbuttons via the imagelist, centralized shortcuts and have unique names for the functions to save and restore it.

The next thing is, that you should save and restore the customized toolbars to an inifile or the registry. This is done by the TFiletoolbar component included with this sample. Note, that you must assign the Actionlist to TFiletoolbars to get the save/restore work.

The customize dialog is built with formstyle fsStayOnTop, so the window is on top of our application. The form is displayed with the Show methode, because we must interact in the mainform for doing Drag & Drop.

For further details look at the TFiletoolbar documentation and to the source of the demo project. In the source you find detailed comments to anything that ist neccesary for get it working in your application.

Download the whole sample project including TFiletoolbar component for saving and restoring Toolbars.
http://www.helli.de/DelphiCorner/dc_tips/dc_tip4/dc_tip4.html

TToolbar97 component pack by Jordan Russel, Version 1.75 or higher available from http://www.jordanr.dhs.org/ (Freeware for non commercial use) is needed.

Example of Drag&Drop functions from Sample project:

//---------------------------------------------------------------
// Drag & Drop of Toolbar Buttons
// These functions are plugged to the OnDragOver, OnDragDrop and
// OnDragEnd property of any toolbar and any button on it.
// By user defined buttons and toolbars this is done automatic,
// by predefined toolbars you must plug in the functions in
// Objectinspector
//---------------------------------------------------------------

procedure TForm1.ToolbarDragOver(Sender, Source: TObject; X,
  Y: Integer; State: TDragState; var Accept: Boolean);
// This function must be plugged to the OnDragOver property of
// any toolbars and toolbuttons
//
// Check if Dropping is allowed
begin
  if Source is TListView then
    // Docking allowed only from CustomizeDialog Command Listview
    Accept := (Source as TListView).Name = CustomizeDialog.Commands.Name;
end;

procedure TForm1.ToolbarDragDrop(Sender, Source: TObject; X, Y: Integer);
// This function must be plugged to the OnDragDrop property of
// any toolbars and toolbuttons
//
// Handler for TToolbutton97 objects for dropping from CustomizeDialog
var
  t: TListView;
  act: TAction;
  ti: TListItem;
  tb, tb2: TToolbarButton97;
  ftb: TFileToolbar;
  oi: Integer;
begin
  if Source is TListView then
  begin // Is it from the Listview?
    t := Source as TListView;
    if Assigned(t) then
    begin
      // Get the selected item, it holds the desired action
      ti := t.Selected;
      if Assigned(ti) then
      begin
        // The action is stored in the data property of the item
        act := ti.Data;
        if Assigned(act) then
        begin
          // create a toolbutton on the fly
          tb := TToolbarButton97.Create(self);
          if Assigned(tb) then
          begin
            tb.Images := ImageList1; // Assign the Imagelist
            tb.DisplayMode := dmGlyphOnly; // display only the image
            // mode is turned to dmManual when leaving the
            // CustomizeDialog but to handle Drag&Drop, it must be
            // dmAutomatic by now
            tb.DragMode := dmAutomatic;
            tb.Action := act; // the desired Action
            // Assign the handlers
            tb.OnDragDrop := ToolbarDragDrop;
            tb.OnDragOver := ToolbarDragOver;
            tb.OnEndDrag := ToolbarEndDrag;
            // Hints like parent
            tb.ParentShowHint := True;
            // Look for the place to add the button on the toolbar
            ftb := nil;
            oi := x div tb.Width;
            // Convert Position from pixel to number of buttons
            if Sender is TFileToolbar then
            begin
              // dropped direct to the toolbar?
              ftb := Sender as TFileToolbar;
            end
            else if Sender is TToolbarButton97 then
            begin
              // placed on an other button?
              tb2 := Sender as TToolbarButton97;
              if Assigned(tb2) then
              begin
                // Get parent and Orderindex of the button
                ftb := tb2.Parent as TFileToolbar;
                oi := ftb.OrderIndex[tb2];
              end;
            end;
            if Assigned(ftb) then
            begin // We have a parent...
              // generate a unique name for the button
              tb.Name := 'tbB' + CustomizeDialog.DateStamp;
              // Insert the button on the toolbar
              ftb.InsertControl(tb);
              ftb.OrderIndex[tb] := oi; // and set the Orderindex
            end;
          end;
        end;
      end;
    end;
  end;
end;

procedure TForm1.ToolbarEndDrag(Sender, Target: TObject; X, Y: Integer);
// This function must be plugged to the OnEndDrag property of any
// toolbutton. The toolbars must not have this, because you cant
// throw them out of the program...
//
// Handler for TToolbarbutton97 objects to throw 'em out
// of the Toolbar
var
  tb: TToolbarButton97;
  ftb: TFileToolbar;
begin
  if not Assigned(Target) then
  begin
    // No target > so throw the button away
    tb := Sender as TToolbarButton97;
    if Assigned(tb) then
    begin
      ftb := tb.Parent as TFileToolbar;
      // Delete the button
      if Assigned(ftb) then
        ftb.RemoveControl(tb);
    end;
  end;
end;

Nincsenek megjegyzések:

Megjegyzés küldése