Delphi Programming / Object Pascal [掲載 2022年03月12日] [更新 2022年03月12日] |
コンソール画面に画像を表示 | |
動作確認等 | Windows 10 ビルド 19042 + Delphi XE5(UP2) Pro VCL-32 |
コンソールアプリの画面に画像を表示する例です.TCanvas を生成して使用します.画像を TBitmap に読み込む際,多少のタイムラグが必要です. |
このサンプルは,コンソールウィンドウをリサイズすると画像を描画しません.また,画像をクリックすると,下図のようにクリックした部分を含む領域が欠落します. |
program Project1; {$APPTYPE CONSOLE} uses Winapi.Windows, System.SysUtils, Vcl.Graphics, Vcl.Forms; var FhConsole : HWND; FhHDC : HDC; FCanvas : TCanvas; FBitmap : TBitmap; FFilePath : string; begin Writeln('コンソール画面に画像を表示 '); FhConsole := FindWindow(nil, PChar(Application.ExeName)); FhHDC := GetDC(FhConsole); FCanvas := TCanvas.Create; FBitmap := TBitmap.Create; try FCanvas.Handle := FhHDC; FFilePath := ExtractFilePath(Application.ExeName) + 'smail_27.bmp'; FBitmap.LoadFromFile(FFilePath); // タイムラグが必要 Sleep(30); FCanvas.Draw(50, 50, FBitmap); finally ReleaseDC(0, FhHDC); FreeAndNil(FCanvas); FreeAndNil(FBitmap); end; Readln; end.
どうしても再描画したい場合,TTimer コンポーネントを使用して定期的に再描画する方法が考えられます. 下図は EXE を実行した直後の画像です,その次の画像は,マウスでコンソール画面をスクロールした結果です.コンソールアプリは,スクロール等のメッセージを捕捉できません.この現象の対処方法は不明です. |
テストに使用したプロジェクトのソースコードです.コンソールアプリとするために {$APPTYPE CONSOLE} を追加して,フォームを非表示で実行するためのコードを追加しています. |
program Project1; uses Vcl.Forms, Unit1 in 'Unit1.pas' {Form1}; {$R *.RES} {$APPTYPE CONSOLE} // 追加 begin Application.Initialize; Application.MainFormOnTaskbar := True; Application.ShowMainForm := False; //追加 Application.CreateForm(TForm1, Form1); Application.Run; end.
フォームのユニットのコードです.コンソールアプリを操作するということ以外,通常のフォームのコードとの違いはありません. |
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls; type TForm1 = class(TForm) Timer1: TTimer; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private 宣言 } FConsoleWnd : HWND; FCanvas : TCanvas; FhHDC : HDC; FBitmap : TBitmap; public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.DFM} //============================================================================= // フォーム生成時の処理 //============================================================================= procedure TForm1.FormCreate(Sender: TObject); begin FConsoleWnd := FindWindow(nil, PChar(Application.ExeName)); SetConsoleTitle('コンソールアプリの画面に画像を描画'); Writeln('コンソール画面に画像を表示 '); FhHDC := GetDC(FConsoleWnd); FCanvas := TCanvas.Create; FCanvas.Handle := FhHDC; FBitmap := TBitmap.Create; FBitmap.LoadFromFile('smail_27.bmp'); Timer1.Interval := 30; Timer1.Enabled := True; end; //============================================================================= // フォーム破棄時の処理 //============================================================================= procedure TForm1.FormDestroy(Sender: TObject); begin FreeAndNil(FBitmap); FreeAndNil(FCanvas); ReleaseDC(0, FhHDC); end; //============================================================================= // Timer1 の OnTimer イベント処理 //============================================================================= procedure TForm1.Timer1Timer(Sender: TObject); begin if FBitmap <> nil then begin FCanvas.Draw(50, 50, FBitmap); end; end; end.
この記事の元になった質問は,コマンドプロンプトに画像を表示することでした,コマンドプロンプトの画面に画像を表示するという状態は,個人的にはちょっと考えられません.そこでコンソール画面としています. |
|
試しに,コマンドプロンプトに画像を描画した結果です.フォームを非表示にして実行しています. |
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls; type TForm1 = class(TForm) Timer1: TTimer; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private 宣言 } FConsoleWnd : HWND; FCanvas : TCanvas; FhHDC : HDC; FBitmap : TBitmap; procedure DrawImage; public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.DFM} //----------------------------------------------------------------------------- // CreateProcess関数を使用して指定したプロセスを起動 // 起動したプロセスが終了するまで待つ //----------------------------------------------------------------------------- function WinExecAndWait32V2(FileName: String; Visibility: Integer): DWORD; var LStartupInfo : TStartupInfo; LProcessInfo : TProcessInformation; LiRet : DWORD; begin Result := 0; FillChar(LStartupInfo, SizeOf(LStartupInfo), #0); LStartupInfo.cb := SizeOf(TStartupInfo); //以下の4行とdwFlagsにSTARTF_USERPOSITION,STARTF_USESIZEを追加 //位置とサイズを指定する必要がなければこれらの設定は不要 LStartupInfo.dwX := 300; LStartupInfo.dwY := 300; LStartupInfo.lpTitle := PChar('コマンドプロンプト'); LStartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USEPOSITION or STARTF_USESIZE; LStartupInfo.wShowWindow := Visibility; SetLength(FileName, Length(FileName)); //参照カウンタ対策 UniqueString(FileName); if not CreateProcess(nil, PChar(FileName), nil, nil, False, NORMAL_PRIORITY_CLASS, nil, nil, LStartupInfo, LProcessInfo) then begin Result := WAIT_FAILED; end else begin //プロセスが起動するまで待つ repeat LiRet := WaitForInputIdle(LProcessInfo.hProcess, 50); Application.ProcessMessages; until LiRet <> WAIT_TIMEOUT; // 起動後の処理 // 本サンプルでは画像を表示 Form1.DrawImage; //起動したプロセスが終了するまで待つ while WaitForSingleObject(LProcessInfo.hProcess, 100) = WAIT_TIMEOUT do Application.ProcessMessages; GetExitCodeProcess(LProcessInfo.hProcess, Result); CloseHandle(LProcessInfo.hProcess); CloseHandle(LProcessInfo.hThread); end; end; //============================================================================= // フォーム生成時の処理 //============================================================================= procedure TForm1.FormCreate(Sender: TObject); begin WinExecAndWait32V2('Cmd.exe /k cd /d c:\&dir', SW_SHOWNORMAL); PostMessage(Handle, WM_CLOSE, 0, 0); end; //============================================================================= // フォーム破棄時の処理 //============================================================================= procedure TForm1.FormDestroy(Sender: TObject); begin FreeAndNil(FBitmap); FreeAndNil(FCanvas); ReleaseDC(0, FhHDC); end; //============================================================================= // Timer1 の OnTimer イベント処理 //============================================================================= procedure TForm1.Timer1Timer(Sender: TObject); begin if FBitmap <> nil then begin FCanvas.Draw(100, 50, FBitmap); end; end; //----------------------------------------------------------------------------- // コマンドプロンプトが起動したら行う処理 //----------------------------------------------------------------------------- procedure TForm1.DrawImage; begin Sleep(100); FConsoleWnd := FindWindow('ConsoleWindowClass', nil); FhHDC := GetDC(FConsoleWnd); FCanvas := TCanvas.Create; FCanvas.Handle := FhHDC; FBitmap := TBitmap.Create; FBitmap.LoadFromFile('smail_27.bmp'); Timer1.Interval := 30; Timer1.Enabled := True; end; end.
下図は,コマンドプロンプトで,本ページのサンプルで使用した画像ファイル名 smail_27.bmp をタイプして (実際にはコピペして) [Enter] キーを押下した結果です.Windows フォトビューアで画像を表示しています. コマンドプロンプトは,このようにコマンドを実行する用途に使用されています.コマンドプロンプトのウィンドウに表示できるのは文字列,つまりテキストだけです.コマンドプロンプトには,画像等,グラフィック関係の描画機能はありません. コマンドプロンプトのウィンドウとコンソールアプリのウィンドウは似ていますが,その機能と用途は全く違います. |
[備考] |