Page 1 of 1

How to save changed attributes to a dwg?

Posted: 20 Feb 2017, 20:35
by Quedlin
Hello,

this is what I want to do:
I want to open a dwg file, read all the blocks with attributes and show them in a string grid.
Then I want to manually change some values and save the changes to the dwg file.

What I did already:
I have build a form with 3 buttons: "Open and read", "Change attribute", "Save to file" an a string grid for showing the vales of the attributes.
I can open a file and read the all the blocks and attributes.

But how can I save the changes back to the dwg file?

This is how my formular looks like: (http://www.fotos-hochladen.net/view/test5n2ftq8m7l.png)
Image

I am not a professional sofware programmer, so I'm sorry for asking such simple things.

I watched the demo of "DXFExporter", but there was only an example of saving a canvas to a dxf file.

Thank you for your help!

Re: How to save changed attributes to a dwg?

Posted: 21 Feb 2017, 23:19
by support
Hello,

To change the block attribute value in the loaded drawing, you can use the following routine:

Code: Select all

procedure ChangeBlockAttribute(ACADImage: TsgCADImage; const ABlockName, AttribName, ANewValue: string);
var
  I: Integer;
  vDXFBlock: TsgDXFBlock;
  vDXFAttdef: TsgDXFAttdef;
begin
  if not Assigned(ACADImage) or (ABlockName = '') then Exit;
  vDXFBlock := ACADImage.Converter.BlockByName(ABlockName);
  if Assigned(vDXFBlock) then
    for I := 0 to vDXFBlock.Count - 1 do
    begin
      if (vDXFBlock.Entities[I].EntType = ceAttdef) then
      begin
        vDXFAttdef := vDXFBlock.Entities[I] as TsgDXFAttdef;
        if (vDXFAttdef.Tag = AttribName) then
        begin
          vDXFAttdef.Value := ANewValue;
          ACADImage.Converter.Loads(vDXFAttdef);
          ACADImage.Converter.Loads(vDXFBlock);
          Break;
        end;
      end;
    end;
end;
After that you can save the changes back to the DWG file using this code:

Code: Select all

procedure SaveToDWGFile(ACADImage: TsgCADImage; AFileName: string);
var
  vCADtoDWG: TsgCADtoDWG;
begin
  if not Assigned(ACADImage) then Exit;
  vCADtoDWG := TsgCADtoDWG.Create(ACADImage);
  try
    vCADtoDWG.SaveToFile(AFileName);
  finally
    vCADtoDWG.Free;
  end;
end;
Mikhail

Re: How to save changed attributes to a dwg?

Posted: 24 Feb 2017, 16:10
by Quedlin
Hello Mikhail,

thanks a lot for your help!

I inserted your code into my project. Now the dwg can be saved without any errors. Unfortunately the values are not changed in the saved dwg.

Here is the code of my project. I hope that you can help me getting my problem solved.

Button1: open a dwg file and reading the values of all attributes
Button3: changing the value in Edit3 to the selected attribute and saving the dwg file
edit1: shows the selected block name (selected by clicking into the StringGrid)
edit2: shows the selected attribute name (selected by clicking into the StringGrid)
edit3: there the new value can be edited

Code: Select all

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Grids, CADImage, DXFConv, sgConsts, CADToDWG, DXF, DWG;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button3: TButton;
    StringGrid1: TStringGrid;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    OpenDialog1: TOpenDialog;
    SaveDialog1: TSaveDialog;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
      var CanSelect: Boolean);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  vDrawing: TsgCADImage;  // a class for reading all the supported formats // global variable for keeping the file loaded in memory

implementation

{$R *.dfm}

procedure ChangeBlockAttribute(ACADImage: TsgCADImage; const ABlockName, AttribName, ANewValue: string);
var
  I: Integer;
  vDXFBlock: TsgDXFBlock;
  vDXFAttdef: TsgDXFAttdef;
begin
  if not Assigned(ACADImage) or (ABlockName = '')
  then showmessage('Fehler');
  vDXFBlock := ACADImage.Converter.BlockByName(ABlockName);
  if Assigned(vDXFBlock) then
    for I := 0 to vDXFBlock.Count - 1 do
    begin
      if (vDXFBlock.Entities[I].EntType = ceAttdef) then
      begin
        vDXFAttdef := vDXFBlock.Entities[I] as TsgDXFAttdef;
        if (vDXFAttdef.Tag = AttribName) then
        begin
          vDXFAttdef.Value := ANewValue;
          ACADImage.Converter.Loads(vDXFAttdef);
          ACADImage.Converter.Loads(vDXFBlock);
          Break;
        end;
      end;
    end;
end;

procedure SaveToDWGFile(ACADImage: TsgCADImage; AFileName: string);
var
  vCADtoDWG: TsgCADtoDWG;
