C++ Builder XE4, 10.2 Tokyo > TImage > AからBへ二倍にして描画内容を転送 > TCanvas.CopyRect | MouseDown処理 | 描画コピーのタイミング


動作環境
C++ Builder XE4
RAD Studio 10.2 Tokyo Update 2 (追記: 2018/01/05)

参考

TCanvas.CopyRect Method

やりたかったこと

  • フォームを拡大 (二倍)
    • TImageは拡大されない模様
  • TImageを拡大 (二倍)
    • FillRect(), FrameRect()などの描画を二倍にするにはどうすれば。。。

[Borg集合体からの悪魔のささやき]

TImageの描画を拡大コピーすれば楽だよね

code

Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::B_drawSomeClick(TObject *Sender)
{
    IMG_src->Canvas->Brush->Color = clRed;
    IMG_src->Canvas->FrameRect(Rect(0, 0, 50, 50));

    TRect srcRect = Rect(0, 0, 50, 50);
    TRect dstRect = Rect(0, 0, 100, 100);

    IMG_disp->Stretch = true;
    IMG_disp->Canvas->CopyRect(dstRect, IMG_src->Canvas, srcRect);
}
//---------------------------------------------------------------------------

実行結果

描画部分のラッパー関数

FrameRect(), FillRect()などのプリミティブな描画関数を使用している関数内で拡大描画する方法は思いついた。
実装したとすると、将来のソースリーディング時に苦労する気がしたので、上記方法を思いついた。

v0.2 MouseDown処理追加

拡大表示したIMG_dispでクリックした座標データを元画像のIMG_srcで使う。

こうすると、IMG_srcの実装はそのままに、拡大表示(とクリック)機能を後から追加できるだろう。

Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------

static const int kRatio_image = 2; // 拡大率
static const int kCenter_image = 25;
static const int kMargin_image = 25;

//---------------------------------------------------------------------------

void __fastcall TForm1::FormShow(TObject *Sender)
{
    IMG_src->Canvas->Brush->Color = clRed;
    IMG_src->Canvas->FrameRect(Rect(0, 0, 50, 50));

    TRect srcRect = Rect(0, 0, 50, 50);
    TRect dstRect = Rect(0, 0, 100, 100);

    //IMG_disp->Stretch = true;
    IMG_disp->Canvas->CopyRect(dstRect, IMG_src->Canvas, srcRect);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::IMG_dispMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
          int X, int Y)
{
    int ax = X / kRatio_image;
    int ay = Y / kRatio_image;
    IMG_srcMouseDown(Sender, Button, Shift, ax, ay);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::IMG_srcMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
          int X, int Y)
{
    bool bfhit = true;

    if (X < (kCenter_image - kMargin_image) ||
        X > (kCenter_image + kMargin_image)) {
        bfhit = false;
    }
    if (Y < (kCenter_image - kMargin_image) ||
        Y > (kCenter_image + kMargin_image)) {
        bfhit = false;
    }

    String msg;
    if (bfhit) {
        msg = L"You hit the nail on the head: " + IntToStr(X) + L"," + IntToStr(Y);
    } else {
        msg = L"You're closer than ever before.";
    }
    OutputDebugString(msg.c_str());
}
//---------------------------------------------------------------------------

描画コピーのタイミング

プリミティブな描画処理(ドットを打つ、線を引く、テキストを書く、色で塗りつぶす)のタイミングごとに表示を拡大コピーすると処理が多くなりすぎる。

タイマーを用意して、タイムアウトごとに拡大コピーをする、というのが一つの案。
LEDの点灯の経験から、だいたい300msec程度の更新であれば違和感が少ないかもしれない。元の更新タイミングが1秒程度であれば、タイマーは1秒でもいいかもしれない。
実際に試したところ、1秒の更新では「遅れ」が気になった。300msec程度が違和感が少ない。

組込みへの応用

今回はWindowsソフトでの実装であるが、将来、モニタサイズが異なる液晶を使っていきそうな組込みで、描画処理に関しても応用できるかもしれない。基本描画機能は読みやすいコードのままにしておいて、拡大機能をそれに追加する。