Search Results for

    Show / Hide Table of Contents

    Working with Diagram Studio programmatically

    Inserting objects in diagram

    To insert objects in diagram, you must:

    1. Creates the object, instantiating the class of object.

    2. Sets the owner of object as the same owner of the diagram.

    3. Sets all other visual properties of the object you might want to change.

    4. Sets the diagram property to the diagram component.

    Example:

    MyBlock := TDiagramBlock.Create(atDiagram1.Owner);
    with MyBlock do
    begin
      Left := 10;
      Top := 10;
      Width := 150;
      Height := 50;
      Diagram := atDiagram1;
    end;
    

    Removing an object from diagram

    To remove an object from the diagram, simply destroy the object. Some examples:

    MyDiagramBlock1.Free; //Destroys the object MyDiagramBlock1
    
    {Destroy all lines in diagram}
    while atDiagram.LinkCount > 0 do
      atDiagram.Links[0].Free;
    

    Alternatively, you can remove the currently selected objects in diagram:

    atDiagram1.DeleteSelecteds;
    

    Adding a line between two blocks (linking blocks)

    A line start (or end) can be attached to a link point. To link two blocks, you must attach the start of the line to a block linkpoint, and attach the end of line to another block linkpoint. Example:

    MyLine := TDiagramLine.Create(atDiagram1.Owner);
    with MyLine do
    begin
      Diagram := atDiagram1;
      SourceLinkPoint.AnchorLink := SomeBlock.LinkPoints[0]; //link start point to someblock
      TargetLinkPoint.AnchorLink := AnotherBlock.LinkPoints[1]; // link end point to anotherblock
    end;
    

    Creating a TDiagramPolyLine: line with multiple points

    The Handles property of a diagram line control the position of its intermediate points. That's valid for all line types, including polylines, bezier, side lines, etc:

    curDataBlock := TDiagramPolyLine.Create(atDiagram1.Owner);
    with curDataBlock do
    begin
      Handles.Clear;
      Handles.Add.OrPoint := Dot(49,115);
      Handles.Add.OrPoint := Dot(151,179);
      Handles.Add.OrPoint := Dot(191,124);
      Handles.Add.OrPoint := Dot(212,84);
      Diagram := atDiagram1;
    end;
    

    Using a metafile as the block shape

    If you want to use a metafile picture as the block shape, you need to load the metafile to block, and also set the shape to none, so the shape block is not drawn, only the picture. Example:

    with atDiagram1.Blocks[0] do
    begin
      Shape := bsNoShape;
      Picture.LoadFromFile('mymetafile.wmf');
    end;
    

    Creating linkpoints in a block

    To create linkpoints, the LinkPoints collection must be used. Each linkpoint is a collection item. The position of the linkpoint must be indicated as a relative point related to the rect specified by the Drawer.OriginalRect property. By default, OriginalRect is (0, 0, 100, 100), making it easy to define link points positions in terms of % of block width/height.

    The following example, from FlowchartBlocks.pas unit, shows how to define four link points for the block, in the top, left, right and bottom sides of the block, in the middle of each side segment.

    procedure TFlowchartBlock.UpdateLinkPoints;
    begin
      LinkPoints.Clear;
      with Drawer.OriginalRect do
      begin
        LinkPoints.Add((Right - Left) / 2, Top, aoUp);
        LinkPoints.Add((Right - Left) / 2, Bottom, aoDown);
        LinkPoints.Add(Left, (Bottom - Top) / 2, aoLeft);
        LinkPoints.Add(Right, (Bottom - Top) / 2, aoRight);
      end;
    end;
    

    Accessing TextCell of a line object

    The line objects has at least one text cell defined by default. If you want to access a text cell of a TDiagramLine object, for example, you can use this code:

    TextCell := LinkLine.TextCells[0];
    

    Changing category of blocks in toolbar

    Calling RegisterDControl for any existing block will re-register it. So it's possible to change the category, or caption for the block. The following code "moves" all the blocks to the "MyBlocks" category, and sets that category in the toolbar.

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      DiagramToolBar1.Category := 'MyBlocks';
    
      RegisterDControl(TDiagramBlock, '', 'Simple block', 'MyBlocks');
      RegisterDControl(TDiagramLine, '', 'Line', 'MyBlocks');
      RegisterDControl(TTextBlock, '', 'Text block', 'MyBlocks');
      RegisterDControl(TDiagramSideLine, '', 'Side line', 'MyBlocks');
    
      DiagramToolBar1.Rebuild;
    end;
    

    Prevent a line from being dettached from a block

    The following sample code is obsolete since version 2.1, which introduced a new TDiagramLine.RequiresConnections property. If you don't want a line to be dettached from a block, just set its RequiresConnections property to true:

    DiagramLine1.RequiresConnections := true;
    

    But for learning purposes, we will keep the old code here:


    The following sample code does not allow an user to remove a line from a linkpoint unless it connects it to another linkpoint

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, atDiagram, ExtCtrls, DiagramExtra, FlowChartBlocks;
    
    const
      CM_CONNECTLINKPOINTS = WM_USER + 1000;
    
    type
      TForm1 = class(TForm)
        DiagramToolBar1: TDiagramToolBar;
        atDiagram1: TatDiagram;
        procedure atDiagram1LinkRemoved(Sender: TObject;
          ADControl: TDiagramControl; ALink: TCustomDiagramLine;
          ALinkPoint: TLinkPoint);
      private
        procedure CMConnectLinkPoints(var Msg: TMessage); message CM_CONNECTLINKPOINTS;
      public
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.atDiagram1LinkRemoved(Sender: TObject;
      ADControl: TDiagramControl; ALink: TCustomDiagramLine;
      ALinkPoint: TLinkPoint);
    var
      c: integer;
      BlockLinkPoint: TLinkPoint;
    begin
      if not (csDestroying in ALink.ComponentState) then 
        if ADControl is TCustomDiagramBlock then
        begin
          BlockLinkPoint := nil;
          // Find the linkpoint of the block where the line was connected to
          for c := 0 to TCustomDiagramBlock(ADControl).LinkPoints.Count - 1 do
            if ALinkPoint.AnchorLink = TCustomDiagramBlock(ADControl).LinkPoints[c] then
            begin
              BlockLinkPoint := TCustomDiagramBlock(ADControl).LinkPoints[c];
              break;
            end;
          // Reconnect line to the block link point
          PostMessage(Handle, CM_CONNECTLINKPOINTS, integer(ALinkPoint), integer(BlockLinkPoint));
        end;
    end;
    
    procedure TForm1.CMConnectLinkPoints(Var Msg: TMessage);
    begin
      if TLinkPoint(Msg.wParam).AnchorLink = nil then
        TLinkPoint(Msg.wParam).AnchorLink := TLinkPoint(Msg.LParam);
    end;
    
    end.
    

    Using Diagram Studio in a DLL

    Diagram Studio has some restrictions in order to be used in a DLL. It's a limitation of GDI+ graphical library from Microsoft. Diagram Studio initializes and finalizes the GDI+ library automatically, except when it's inside a DLL (IsLibrary = true), since doing that can cause deadlocks or system crashes.

    So in order to use Diagram Studio in a DLL, you must initialize and finalize GDI+ library by yourself, from your EXE application. We have public procedures in Diagram units that make that job for you, so you may just export those functions in your DLL and call them from your application.

    The DLL containing Diagram Studio must export the InitializeGdiPlus and FinalizeGdiPlus procedures, both declared at DgrGdipObj unit.

    library DiagramDLL;
    
    uses
      SysUtils,
      Classes,
      DgrGdipObj;
    
    {$R *.res}
    
    exports
      InitializeGdiPlus,
      FinalizeGdiPlus;
    
    begin
    end.
    

    The application using DLL must call InitializeGdiPlus before using Diagram Studio (or at beginning of program) and FinalizeGdiPlus before it terminates.

    procedure InitializeGdiPlus; external 'DiagramDLL.dll';
    procedure FinalizeGdiPlus; external 'DiagramDLL.dll';
    
    procedure TestLoadUnloadDiagramDLL;
    var 
      HInst: HMODULE;
    begin
      HInst := LoadLibrary('DiagramDLL.dll');
      if HInst <> 0 then 
      begin
        InitializeGdiPlus;
        ShowMessage('Loaded');
        FinalizeGdiPlus;
        if FreeLibrary(HInst) then
          ShowMessage('Unloaded');
      end 
      else
        ShowMessage('Not Loaded!');
    end;
    

    Auto-layout

    You can perform an automatic layout of the diagram. To do that, just call method ApplyLayout passing a valid layout algorithm object:

    atDiagram1.ApplyLayout(Layout);
    

    Currently there is only one layout algorithm available, which is TForceLayout, declared in unit AutoLayout.Force:

    uses 
      AutoLayout.Force;
    
    var
      Layout: TForceLayout;
    begin
      Layout := TForceLayout.Create;
      try
        Layout.DisplacementThreshold := 10;
        Layout.DefaultSpringLength := 100;
        Layout.MaxIterations := 500;
        Layout.Damping := 0.5
        Layout.RepulsionConstant := 100000;
        Layout.AttractionConstant := 0.2
        atDiagram1.ApplyLayout(Layout);
      finally
        Layout.Free;
      end;
    end;
    

    Each layout algorithm has its own parameters. The code above shows the available parameters for force algorithm. You don't need to set any of those, since default values are already defined.

    In This Article
    Back to top TMS Diagram Studio v4.31
    © 2002 - 2025 tmssoftware.com