0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

C++ Builder XE4 > 画像処理 > 画面に入りきらないTChartを部分ごとにキャプチャし、合成した上でクリップボードに送る

Last updated at Posted at 2018-12-26
動作環境
C++ Builder XE4

関連

目的

  • TChartを高解像度でFastReportへ送る

障害

  • FastReport上のTfrxChartViewに対してCloneChart()処理がまともに動かない
    • グラフタイトル、軸タイトルしかクローンできない
    • 内部の系列データは自前実装?でコピーする
      • その実装もまともに動かない?

検討した方法

  • 画像を部分ごとにキャプチャする
  • 個々の画像を連結して一つのTImageとする
  • TImageからクリップボードで送る

フォームデザイン

2018-12-26_09h57_39.png

  • 左上は連結用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;
}
//---------------------------------------------------------------------------

動作例

ソフト起動時
2018-12-26_09h59_34.png

Button1押下後
2018-12-26_09h59_50(1).png

起動したペイントブラシにてctrl+vした後
2018-12-26_10h01_58.png

画面には表示しきれない画像をキャプチャし、クリップボードで送ることができた。

失敗

上記実装時にriとciを使い間違える失敗をした。
loop-index cross-talk

Sleep()

			Sleep(10);  // msec
			Application->ProcessMessages();

上記はSleep(1); //msecでも成功する場合もある。

実環境で実行して、値を調整すること。

Image1不要

動作確認用に使用しているが、処理において重要ではないため削除して問題ない。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?