BcadCapture.exe for Bricscad V13
■概要
編集中のすべての図面を切り替え、画面をキャプチャーします。※
キャプチャーした画像は、シート番号(またはページ番号)順にソートされ、画像をダブルクリックすると、編集中の図面が切り替わります。
また、キャプチャーとは関係なく、連続実行する LISP コマンドを1個登録できます。
※シート番号(またはページ番号)を取得すると、結構時間がかかります。
プロパティーバーの下に置いた時

プロパティーバーを隠すくらいの大きさにした時

すべてを表示させた時

■設定画面

■ご注意
・Bricscadのバージョン、OS環境(32bit/64bit)が違うと動かないと思います。
・キャプチャ時点の情報しか保持していませんので、Bricscadの図面構成が変わると、正しく動きません。
・キャプチャ位置が合わないときは、「高DPI設定では、画面のスケーリングを無効にする」をチェックしてみて下さい。

■ダウンロード
BcadCapture.zip
■ソースコード
unit BcadCaptureUnit;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs,BricscadApp_TLB, BricscadDb_TLB,
Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Grids, ComObj, IniFiles, Vcl.Buttons,
Vcl.Menus ;
type
TDwgDoc = record
Index : integer;
Name : string;
Comment : string;
end;
type
TForm2 = class(TForm)
DrawGrid1: TDrawGrid;
Panel1: TPanel;
ComboBox1: TComboBox;
SpeedButton1: TSpeedButton;
PopupMenu1: TPopupMenu;
N3: TMenuItem;
N1: TMenuItem;
N2: TMenuItem;
SpeedButton2: TSpeedButton;
SpeedButton3: TSpeedButton;
procedure FormDestroy(Sender: TObject);
procedure DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
procedure FormResize(Sender: TObject);
procedure DrawGrid1DblClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ComboBox1Change(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure N3Click(Sender: TObject);
procedure N2Click(Sender: TObject);
procedure SpeedButton2Click(Sender: TObject);
procedure SpeedButton3Click(Sender: TObject);
procedure DrawGrid1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
// 取得するブロック名と属性名
BlkName, BlkName1, BlkName2, AttName, AttName1, AttName2 : string;
AttFlag1, AttFlag2 : boolean;
// 連続実行するLISP
LspFileName : TFileName;
LspCmdName : string;
LspCommand : string;
end;
var
Form2: TForm2;
// キャプチャしたビットマップを保持
BmpAry : array of TBitMap;
// 図面名とその位置を保持
DwgDocAry : array of TDwgDoc;
// ビットマップの大きさ
BmpW, BmpH : integer;
// タイトル表示の高さ
TitleH1, TitleH2 : integer;
// シート名、ページ番号を表示する
CmtDispFlag : boolean;
// キャプチャ時、属性を取得
CmtGetFlag : boolean;
BcadActiveFlag : boolean;
implementation
{$R *.dfm}
uses BcadCaptureCfgUnit;
//****************************************
// 画面の指定位置をBitmapに変換
//****************************************
procedure CaptureToBmp(Lf, Tp, W, H: Integer; bmp: TBitmap);
const
CAPTUREBLT = $40000000;
var
hdcScreen : HDC;
begin
bmp.Width := W;
bmp.Height := H;
hdcScreen := CreateDC('DISPLAY', nil, nil, nil);
try
BitBlt( bmp.Canvas.Handle, 0, 0, W, H, hdcScreen, Lf, Tp, SRCCOPY or CAPTUREBLT);
finally
DeleteDC(hdcScreen);
end;
end;
//****************************************
// 属性の値を取得
//****************************************
function GetAttString(doc : AcadDocument; const BlkName : string; const TagName : string): string;
var
mspc : AcadModelSpace;
ent : AcadEntity;
blkref : AcadBlockReference;
attr : OleVariant;
att : AcadAttributeReference;
idisp : IDispatch;
j , n, m, k : integer;
begin
Result := '';
mspc := doc.ModelSpace;
if mspc.Count > 0 then begin
for j := 0 to mspc.Count - 1 do begin
ent := mspc.Item(j);
if 'AcDbBlockReference' = ent.EntityName then begin
blkref := ent as AcadBlockReference;
if blkref.HasAttributes then begin
if blkname = blkref.Name then begin
attr := blkref.GetAttributes;
n := VarArrayLowBound(attr, 1);
m := VarArrayHighBound(attr, 1);
for k := n to m do begin
// 個々の属性を取得
idisp := attr[k];
att := idisp as AcadAttributeReference;
if TagName = att.TagString then begin
Result := att.TextString;
Break;
end;
end;
break;
end;
end;
end;
end;
end;
end;
// *******************************
// DwgDocAryをソート
// *******************************
procedure SortDwgDocAry;
var
len, n, m : integer;
i, j: integer;
DwgDocTmp : TDwgDoc;
s, s1 : string;
begin
n := Length(DwgDocAry);
if n > 1 then begin
// コメント文字列の最大文字数
len := 0;
for i := 0 to n -1 do begin
m := DwgDocAry[i].Comment.Length;
if len < m then len := m;
end;
// 文字列比較のため同じ長さにする
for i := 0 to n -1 do begin
with DwgDocAry[i] do begin
m := Comment.Length;
if m < len then begin
for j := 1 to len - m do begin
Comment:= ' ' + Comment;
end;
end;
end;
end;
// ソート
for i := 0 to n - 2 do begin
s := DwgDocAry[i].Comment + ':' + DwgDocAry[i].Name;
for j := i + 1 to n - 1 do begin
s1 := DwgDocAry[j].Comment + ':' + DwgDocAry[j].Name;
if s1 < s then begin
DwgDocTmp := DwgDocAry[i];
DwgDocAry[i] := DwgDocAry[j];
DwgDocAry[j] := DwgDocTmp;
s := s1;
end;
end;
end;
end;
end;
procedure TForm2.ComboBox1Change(Sender: TObject);
var
idx : integer;
i : integer;
begin
with ComboBox1 do begin
idx := ItemIndex;
if idx >= 0 then
i := Integer(Items.Objects[idx])
else
i := -1;
end;
if (i >= 0) and (i < Length(DwgDocAry)) then begin
with DrawGrid1 do begin
Col := i mod ColCount;
Row := i div ColCount;
end;
end;
end;
procedure TForm2.DrawGrid1Click(Sender: TObject);
var
i : integer;
begin
with DrawGrid1 do
i := Row * ColCount + col;
ComboBox1.ItemIndex := i;
end;
procedure TForm2.DrawGrid1DblClick(Sender: TObject);
var
i, id : integer;
app : IAcadApplication;
docs : IAcadDocuments;
begin
with DrawGrid1 do begin
i := Row * ColCount + col;
if (i >= 0) and (i < Length(DwgDocAry)) then begin
try
app := GetActiveOleObject('BricscadApp.AcadApplication') as IAcadApplication;
docs := app.Documents;
id := DwgDocAry[i].Index;
ComboBox1.ItemIndex := i;
if id < docs.Count then begin
docs.Item(id).Activate;
if BcadActiveFlag then
// Bricscad をアクティブに
SetForegroundWindow(app.HWND);
end;
except
ShowMessage('有効な BricsCAD が見つかりません.');
end;
end;
end;
end;
// **************************
// キャプチャ画像を描画
// **************************
procedure TForm2.DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
var
i, w, h, dx, dy : integer;
idx : integer;
begin
with DrawGrid1 do begin
// 現在の表示位置
i := ARow * ColCount + Acol;
idx := -1;
if (i >= 0) and (i < Length(DwgDocAry)) then
idx := DwgDocAry[i].Index;
if (idx >= 0) and (idx < Length(BmpAry)) then begin
w := BmpAry[idx].Width;
h := BmpAry[idx].Height;
dx := (DefaultColWidth - w) div 2;
if not CmtDispFlag then
dy := (DefaultRowHeight - h - TitleH1) div 2
else
dy := (DefaultRowHeight - h - TitleH2) div 2;
with Canvas do begin
if not CmtDispFlag then
Draw(Rect.Left + dx, Rect.Top + dy + TitleH1, BmpAry[idx])
else
Draw(Rect.Left+dx,Rect.Top+dy + TitleH2, BmpAry[idx]);
// 背景を塗りつぶし
if (ARow = Row) and (ACol = Col) then
Brush.Color := clBlue
else
Brush.Color := clGray;
if not CmtDispFlag then
Rectangle(Rect.Left + 1, Rect.Top + 1, Rect.Right - 1, Rect.Top + TitleH1 + 1)
else
Rectangle(Rect.Left + 1, Rect.Top + 1, Rect.Right - 1, Rect.Top + TitleH2 + 1);
Font.Color := clWHITE;
// タイトルを描画
TextOut(Rect.Left + 3, Rect.Top + 3, ExtractFileName(DwgDocAry[i].Name));
// コメントを描画
if CmtDispFlag then
TextOut(Rect.Left + 3, Rect.Top + 3 + TitleH1 + 1, DwgDocAry[i].Comment);
// 標準の設定に戻す
Pen.Style := psSolid;
Brush.Style := bsClear;
Pen.Color := clGray;
Pen.Width := 1;
Rectangle(Rect);
end;
end
else begin
with Canvas do begin
Brush.Color := clWhite;
FillRect(Rect);
end;
end;
end;
end;
procedure TForm2.FormCreate(Sender: TObject);
var
ini : TIniFile;
begin
BmpH := 168;
BmpW := 240;
TitleH1 := 20;
TitleH2 := 42;
with DrawGrid1 do begin
DefaultColWidth := BmpW;
DefaultRowHeight := BmpH + 20;
Options := Options + [goThumbTracking];
end;
BlkName := 'TITLE';
AttName := 'ZSHEET';
BlkName1 := BlkName;
AttName1 := AttName;
BlkName2 := BlkName;
AttName2 := AttName;
AttFlag1 := True;
AttFlag2 := False;
// ダブルクリックで Bricscad をアクティブに
BcadActiveFlag := False;
// コメント表示
CmtDispFlag := True;
// キャプチャ時、コメントを取得
CmtGetFlag := True;
LspFileName := '';
LspCmdName := '';
LspCommand := '';
ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini'));
try
with Ini do begin
Top := ReadInteger('Form', 'Top', Top);
Left := ReadInteger('Form', 'Left', Left);
Width:= ReadInteger('Form', 'Width', Width);
Height := ReadInteger('Form', 'Height', Height);
if Left >= Screen.Width then Left := (Screen.Width + Width) div 2;
if Top >= Screen.Height then Top := (Screen.Height + Height) div 2;
BlkName1 := ReadString('Bcad', 'BlkName1', BlkName1);
BlkName2 := ReadString('Bcad', 'BlkName2', BlkName2);
AttName1 := ReadString('Bcad', 'AttName1', AttName1);
AttName2 := ReadString('Bcad', 'AttName2', AttName2);
AttFlag1 := ReadBool('Bcad', 'AttFlag1', AttFlag1);
AttFlag2 := ReadBool('Bcad', 'AttFlag2', AttFlag2);
BcadActiveFlag := ReadBool('Bcad', 'ActiveFlag', BcadActiveFlag);
CmtDispFlag := ReadBool('BcadCapt', 'CmtDispFlag', CmtDispFlag);
CmtGetFlag := ReadBool('BcadCapt', 'CmtGetFlag', CmtGetFlag);
LspFileName := ReadString('Bcad', 'LispFileName', LspFileName);
LspCmdName := ReadString('Bcad', 'LispCmdName', LspCmdName);
LspCommand := ReadString('Bcad', 'LispCommand', LspCommand);
// メニュー
N2.Caption := LspCmdName;
SpeedButton2.Caption := LspCmdName;
end;
finally
ini.Free;
end;
end;
procedure TForm2.FormDestroy(Sender: TObject);
var
i : integer;
ini : TIniFile;
begin
if Length(BmpAry) > 0 then begin
for i := 0 to Length(BmpAry) -1 do
BmpAry[i].Free;
end;
ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini'));
try
with Ini do begin
WriteInteger('Form', 'Top', Top);
WriteInteger('Form', 'Left', Left);
WriteInteger('Form', 'Width', Width);
WriteInteger('Form', 'Height', Height);
WriteString('Bcad', 'BlkName1', BlkName1);
WriteString('Bcad', 'BlkName2', BlkName2);
WriteString('Bcad', 'AttName1', AttName1);
WriteString('Bcad', 'AttName2', AttName2);
WriteBool('Bcad', 'AttFlag1', AttFlag1);
WriteBool('Bcad', 'AttFlag2', AttFlag2);
WriteBool('Bcad', 'ActiveFlag', BcadActiveFlag);
WriteBool('BcadCapt', 'CmtDispFlag', CmtDispFlag);
WriteBool('BcadCapt', 'CmtGetFlag', CmtGetFlag);
WriteString('Bcad', 'LispFileName', LspFileName);
WriteString('Bcad', 'LispCmdName', LspCmdName);
WriteString('Bcad', 'LispCommand', LspCommand);
end;
finally
ini.Free;
end;
end;
// ***************************
// フォームリサイズ
// ***************************
procedure TForm2.FormResize(Sender: TObject);
var
n, xcnt, ycnt:Integer;
begin
n := Length(BmpAry);
if n > 0 then begin
with DrawGrid1 do begin
xcnt := (Width - 23) div DefaultColWidth;
if xcnt=0 then xcnt:=1;
ycnt := n div xcnt;
if n mod xcnt > 0 then Inc(ycnt);
ColCount := xcnt;
RowCount := ycnt;
end;
end;
end;
procedure TForm2.N2Click(Sender: TObject);
var
app : IAcadApplication;
docs : IAcadDocuments;
adoc, doc : IAcadDocument;
i : integer;
begin
if (LspCommand <> '') then begin
try
app := GetActiveOleObject('BricscadApp.AcadApplication') as IAcadApplication;
adoc := app.ActiveDocument;
docs := app.Documents;
for i := 0 to docs.Count - 1 do begin
doc := docs.Item(i);
doc.Activate;
if LspFileName <> '' then
doc.SendCommand(#27 + '(load "' + LspFileName + '")' + #13#10);
doc.SendCommand(LspCommand + #13#10);
end;
adoc.Activate;
except
ShowMessage('有効な BricsCAD が見つかりません.');
end;
end;
end;
// ************************************
// 設定フォーム
// ************************************
procedure TForm2.N3Click(Sender: TObject);
begin
Form3 := TForm3.Create(Form2);
with Form3 do begin
try
Edit1.Text := BlkName1;
Edit2.Text := AttName1;
Edit3.Text := BlkName2;
Edit4.Text := AttName2;
Edit5.Text := BmpW.ToString;
Edit6.Text := BmpH.ToString;
Edit7.Text := TitleH1.ToString;
Edit8.Text := TitleH2.ToString;
CheckBox1.Checked := AttFlag1;
CheckBox2.Checked := AttFlag2;
CheckBox4.Checked := BcadActiveFlag;
CheckBox3.Checked := CmtGetFlag;
CheckBox5.Checked := CmtDispFlag;
Edit9.Text := LspFileName;
Edit10.Text := LspCommand;
Edit11.Text := LspCmdName;
if ShowModal = mrOk then begin
BlkName1 := Edit1.Text;
AttName1 := Edit2.Text;
BlkName2 := Edit3.Text;
AttName2 := Edit4.Text;
BmpW := StrToIntDef(Edit5.Text, BmpW);
BmpH := StrToIntDef(Edit6.Text, BmpH);
TitleH1 := StrToIntDef(Edit7.Text, TitleH1);
TitleH2 := StrToIntDef(Edit8.Text, TitleH2);
AttFlag1 := CheckBox1.Checked;
if AttFlag1 and (BlkName1 <> '') and (AttName1 <> '') then begin
BlkName := BlkName1;
AttName := AttName1;
end;
AttFlag2 := CheckBox2.Checked;
if AttFlag2 and (BlkName2 <> '') and (AttName2 <> '') then begin
BlkName := BlkName2;
AttName := AttName2;
end;
BcadActiveFlag := CheckBox4.Checked;
CmtGetFlag := CheckBox3.Checked;
CmtDispFlag := CheckBox5.Checked;
LspFileName := Edit9.Text;
LspCommand := Edit10.Text;
LspCmdName := Edit11.Text;
// メニュー
N2.Caption := LspCmdName;
SpeedButton2.Caption := LspCmdName;
end;
finally
Free;
end;
end;
end;
// ***********************************
// 画面キャプチャ
// ***********************************
procedure TForm2.SpeedButton1Click(Sender: TObject);
var
app : IAcadApplication;
docs : IAcadDocuments;
doc, docOrg : IAcadDocument;
limmax, limmin : OleVariant;
scrsize : OleVariant;
scrH, scrW : integer;
hnd : THandle;
ARect : TRect;
ALeft, ATop : integer;
gridMode : Integer;
ucsIcon : integer;
dwgName : TFileName;
i : integer;
idxOrg : integer;
scale : double;
begin
// Bricscad を見つける
try
if not Supports(GetActiveOleObject('BricscadApp.AcadApplication'), AcadApplication, app) then begin
ShowMessage('サポートされていません.');
exit;
end;
except
ShowMessage('有効な BricsCAD が見つかりません.');
Exit;
end;
docs := app.Documents;
// 自フォームを最小に
WindowState := wsMinimized;
Sleep(50);
try
if Length(BmpAry) > 0 then begin
for i := 0 to Length(BmpAry) -1 do
BmpAry[i].Free;
end;
SetLength(BmpAry, docs.Count);
SetLength(DwgDocAry, docs.Count);
with DrawGrid1 do begin
// 適当な大きさを確保
RowCount := docs.Count div ColCount;
if docs.Count mod ColCount > 0 then RowCount := RowCount + 1;
end;
// 最小化されていれば、最大にする
if app.WindowState = acMin then begin
app.WindowState := acMax;
end;
// アクティブドキュメントを取得
docOrg := app.ActiveDocument;
idxOrg := 0;
for i := 0 to docs.Count - 1 do begin
doc := docs.Item(i);
// 現在のドキュメントの位置
if doc = docOrg then idxOrg := i;
// 配列に格納
with DwgDocAry[i] do begin
Index := i;
Name := doc.Name;
// シート番号またはページ番号
if CmtGetFlag then
Comment := GetAttString(doc, BlkName, AttName)
else
Comment := '';
end;
doc.Activate;
// ファイル名を表示
dwgName := doc.Name;
// Bricscad をアクティブに
SetForegroundWindow(doc.HWND);
// 図面範囲を取得
limmax := doc.GetVariable('LIMMAX');
limmin := doc.GetVariable('LIMMIN');
// 図面範囲をズーム
app.ZoomWindow(limmin, limmax);
// グラフィック画面のサイズを取得
scrsize := doc.GetVariable('SCREENSIZE');
scrW := scrsize[0];
scrH := scrsize[1];
// グリッドの表示モードを取得
gridMode := doc.GetVariable('GRIDMODE');
// UCSアイコンの表示モードを取得
ucsICon := doc.GetVariable('UCSICON');
// グリッドを非表示に
if gridMode > 0 then
doc.SetVariable('GRIDMODE', 0);
// UCSアイコンを非表示に
if ucsIcon > 0 then
doc.SetVariable('UCSICON', 0);
// キャプチャするビットマップの大きさに縮小
if BmpH / BmpW < scrH / scrW then
scale := BmpW / scrW
else
scale := BmpH / scrH;
app.ZoomScaled(scale, 0);
// グラフィックウィンドウのハンドルを取得
hnd := FindWindowEx(app.ActiveDocument.HWND, 0, 'AfxFrameOrView100u', nil);
// ウィンドウの位置と大きさを取得
GetWindowRect(hnd, ARect);
// グラフィックウィンドウの左上座標
ALeft := ARect.Left;
ATop := ARect.Top;
// キャプチャ用ビットマップを作成
BmpAry[i] := TBitmap.Create;
BmpAry[i].PixelFormat := pf32bit;
// ビットマップの大きさ
BmpAry[i].Width := BmpW;
BmpAry[i].Height := BmpH;
// キャプチャ
CaptureToBmp(
ALeft + (scrW - BmpW) div 2,
ATop + (scrH - BmpH) div 2,
BmpAry[i].Width, BmpAry[i].Height, BmpAry[i]);
// ズームを元に戻す
app.ZoomWindow(limmin, limmax);
// グリッドの表示を戻す
if gridMode > 0 then
doc.SetVariable('GRIDMODE', gridMode);
// UCSアイコンの表示を戻す
if ucsIcon > 0 then
doc.SetVariable('UCSICON', ucsIcon);
end;
// 元の図面をアクティブに
docOrg.Activate;
// シート番号、ページ番号順にソート
SortDwgDocAry;
with ComboBox1 do begin
Items.Clear;
Sorted := False;
for i := 0 to Length(DwgDocAry) - 1 do begin
Items.AddObject(DwgDocAry[i].Comment +':'+ DwgDocAry[i].Name , TObject(i));
if DwgDocAry[i].Index = IdxOrg then
ItemIndex := i;
end;
end;
FormResize(self);
ComboBox1Change(self);
except
;
end;
// 自フォームを戻す
WindowState := wsNormal;
// 自フォームをアクティブに
SetForegroundWindow(Handle);
end;
procedure TForm2.SpeedButton2Click(Sender: TObject);
begin
// コマンド実行
N2Click(self);
end;
procedure TForm2.SpeedButton3Click(Sender: TObject);
begin
// 設定
N3Click(self);
end;
end.