begin
  if not Assigned(ACADImage) then Exit;
  vCADtoDWG := TsgCADtoDWG.Create(ACADImage);
  try
    vCADtoDWG.SaveToFile(AFileName);
  finally
    vCADtoDWG.Free;
  end;
end;

// Open a DWG file an reading the attributes and values
procedure TForm1.Button1Click(Sender: TObject);
const
  Exts: array[0..1] of string = ( '.dxf', '.dwg');
var
  I, J, K, spalte, reihe: Integer;
  vFileExt: string;
  //vDrawing: TsgCADImage;  // disabled for keeping the file loaded in memory, vDrawing is global variable
  // An insert is a block reference. Several inserts can reference to the same block.
  vInsert: TsgDXFInsert;
begin
  if not OpenDialog1.Execute
  then Exit;
  for reihe:= StringGrid1.RowCount-1 downto 0 do     // clearing the StringGrid if "open"-Button is pressed again
   begin
    for spalte:= StringGrid1.ColCount-1 downto 0 do
     begin
      StringGrid1.Cells[spalte, reihe]:= '';
     end;
   end;
   StringGrid1.RowCount:= 1;
  vFileExt := ExtractFileExt(LowerCase(OpenDialog1.FileName));
  // Create an instance of TsgCADImage descendant depending on a file extension
  case StrIndex(vFileExt, Exts) of
    0:	vDrawing := TsgCADdxfImage.Create;   // for DXF files
    1:	vDrawing := TsgDWGImage.Create;      // for DWG files
  end;
  vDrawing.LoadFromFile(OpenDialog1.FileName);

  // Set a default layout as the current
  vDrawing.CurrentLayout := vDrawing.Layouts[vDrawing.Converter.DefaultlayoutIndex];

  K := 0;
  StringGrid1.RowCount:= 1;
  StringGrid1.Cells[0,0]:= 'Block Name';
  StringGrid1.Cells[1,0]:= 'Attribut Name';
  StringGrid1.Cells[2,0]:= 'Attribut aktueller Wert';
  StringGrid1.Cells[3,0]:= 'Attribut neuer Wert';

  // Searching entities in the current layout of the drawing
  for I := 0 to vDrawing.CurrentLayout.Count - 1 do
  begin
    if vDrawing.CurrentLayout.Entities[I].EntType = ceInsert then
    begin
      vInsert := TsgDXFInsert(vDrawing.CurrentLayout.Entities[I]);
      for J := 0 to vInsert.Attribs.Count - 1 do
      begin
        StringGrid1.RowCount:= StringGrid1.RowCount+1;
        StringGrid1.Cells[0,K+J+1]:= vInsert.Block.Name;
        StringGrid1.Cells[1,K+J+1]:= TsgDXFAttrib(vInsert.Attribs[J]).Tag;
        StringGrid1.Cells[2,K+J+1]:= TsgDXFAttrib(vInsert.Attribs[J]).Value;
      end;
      K := K + vInsert.Attribs.Count;
    end;
  end;
  //vDrawing.Free;           // I disabled this line for keeping the drawing loaded in memory
  Label2.Caption:= IntToStr(StringGrid1.RowCount-1);
  Label3.Caption:= ExtractFileName(OpenDialog1.FileName);
end;

// Overwrite old values of attributes and saving the DWG file
procedure TForm1.Button3Click(Sender: TObject);
begin
 if not SaveDialog1.Execute
 then Exit;
 ChangeBlockAttribute(vDrawing, edit1.text, edit2.text, edit3.Text);   // all edit fields only for testing
 SaveToDWGFile(vDrawing, SaveDialog1.FileName);
 vDrawing.Free;       //  keeping the file loaded in memory
end;

// clicking on a cell takes the values to edit1 (Block name), and edit2 (Attribute Name)
procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol,
  ARow: Integer; var CanSelect: Boolean);
begin
  label7.Caption:= 'Zeile: '+IntToStr(ARow)+' / Spalte: '+intToStr(ACol);
  Edit1.Text:= StringGrid1.Cells[0,ARow];
  Edit2.Text:= StringGrid1.Cells[1,ARow];
end;

end.
THANKS A LOT FOR YOUR HELP!

Re: How to save changed attributes to a dwg?

Posted: 24 Feb 2017, 17:45
by support
Hello,

The problem is that your code reads attributes (TsgDXFAttrib) from the block references (TsgDXFInsert), while my routine changes the attribute definitions (TsgDXFAttdef) in the block definition (TsgDXFBlock). You said that you want to open a dwg file, read all the blocks with attributes and show them in a string grid, so I thought you are reading TsgDXFBlock objects.


Mikhail