質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

2865閲覧

BitBltによる画像表示について

mentos109

総合スコア28

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2018/04/27 16:27

現在C++でGUIアプリケーションを作成しているのですが、ウィンドウに画像を表示させたいです。
調べると、画像を表示するにはメッセージループのWM_PAINTの箇所に該当する記述を追加する必要があるということでしたが、
これらの記述を外部の自作関数内などに移し、関数を呼び出してみたところ、うまく行きませんでした。
なぜWM_PAINT内でないとうまく動かないのでしょうか?また、WM_PAINT内の記述がかなり多くなり煩雑になりそうなのですが、回避する方法はありますか?

記述は以下のとおりです。

C++

1 PAINTSTRUCT ps; 2 HDC hdc = BeginPaint(hWnd, &ps); 3 HDC hMdc = CreateCompatibleDC(hdc); 4 5 SelectObject(hMdc, LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1))); 6 7 BitBlt(hdc, 0, 0, 100, 100, hMdc, 0, 0, SRCCOPY);

よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

なぜWM_PAINT内でないとうまく動かないのでしょうか?

そういう仕様だからとしか言いようがないのですが。
BeginPaint関数はWM_PAINTメッセージハンドラーから呼び出すことを前提としています。そのことは公式のリファレンスにも明記されています。APIを利用する際は、ちゃんとリファレンスを読んで使い方を理解しましょう。

そもそも、WM_PAINTメッセージは、ウィンドウを描画する必要があるとシステムが判断したときに当該のウィンドウに送られるものなので、きちんと書かないとウィンドウの表示が乱れます。例えば、あるウィンドウの上に別のウィンドウを重ねて一部あるいは全部を覆い隠したとします。手前のウィンドウを動かして奥のウィンドウが現れたときに、隠されていた部分を描画し直さないといけないわけですが、それを知らせるのがWM_PAINTメッセージです。WM_PAINTメッセージをきちんと処理しないと、表示が欠けたり、ゴミデータが表示されたりします。

WM_PAINT内の記述がかなり多くなり煩雑になりそうなのですが、回避する方法はありますか?

複雑な描画を行う場合は、バックバッファー(オフスクリーンバッファーとも言う。裏画面などと言うことも)というテクニックを使うのが一般的です。これにより、表示と描画が切り離せます。また、WM_PAINTで複雑な描画を行うと表示がちらつくことがあるので、それの抑制にもなります。

まず、ウィンドウの描画領域と同じサイズのビットマップを作成します。これをバックバッファーとします。ビットマップの作成にはCImageクラスの利用がお手軽で簡単です。Windows SDKに含まれているので、別途何かを用意する必要はありません。
WM_PAINTメッセージでは、バックバッファーを丸ごとウィンドウにコピー(BitBlt)する処理を書きます。ビットマップに描画した内容が表示に反映されるようになります。

これで、描画処理とWM_PAINTを切り離すことができました。あとは、アプリの都合が良いタイミングでビットマップに描画を行い、InvalidateRect関数でウィンドウに表示の変更を伝えるだけです。

投稿2018/04/28 01:09

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mentos109

2018/04/28 03:31

よくわかりました。仕様だったのですね。 また、対処方法も非常に参考になりました。ありがとうございました。
guest

0

ベストアンサー

cpp

1// image.h 2#pragma once 3 4#include <Windows.h> 5 6typedef struct tagImage { 7 int nWidth; // 横幅 8 int nHeight; // 縦幅 9 HDC hdc; // デバイスコンテキスト 10 HBITMAP hbmp; // ビットマップハンドル 11}IMAGE, *LPIMAGE; 12 13int CreateImage(IMAGE* image, HWND hWnd, int width, int height); 14int CreateImageFromFileA(IMAGE* image, HWND hWnd, const char* filename); 15int CreateImageFromFileW(IMAGE* image, HWND hWnd, const wchar_t* filename); 16#ifdef UNICODE 17#define CreateImageFromFile CreateImageFromFileW 18#else 19#define CreateImageFromFile CreateImageFromFileA 20#endif 21 22int BltImage(IMAGE* dst, int x, int y, IMAGE* scr, RECT scr_r, DWORD flag); 23int DeleteImage(IMAGE* image);

cpp

