月別アーカイブ: 2025年9月

マウスカーソルの形状も含めてデスクトップ画面をキャプチャしたくなりました!みたいな時は、もしかしたら『コレ』が使えるカモ?しれません・・・

ほとんど、自分専用のプログラムですが、夢見た通りのモノができました! *(^_^)*♪

マウスのカーソルを含めて画面をキャプチャできます!


起動時に出てくるのはこれだけです!

アプリ起動時に表示される案内です。


過去記事で、怖れ多くも『マウスカーソルの形状も含めて画面のハードコピーを取るプログラムを自分で書いてしまいました。後日、機会がありましたら、この Blog でご紹介したいと思います。』と、ご案内しましたアプリケーションもどきです。

私が試した限りですが、期待通りに動作している気がします・・・。

【推奨動作環境】

業務用PCの 1366 × 768 、拡大率 100 % のモニターで制作・動作確認を行っています。高 DPI 環境下で拡大率 150 %や 200 %の環境では意図した通りに画面をキャプチャできません(Windows がアプリに対してスケーリングされた論理座標を提供するため、キャプチャ結果がズレたり、キャプチャサイズが異なったりします)。ですので、このアプリについては、画面の拡大率 100 %での使用を強く推奨させていただきます。

【もくじ】

1.手作りの『それ』が必要になった理由
2.使い方
3.☆ここではまりました☆
4.ダウンロードはこちらから
5.お願いとお断り

1.手作りの『それ』が必要になった理由

前回、『解答欄(矩形)検出器を改良しました!』の記事を書いた際、どうしても必要になったのがマウスカーソルの形状を含めて画面をキャプチャできるプログラムです。

AI に「マウスカーソルの形状を含めて画面をキャプチャするいちばんかんたんな方法は?」と尋ねてみると Windows 標準搭載の「拡大鏡」を使えばいいよ ♪・・・とのご回答を頂戴したのですが、試して3秒後には、

( 思ったのと、ちがう )

そう感じて画面を閉じてしまいました。

他に、いつも愛用している「 Lightscreen 」という画面キャプチャユーティリティも AI から紹介されましたが、こちらはもう、ほんとうに素晴らしいソフトウェアで、この Blog に掲載した画像もほぼ全部、LightScreen でキャプチャしたものと言っていいくらいです。

ただ、残念ながら、今回の目的である『簡単に』マウスカーソルの形状を含めてキャプチャするという目的の実現に関しては、『タイマーの設定が必要』等の部分で、この目的の実現に関する部分に限っての話ですが、LightScreen は( ベスト・オブ・ベストの選択肢とは言えないかな・・・)って、思ってしまいました。

いつも、お世話になってるのに、こんなコメントしかできなくて、ほんとうにごめんなさい。

それからこれは、僕の PC で起きてしまったことなので、書かせていただきますが、僕のような素人には何が原因なのか・・・さっぱりわからないのですが、何らかの設定変更のあと?でしょうか・・・ タイトルバーが以前よりすごく大きく(逆に文字はほとんど読み取れないくらい小さく)表示されるようになることが(時として)あり、さらにこうなった時は、タイトルバー部分をクリックしてアクティブにして、画面上の位置を変えようとドラッグしても微動だにしないという不思議な現象に遭遇・・・ たしか、以前はそんなことは、なかった・・・ ような気がするのですが・・・

その際は、次のように操作してコトなきを得ましたが・・・。

( ただ、この方法でも「動かない」こともありました・・・ )

左上のアイコンを右クリックすると表示される
サブメニューの移動をクリックしてタイトルバー部分を
ドラッグすると移動できたり・できなかったり・・・

あと、表示されるタイトルバーも文字も、なぜかすごく大きい。
(逆にアプリの文字は、ものすごく小さい)

この状態で、マウスカーソルの形状を含めて画面キャプチャする機能を試そうと思ったのですが、今度は、設定?画面の文字が小さすぎて読めません・・・。

