動作環境
C++ Builder XE4
関連
- C++ Builder XE4 > FastReport VCL 5 > PDF Export > TEdit付きのChart1をFastReportへ送る (クリップボード経由) > 解像度は72dpi
- C++ Builder XE4 > 画像処理 > 4つのファイル画像をN個合成して、表示枠を超える画像を作成する + クリップボードへ送る > ペイントブラシで画像を端から端まで貼付けできるか?
- C++ Builder XE4 > 画像処理 > 4つのファイル画像を合成してTImageとして表示
- C++ Builder XE4 > 実装例: (a)TPanel上の表示をStretchBlt()使用で拡大 + (b)クリップボードへ送る + (c)ペイントブラシ起動
- C++ Builder XE4 > Clipboard > クリップボードへ画像を送り、クリップボードから画像ファイルへ保存
目的
- TChartを高解像度でFastReportへ送る
障害
- FastReport上のTfrxChartViewに対してCloneChart()処理がまともに動かない
- グラフタイトル、軸タイトルしかクローンできない
- 内部の系列データは自前実装?でコピーする
- その実装もまともに動かない?
検討した方法
- 画像を部分ごとにキャプチャする
- 個々の画像を連結して一つのTImageとする
- TImageからクリップボードで送る
フォームデザイン
- 左上は連結用TImge
- 右下はキャプチャ対象画像
- TChart上に3つのTShapeを配置
- 実行時に拡大をして、画面に収まりきらない状態にする
- その状態でキャプチャできることを確認するため
実装
Unit1.h
//---------------------------------------------------------------------------
# ifndef Unit1H
# define Unit1H
//---------------------------------------------------------------------------
# include <System.Classes.hpp>
# include <Vcl.Controls.hpp>
# include <Vcl.StdCtrls.hpp>
# include <Vcl.Forms.hpp>
# include <Vcl.ExtCtrls.hpp>
# include <VCLTee.Chart.hpp>
# include <VCLTee.TeEngine.hpp>
# include <VCLTee.TeeProcs.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE で管理されるコンポーネント
TImage *Image1;
TButton *Button1;
TPanel *Panel1;
TChart *Chart1;
TShape *Shape1;
TShape *Shape2;
TShape *Shape3;
void __fastcall Button1Click(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
private: // ユーザー宣言
public: // ユーザー宣言
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
# endif
Unit1.cpp
//---------------------------------------------------------------------------
# include <vcl.h>
# pragma hdrstop
# include <pngimage.hpp>
# include <ClipBrd.hpp>
# include "Unit1.h"
//---------------------------------------------------------------------------
# pragma package(smart_init)
# pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
static const int kNum_div = 6; // 画像分割数 (水平と垂直で同じ分割). 3:任意
void __fastcall TForm1::Button1Click(TObject *Sender)
{
// 0. オリジナルの位置を保持
int preTop = Chart1->Top;
int preLeft = Chart1->Left;
// 1. 部分ごとにキャプチャして連結する
int clipWidth = Panel1->Width / kNum_div; // 切取り高さ
int clipHeight = Panel1->Height / kNum_div; // 切取り幅
TBitmap *bmp_whole = new TBitmap(); // A. 全画像を載せる
TBitmap *bmp_frac = new TBitmap(); // B. 部分ごとにキャプチャし、逐次Aに載せる
bmp_frac->SetSize(clipWidth, clipHeight);
bmp_whole->SetSize( Panel1->Width, Panel1->Height );
HDC dc_frac = GetDC(Panel1->Handle); // BitBlt()用
for(int ri = 0; ri < kNum_div; ri++) { // ri: row index
for(int ci = 0; ci < kNum_div; ci++) { // ci: column index
// Panel上でキャプチャ対象部分をキャプチャ位置に移動 (左上でキャプチャする)
Chart1->Top = -(ri * clipHeight);
Chart1->Left = -(ci * clipWidth);
// 下記のwaitがないと画像取得に失敗し、[左上の画像 * N個]になる
Sleep(10); // msec
Application->ProcessMessages();
// 常に左上の位置(0,0)でキャプチャする
::BitBlt(bmp_frac->Canvas->Handle, 0, 0, clipWidth, clipHeight, dc_frac, 0, 0, SRCCOPY);
// キャプチャしたものを逐次、全画像用BMPに描く
bmp_whole->Canvas->Draw(clipWidth * ci, clipHeight * ri, bmp_frac);
}
}
Image1->Picture->Assign(bmp_whole);
// 2. Chart1を元の位置に戻す
Chart1->Top = preTop;
Chart1->Left = preLeft;
// 3. クリップボードへ
Clipboard()->Assign(bmp_whole);
// 4, 手仕舞い
delete bmp_whole;
delete bmp_frac;
// 5. ペイントブラシ起動 (ctrl + vでの動作確認用)
ShellExecute(NULL, NULL, L"pbrush.exe", L"", NULL, SW_SHOWNORMAL);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
// Chart1はPanel1上に配置されている
// 上下左右をPanel1に合わせて伸縮するようにする
Chart1->Anchors = TAnchors() << akLeft << akTop << akRight << akBottom;
// デザイン画面で重なりを明白にするため、サイズを変えていたが、
// 本来はChart1とPanel1は同じサイズとする
Chart1->Top = 0;
Chart1->Left = 0;
Chart1->Height = Panel1->Height;
Chart1->Width = Panel1->Width;
// Panelのサイズを拡大 (画面に入りきらないサイズの例として)
Panel1->Height *= 2;
}
//---------------------------------------------------------------------------
動作例
画面には表示しきれない画像をキャプチャし、クリップボードで送ることができた。
失敗
上記実装時にriとciを使い間違える失敗をした。
loop-index cross-talk
Sleep()
Sleep(10); // msec
Application->ProcessMessages();
上記はSleep(1); //msec
でも成功する場合もある。
実環境で実行して、値を調整すること。
Image1不要
動作確認用に使用しているが、処理において重要ではないため削除して問題ない。