1#include "Image.h" 2#include <cassert> 3 4int CreateImage( 5 IMAGE * image, // 画像を作成するためのポインタ 6 HWND hWnd, // ウィンドウハンドル 7 int width, int height) // 作成する横幅と縦幅 8{ 9 HDC hdc; 10 hdc = GetDC(hWnd); 11 12 // 仮想画面とDCの作成 13 image->hbmp = CreateCompatibleBitmap(hdc, width, height); 14 image->hdc = CreateCompatibleDC(hdc); 15 ReleaseDC(hWnd, hdc); 16 17 if (image->hbmp == NULL && image->hbmp == nullptr || 18 image->hdc == NULL && image->hdc == nullptr) 19 { 20 return -1; 21 } 22 23 // 関連付け 24 SelectObject(image->hdc, image->hbmp); 25 26 image->nWidth = width; 27 image->nHeight = height; 28 29 // 画面クリア(白) 30 BitBlt(image->hdc, 0, 0, width, height, nullptr, 0, 0, WHITENESS); 31 return 1; 32} 33 34int CreateImageFromFileA( 35 IMAGE* image, // 画像格納用変数ポインタ 36 HWND hWnd, // ウィンドウハンドル 37 const char* filename) // 読み込むファイル名 38{ 39 HDC hdc; 40 HINSTANCE hInst; 41 BITMAP bmp; 42 43 // ファイルから読み込む 44 hInst = (HINSTANCE)GetWindowLongA(hWnd, GWL_HINSTANCE); 45 image->hbmp = (HBITMAP)LoadImageA(hInst, filename, IMAGE_BITMAP, 0, 0, 46 LR_LOADFROMFILE | LR_CREATEDIBSECTION); 47 48 // DCの作成 49 hdc = GetDC(hWnd); 50 image->hdc = CreateCompatibleDC(hdc); 51 ReleaseDC(hWnd, hdc); 52 53 if (image->hbmp == NULL && image->hbmp == nullptr || 54 image->hdc == NULL && image->hdc == nullptr) 55 { 56 return -1; 57 } 58 59 // 関連付け 60 SelectObject(image->hdc, image->hbmp); 61 62 // ビットマップ情報の取得 63 GetObjectA(image->hbmp, sizeof(BITMAP), (void*)&bmp); 64 image->nWidth = bmp.bmWidth; 65 image->nHeight = bmp.bmHeight; 66 return 1; 67} 68 69int CreateImageFromFileW( 70 IMAGE* image, // 画像格納用変数ポインタ 71 HWND hWnd, // ウィンドウハンドル 72 const wchar_t* filename) // 読み込むファイル名 73{ 74 HDC hdc; 75 HINSTANCE hInst; 76 BITMAP bmp; 77 78 // ファイルから読み込む 79 hInst = (HINSTANCE)GetWindowLongW(hWnd, GWL_HINSTANCE); 80 image->hbmp = (HBITMAP)LoadImageW(hInst, filename, IMAGE_BITMAP, 0, 0, 81 LR_LOADFROMFILE | LR_CREATEDIBSECTION); 82 83 // DCの作成 84 hdc = GetDC(hWnd); 85 image->hdc = CreateCompatibleDC(hdc); 86 ReleaseDC(hWnd, hdc); 87 88 if (image->hbmp == NULL && image->hbmp == nullptr || 89 image->hdc == NULL && image->hdc == nullptr) 90 { 91 return -1; 92 } 93 94 // 関連付け 95 SelectObject(image->hdc, image->hbmp); 96 97 // ビットマップ情報の取得 98 GetObjectW(image->hbmp, sizeof(BITMAP), (void*)&bmp); 99 image->nWidth = bmp.bmWidth; 100 image->nHeight = bmp.bmHeight; 101 return 1; 102} 103 104int BltImage( 105 IMAGE* dst, // 転送先イメージ 106 int x, // 表示先X座標 107 int y, // 表示先Y座標 108 IMAGE* scr, // 表示元イメージ 109 RECT scr_r, // 表示元領域 110 DWORD flag) // 転送フラグ 111 112{ 113 int w = scr_r.right - scr_r.left; 114 int h = scr_r.bottom - scr_r.top; 115 116 BitBlt(dst->hdc, x, y, w, h, scr->hdc, scr_r.left, scr_r.top, flag); 117 return 0; 118} 119 120int DeleteImage(IMAGE* image) 121{ 122 DeleteDC(image->hdc); 123 DeleteObject(image->hbmp); 124 125 image->hdc = nullptr; 126 image->hbmp = nullptr; 127 return 1; 128}

こちらにある CreateImage関数、CreateImageFromFile関数、BltImage関数、DeleteImage関数の4つを使えば簡単に画像の表示ができます。
CreateImage関数でメモリDCを作成し、そのメモリDCに対して BltImage関数で描画、BltBltでウィンドウのデバイスコンテキストに描画、WM_DESTROYメッセージでそのメモリDCを削除します。

投稿2018/04/29 03:01

naohiro19_

総合スコア178

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mentos109

2018/04/29 07:38

コードを用いた、詳しいご説明ありがとうございます。 今後はこのように記述しようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問