いったい何が原因でこうなったのか、それがわかりません。
私の使い方が間違っていると思うのですが、その間違いがわかりません。


exe を右クリックして、プロパティを表示し、「高 DPI 設定の変更」も試しましたが、効果がありません。これにはどう対応していいのか、まったく手も足も出ず、ほんとうに困ってしまいました。

【これは Windows 側の問題ではないかと?】

Lightscreen の名誉のために追記します。この Lightscreen の見た目の問題ですが OS を再起動したら元の姿に戻りました。再起動前に自分がナニをやったのか、よくよく考えてみると、解像度の変更を数回繰り返したように思います。もしかしたら、そのへんに何か、原因があったのかもしれません。

OS を再起動したら元の姿に戻ってくれました!

拝啓 Lightscreen 様

ご心配をおかけしましたこと、心より深くお詫び申し上げます。
どうか、これまで通り、仲よくしてください!!

いずれにしても、ここまで来てしまった以上、他人様に頼って問題を解決しようという、

甘え切った姿勢に
問題の真の原因がある

のは、火を見るよりも明らかです。それならば、取るべき道はただ一つ。

そう、自前で・・・
なんとかするしか、
ありません。

・・・

そうです。自前でなんとかするしか、ないのですが・・・

なんか、最近、そんなコトばっかり で・・・

それって、やっぱり・・・

前から、ちょっとは、思ってたケド。

僕は能力が低くて、適応力がなくて、ノロくて、グズだから、

もっと アリテー に言えば、ク〇ク〇パーだから

みんなが使ってる、一般的なアプリにすら馴染めないんだ。T_T

僕はやっぱりダメなんだ・・・。

ダメ人間なんだ!!

ひー(我が心の声)

でも、いいんだ。

僕には Delphi がいてくれる。

そう・・・ いつも Delphi がいてくれる。

Delphi があれば、なんにも心配なんかない。

汎用のアプリなんか使えなくても、自力で自分専用のを作るカラ☆

Delphi だけがトモダチさぁ♪

(この変わり身の早さだけが身上です)

こうして深い悲しみを、無上のよろこびに変えるべく、「その気になればマウスカーソルの形状も含めて画面キャプチャが可能なプログラム作り」がはじまりました。

あぁ アプリの名前、なんにしよー☆ みたいな・・・

みんなは、思ったように使えるアプリがないとき、いったいどーしてるのかなー? みたいな・・・

2.使い方

マウスのカーソルを含めてPCの画面をキャプチャする核心部分のコードは次の通りです。参考資料として、「ホットスポット」に対する考慮がないため、IDE のエディタ上などでカーソルが I ビームとなった状態でPC画面をキャプチャすると、マウスカーソルの位置がズレるコード( Version_01 )もコメント化した状態で載せています。試用される場合、コメント化してある下記 Version_01 のコードは、期待通りに動作しないコードであることに、どうかご注意ください。

また、キャプチャした画像のスクロールに関しても(画像関連のプログラムを書くときは、いつもこれが問題になるのですが)、なめらかにスクロールできるように処理を追加しています。Windows11の設定がデフォルト設定のままであれば、マウスのホイールを回転させれば上下方向にスクロール、Shift キーを押しながら、マウスのホイールを回転させれば、左右方向にスクロールします。

procedure TForm1.CaptureDesktop(ABitmap: TBitmap; IncludeCursor: Boolean);
var
  DC: HDC;
  R: TRect;
  CursorInfo: TCursorInfo;
  Pt: TPoint;
  //マウスのカーソル位置を正しくキャプチャするために追加
  IconInfo: TIconInfo;
begin

  //Version_01(マウスカーソルの位置がずれる)
  {
  if not Assigned(ABitmap) then Exit;
  R := Rect(0, 0,
    GetSystemMetrics(SM_CXSCREEN),
    GetSystemMetrics(SM_CYSCREEN));
  DC := GetDC(0);
  try
    ABitmap.PixelFormat := pf24bit;
    ABitmap.Width := R.Right;
    ABitmap.Height := R.Bottom;
    BitBlt(ABitmap.Canvas.Handle, 0, 0, R.Right, R.Bottom,
           DC, 0, 0, SRCCOPY);
    if IncludeCursor then
    begin
      CursorInfo.cbSize := SizeOf(CursorInfo);
      if GetCursorInfo(CursorInfo) and (CursorInfo.Flags = CURSOR_SHOWING) then
      begin
        GetCursorPos(Pt);
        DrawIcon(ABitmap.Canvas.Handle, Pt.X, Pt.Y, CursorInfo.hCursor);
      end;
    end;
  finally
    ReleaseDC(0, DC);
  end;
  }

  //上のコードを実行するとキャプチャした画像の「マウスカーソルの位置がずれる」
  //これは( Delphiの? )スクリーンキャプチャでよく起きる現象のようだ

  //【問題の原因】

  //GetCursorPos(Pt);
  //DrawIcon(ABitmap.Canvas.Handle, Pt.X, Pt.Y, CursorInfo.hCursor);

  //「カーソルのホットスポット(実際のクリック位置)」を考慮せずに
  //アイコンの左上を (Pt.X, Pt.Y) に描画している。

  //マウスカーソルは単なるアイコンではなく、
  //「ホットスポット」という基準点(通常は左上から数ピクセルずれた位置)が存在する。

  //Delphi のコードではその補正をしていないため、
  //キャプチャしたカーソルが右下に数ピクセルずれてしまう。

  //特に Delphi IDE のエディタ上では I ビームカーソルなど、
  //ホットスポットが左上から大きくずれているものを使うので、ズレが目立つ。

  //一方 GUI デザイン画面では標準の矢印カーソル(ホットスポットが左上 0,0 のもの)
  //が使われるのでズレが目立たない。

  //【修正方法】

  //GetIconInfo を使い、カーソルのホットスポットを考慮して描画位置を補正する。
  }

  //スクロールに関する問題の解決方法
  //1. AutoScroll := True (デフォルト)でスクロールバーは自動表示される
  //2. 手続き内で ScrollBox1.HorzScrollBar.Visible := False を設定
  //3. 以降、スクロールバーが表示されなくなる(領域を超えても)
  //いったん Visible を False にすると
  //Delphi が「このスクロールバーは使わない」と判断してしまい、
  //AutoScroll の制御対象から外れてしまう。

  ScrlPreview.AutoScroll:= True;
  ScrlPreview.HorzScrollBar.Visible := True;
  ScrlPreview.VertScrollBar.Visible := True;
  //ScrlPreview.Realign; // ← 状況によってはこれも必要?

  //Version_02(マウスカーソルの位置も正しく取得できる)
  if not Assigned(ABitmap) then Exit;

  R := Rect(0, 0,
    GetSystemMetrics(SM_CXSCREEN),
    GetSystemMetrics(SM_CYSCREEN));

  DC := GetDC(0);
  try
    ABitmap.PixelFormat := pf24bit;
    ABitmap.Width := R.Right;
    ABitmap.Height := R.Bottom;
    BitBlt(ABitmap.Canvas.Handle, 0, 0, R.Right, R.Bottom,
           DC, 0, 0, SRCCOPY);

    if IncludeCursor then
    begin
      CursorInfo.cbSize := SizeOf(CursorInfo);
      if GetCursorInfo(CursorInfo) and (CursorInfo.Flags = CURSOR_SHOWING) then
      begin
        GetCursorPos(Pt);
        if GetIconInfo(CursorInfo.hCursor, IconInfo) then
        try
          //ホットスポットを考慮してカーソルを描画
          DrawIcon(ABitmap.Canvas.Handle,
            Pt.X - Integer(IconInfo.xHotspot),
            Pt.Y - Integer(IconInfo.yHotspot),
            CursorInfo.hCursor);
        finally
          if IconInfo.hbmMask <> 0 then DeleteObject(IconInfo.hbmMask);
          if IconInfo.hbmColor <> 0 then DeleteObject(IconInfo.hbmColor);
        end;
      end;
    end;
  finally
    ReleaseDC(0, DC);
  end;
end;

プログラムの名称は、AI に相談したら即 ” Capity ” がいいよ☆との提案がありまして、それに決めました。なお、この ” Capity ” という名称は、特許情報プラットフォーム「 J-PlatPat 」のキーワード検索で「特許・実用新案、意匠、商標」の四法について過去の登録・申請の有無を調査し、2025年9月27日現在、この名称に該当する登録・申請が0件であることを確認済みです。

Capity – Lightweight Screen Capture Tool

【使い方】

上記コードを核心部分に据えて、(作者が)最低限必要と思われるアレやコレを GUI として付け足して、完成した気がする Capity.exe をダブルクリックして起動すると・・・


画面右下に操作方法の案内(トースト通知:Toast Notification?)だけを表示して、プログラム本体は非表示状態(タスクバーには表示されます)で起動します。

プログラム本体は「非表示」状態で起動します!


プログラム本体を表示するには、タスクバーの Capity (読めないかもしれません!)アイコンをクリックしてください。


タスクバーの Capity アイコンをクリックすると本体が表示されます。

プログラム本体を表示(起動時の画面をこのアプリでキャプチャしました)
なお、メイン画面の画像は、右下隅へスクロールした状態を取得(キャプチャ)しています。


マウスのカーソルの形状を含めて PC の画面をキャプチャする設定であった場合には、起動時に画面右下の通知領域に次の案内が表示されます。ただし、高DPI環境では、ヒントの位置がずれて表示されないことがあるようです。ところで、この表示の名称は「トースト通知」でいいのでしょうか?

起動時の表示は、ヒントの表示が無効化されている場合も、当然、出ません!


上記案内にある通り、Shift + Ctrl + C ( これは Shift キーと Ctrl キーと C キーを同時に押すことを意味します -> 実際の操作では、左手でキーボード左下にある Shift キーと Ctrl キーを同時に押しつつ、右手で C キーを押します)のキー操作で現在表示されている PC 画面が、マウスのカーソルの形状も含めてキャプチャされます。

マウスのカーソルの形状を含めずに PC の画面をキャプチャする設定であった場合には、起動時に次の確認画面が表示されます。


「はい」・「いいえ」どちらを選択しても、画面右下の通知領域に上記案内を出して、プログラム本体は非表示(タスクバーには表示)で起動します。

「はい」を選んだ場合は、IncludeCursor という名前のチェックボックスにチェックが入ります。このチェックボックスの状態(チェックの有無)やその他の VCL コントロールの選択(設定)状態は、プログラム終了時に自動的に保存され、次回はこの自動保存された設定に基づいて起動します。

・設定の保存先フォルダ:C:\Users\ユーザー名\AppData\Roaming\Capity
・設定の保存ファイル:settings.dat

「EN」のチェックを外すと各 VCL コントロールのキャプションは日本語表記になります。


日本語表記の状態です。

「EN」をチェックすれば英語表記に戻ります。


あとは、キャプチャしたい画面を最前面に表示して、Shift + Ctrl + C のショートカットキーで PC 画面をキャプチャしてください。上の画像にある「キャプチャ」ボタンをクリックした場合は、このアプリの作業画面がキャプチャされます。

「キャプチャ」ボタンをクリックするか、アプリを最小化して Shift + Ctrl + C する度に、新しいキャプチャデータが作られます。新しくつくられたキャプチャデータ(画像)は、アプリの右側にサムネイル表示されます。このサムネイル表示を左クリックすると、そのキャプチャデータがアクティブになり、メイン画面に表示されます。右クリックすると削除の可否を問うメッセージが表示されます。キャプチャしたデータを保存していない場合は、削除されたデータを復活させることはできません。

このアプリは本格的な画像編集に使用するための素材、もしくは、操作方法の解説を作成するために必要な情報画像(部分的な切り抜き画像)を簡単に作成したいという目的を実現するために開発しました。ですので「現在、表示されている画面の全部、もしくは一部を、必要であればマウスカーソルの形状を含めた画像データとして取得する」ことしかできません。保存した画像データを再度読み込んで表示したり、キャプチャした画像を加工する(例えば、ぼかす・モザイクをかけるといったような)機能はありません。ただし、画像の指定範囲を「ぼかす・モザイクをかける」機能は、後日、追加できたら、追加したいと考えています。

また、範囲を指定してキャプチャする機能はありませんが、アプリ側でキャプチャした画像上に矩形を描画し、この矩形で囲んだ範囲を任意の名称を付けて保存したり、クリップボードへ送信することができます(方法は後述)。※ このアプリで、本当に実現したかった機能は、この機能です!

キャプチャした画像上に描く矩形の枠線の太さと色は変更可能です。アプリは終了時の設定内容を自動的に記憶しますので、次回起動時は前回終了時の設定を復元して起動します。矩形で囲った範囲内部を右クリックすると表示されるサブメニューから、その範囲のみを「名前を付けて保存」したり、「クリップボードへ送信」したりすることができますが、その際、保存したり、送信されるのは、矩形下の指定した範囲のみです。矩形そのものは保存・送信されません。

範囲を指定する際に描かれる矩形の枠線の太さと色は変更可能です。


何らかの理由で矩形も含めて保存・送信したい場合は、「矩形が表示された状態そのものをキャプチャ」して、その矩形全体を囲むように範囲を指定(範囲選択後も、矩形の上下左右と四隅に表示されるグラブハンドルをドラッグして選択範囲の微調整が可能です)し、保存・送信を行ってください。

なお、アプリの仕様として、単に画面をキャプチャしただけでは画像データとして保存されません。画像データとして利用したい場合は、必ず保存の作業を行ってください。保存していないキャプチャデータはアプリ終了時に自動的に破棄されますので、この点には十分ご注意ください。

キャプチャした画面を画像データとして保存する方法は3つあります。

(1)ショートカットキー( Shift + Ctrl + S )で保存。
(2)アプリ本体の「Save」ボタンをクリックして保存。
(3)アプリ本体で範囲を指定して保存。

(1)ショートカットキー( Shift + Ctrl + S )で保存

まず、(1)のショートカットキーによる保存は、最後に Shift + Ctrl + C を行ったデータに対して有効です。画像データの保存先 Path は、デフォルト設定はデスクトップですが、アプリを起動後、ユーザーが保存先を任意の場所に変更した場合は、ユーザーが選んだ任意の場所となります(アプリは終了時にデータの保存先 Path を記録して終了、次回起動時はその Path の存在を確認し、Path が存在すればそこを、存在しなければユーザーが新しく指定した任意のフォルダ(もしくはデスクトップ)を画像データの保存先として自動選択します)。

ショートカットキー( Shift + Ctrl + S )で保存した場合は、SaveDialog は表示されません。ショートカットキー押し下げと同時に上記指定フォルダに保存後、次のメッセージが表示されます。

画像ファイルの名称は「Screenshot_西暦年月日_時分秒」+「.拡張子」となります。
(SaveDialog 使用時は、任意の名称に変更可能です)

画像データの保存形式は、デフォルト「PNG」形式です。アプリ本体側で 予め指定 すれば「BMP」や「JPEG」形式で保存することもできます。先ほどの Path と同様、アプリは終了時に指定されていた画像ファイルの保存形式を記憶しますので、次回は前回終了時の保存形式が自動的に選択された状態で起動します。

(2)アプリ本体の「Save」ボタンをクリックして保存

2つ目の保存方法が、アプリ本体の「Save」ボタンをクリックして保存する方法です。初めて起動した際には、保存形式はデフォルトで PNG 形式になっていると思いますが、PNG 形式の他に BMP や JPEG でも保存可能です。ですので、アプリの「Save」ボタンを利用する保存の流れとしては、タスクバーのアプリをクリック → 画像の保存形式を指定 → 画像の保存( Save ボタンをクリック)が基本です。

キャプチャした画像の保存形式を指定した後、「Save」ボタンをクリックしてください。

このアプリでキャプチャした画像です!


即時保存のショートカットキー( Shift + Ctrl + S )を使わず、タスクバーに待機していたアプリのアイコンをクリックしてプログラムの本体を表示し、画面右下の「Save」ボタンをクリックする(2)の場合は、(1)の場合とは異なり、「名前を付けて保存」のダイアログが表示されます。必要に応じて保存場所・ファイル名を変更し、「保存」ボタンをクリックすれば、キャプチャした画像をそのまま、任意に指定したディレクトリ(フォルダ)に保存できます。

キャプチャした画像ファイルの保存先とファイル名は Windows 側の機能を利用して変更が可能です。
必要に応じてダイアログを操作し、「任意の場所・任意の名称」に変更してください。

(3)アプリ本体で範囲を指定して保存

キャプチャした画像の一部を範囲指定して保存する方法です。例えば、操作方法の案内で「最小化ボタンをクリックしてください」という趣旨を解説する際に使用したい画像を作成するには、次のように操作します。

まず、マウスのカーソルを最小化ボタンに乗せて(最小化ボタンをポイントして)、画面全体をキャプチャ( Shift + Ctrl + C )して、必要な範囲を矩形で範囲指定します。範囲指定は、必ず、指定したい範囲の左上から右下へドラッグする形で行ってください(右下から左上へドラッグする操作は無効となります)。

解説に使用したい範囲を矩形で囲みます。


矩形で囲んだ範囲の内部へマウスのカーソルを移動させる(矩形内部をポイントする)と、マウスのカーソルの形状が上下・左右の矢印( SizeAll ・「全方向サイズ変更カーソル」or「移動カーソル」に変化します(この状態で範囲そのものを移動させることもできますが、移動はあまりスムースではありません)。この状態でマウスを右クリックするとサブメニューが表示されます。

実行したいコマンドをクリックしてください。


指定範囲をそのまま無加工で使用する場合は「名前を付けて保存」、画像編集ソフトでさらに加工して使いたい場合は「クリップボードへ送る」を選んでください。

この解説そのものも、このアプリで作成しましたが、キャプチャした画像をさらにキャプチャするので、なんだか、すごく混乱しました。解説の解説を作るって、難しいです・・・

【終了方法】

アプリを終了するには、操作画面右下隅にある「Close」or「終了」ボタンをクリックしてください。確認メッセージが表示されます。

「はい」をクリックすると終了します。

3.☆ここではまりました☆

「こんなのカンタンさぁ・すぐ出来るー」みたいな軽いノリで始めたこのアプリの制作でしたが、思わぬ落とし穴にはまり、3日間ほど停滞しました。それは何かというと、範囲を指定する矩形を描画した後の、矩形のリサイズ時の挙動の制御です。

矩形の新規描画の際には、キャプチャした画像上の任意の位置をドラッグするわけですが、この時、ドラッグした範囲が画像の右や下、または右下隅までくると、次の画像のようにドラッグそのものが自動的に停止します。

新規に矩形を描画する際は、画像の端までドラッグしたら、もうそれ以上ドラッグできません。


ところが、この範囲の選択後、矩形の上下左右と四隅に表示されるグラブハンドルをクリックして(掴んで)リサイズしようとすると、選択範囲(上の画像の赤い点線部分:業界用語では「ラバーバンド」と言うようです)が画像の幅・高さを超えて右へ・下へ、大きくずれて描画されてしまうのです。

範囲選択後、矩形をリサイズしようとするとキャプチャした画像の範囲をオーバーしてしまう・・・


上の例はわかりやすさのため、画面の右下隅で新規矩形描画時にカーソルが自動停止した後、さらに右下側へリサイズするという、現実にはあり得ない設定で説明しましたが、実際の場面では、キャプチャした画像の右下方向を範囲選択して切り抜きたいとき、この現象が発生するわけです。

この選択範囲が画像の端をはるかにオーバーした状態で「名前を付けて保存」・「クリップボードへ送信」しても、保存・送信されるのは余計な余白のない(取得したかった)画像データのみなので、『問題がない』と言えば『問題ない』のですが、気分がよくないです。

プログラム的には、キャプチャした画像は imgPreview という名前の TImage に表示し、さらにその上に plImage1という名前の TImage を乗せ、これをラバーバンドとして利用しています。ですので、手続きは、imgPreview の MouseDown 、MouseMove 、MouseUp と、plImage1 の MouseDown 、MouseMove 、MouseUp があるわけです。

plImage1 は、Mr.XRAY さんが公開していらっしゃる plResizeImage.pas を利用させていただき、作成したものです。改変可能とのことでしたので、元の plResizeImage.pas に必要な機能を追加して使わせていただきました。素晴らしいプログラムを公開してくださっている Mr.XRAY さんに心より厚く御礼申し上げます。ほんとうに、ありがとうございました。

157_移動リサイズ可能な TImage ラバーバンドとグラブハンドル

さて、どうやってこの問題を解決したか? ですが・・・

私は、当初、imgPreview 上での動作なので、imgPreview の MouseDown 、MouseMove 、MouseUp の各手続きに必要な制御を記述すればイイとハナから思い込み(しかも、その思い込みが原因で、これまでにもさんざん苦労して、痛い思いを味わい続けてきたことすら完全に忘れ)、手を変え、品を変え、コードを変えて、imgPreview の MouseDown 、MouseMove 、MouseUp の各手続きに、ドラッグ操作が imgPreview の右下隅で自動停止するコードを書き続けたわけですが、どんなにコードを尽くしても、上の画像で示した画像の境界を超えてラバーバンドが描画される現象を改善することが出来ず、つまり、ラバーバンドは画像の端の先々まで伸び続けるという、またまた、この「他に誰一人として悩まないこと」で、さんざんに悩み、まるまる2日間をこの問題の解決に費やしました。今思えば、見方によっては、それは途方もなく無駄で無意味な時間であったわけですが・・・。この悩んでいる状態を経験したくてプログラムを書いているように思えてならないフシもあり、そうなるともう、これは救いようがありません・・・

ともあれ、七転八倒し続けた挙句、(オレは根本的に間違えているのではなかろうか?)と、ようやくそこに思いが至りました。時にして遅すぎですが、これが悩み続けて3日目のことです。

で、気づいた根本的な間違いとはナニか? というと、確実に呼ばれていると思い込んでいた上記イベントは実は呼ばれていないんじゃないか? という至極(「非常に」・「とても」の上位語として、強調の意味を持ちます)当然のことなのですが、3日めにしてようやくというか、やっとそこに思いが至ったわけです。

一緒に暮らしているヒトに『悔い改めましたか?』とよく問われますが、どんなに悔い改めても同じような誤りを繰り返す私は、やっぱり、バカなんじゃないかと・・・、今に始まったことではありませんが、そう思えてなりません。

神さま
ボクには信じることと
思い込むことの違いが
よくわかりません。

信じるものは救われると
聞きましたが、
思い込むものは
救われないのでしょうか?

父からは、いつか・・・
『大丈夫。天国の黒板にはあなたの名前が書いてある。』と

ものすごいことを聞きましたが、
あっ。いえ、その・・・
決して「ついでに」という訳ではありませんが、
それも ほんとう でしょうか?

そのように悩みつつ、書いたコードがコレです。

  {$IFDEF DEBUG}
  OutputDebugString('imgPreviewMouseDown called');
  {$ENDIF}

実際の画面上では、こう見えます。


本来ならば、コレをいちばん最初に確認すべきだったのですが、後悔と反省の狭間で目を瞬きながら「いつ・どのイベントが呼ばれているのか」確かめて見ると・・・ 矩形のリサイズ時に呼ばれているのは、


当たり前ですが、(本人は、そのような手続きを書いたことすら忘れていた )plImageResized 手続きでありました!

しばし、唖然としましたが、わかってしまえばコトはカンタンです。

procedure TForm1.plImage1Resized(Sender: TObject; ARect: TRect; ALeft, ATop,
  AWidth, AHeight: Integer);
var
  ・・・ 省略 ・・・
  clipRect: TRect;
  topLeft, bottomRight: TPoint;
begin

  {$IFDEF DEBUG}
  OutputDebugString('plImageResized called');
  {$ENDIF}

  ・・・ 省略 ・・・

  //マウスのカーソルの移動範囲を制限

  //imgPreview のクライアント領域をスクリーン座標に変換してカーソルの移動を制限
  clipRect := imgPreview.ClientRect;
  topLeft := imgPreview.ClientToScreen(Point(clipRect.Left, clipRect.Top));
  bottomRight := imgPreview.ClientToScreen(Point(clipRect.Right, clipRect.Bottom));

  clipRect.Left := topLeft.X;
  clipRect.Top := topLeft.Y;
  clipRect.Right := bottomRight.X;
  clipRect.Bottom := bottomRight.Y;

  // カーソル移動範囲を制限
  ClipCursor(@clipRect);

end;

で、このままだと、マウスのカーソルは imgPreview の外へ出れなくなってしまうので、plImage1 の MouseUp 手続きで ClipCursor に nil を代入してカーソルの移動制限を解除します。

procedure TForm1.plImage1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  screenPt: TPoint;
  localPt: TPoint;
begin

  //フラグをリセット
  DragFlag := False;
  MoveFlag := False;

  //ドロップ後の plImage1 のスクリーン座標を取得
  screenPt := plImage1.ClientToScreen(Point(0, 0));

  //imgPreview のローカル座標に変換
  localPt := imgPreview.ScreenToClient(screenPt);

  //キャプチャ範囲を更新
  rbX := localPt.X;
  rbY := localPt.Y;
  rbW := plImage1.Width;
  rbH := plImage1.Height;

  //カーソルの移動制限を解除
  ClipCursor(nil);

end;

これでリサイズ時でも、キャプチャした画像の端でカーソルが停止するようになったはずです。そしてこれは思い込みではないはずです。

結果を信じながら、キャプチャした画像上を範囲選択します。

範囲選択後、いったん指をマウスから離し、さらにリサイズします。


神さまに祈りながら、グラブハンドルをクリックして(掴んで)右下隅の方へドラッグし(引っ張り)ます。はたして結果は如何に・・・

☆キャプチャ画像の右下隅でドラッグは自動停止しました☆

やった! やった!!

これでようやく
夢が全部叶いました!

4.ダウンロードはこちらから

今回の記事で紹介した PC の画面キャプチャを実行するプログラム一式を以下からダウンロードできます。なお、ダウンロードとご使用にあたっては、免責事項及び使用条件への同意が必要です。免責事項及び使用条件の詳細は付属の License.txt をご覧ください。

なお、プログラムの初回起動時には、Windows Defender SmartScreen による警告画面が表示されます。この警告画面に関する詳細は、当 Blog の次の過去記事をご参照ください。

5.お願いとお断り

このサイトの内容を利用される場合は、自己責任でお願いします。記載した内容(プログラムを含む)を利用した結果、利用者および第三者に損害が発生したとしても、このサイトの管理者は一切責任を負えません。予め、ご了承ください。