あきらめました・・・12/27 金
昨日も書いた、PDF ファイルの読み込みですが、フリーのライブラリがありません。正確にいうと、C++ で使えるライブラリがありません。
強いてやろうとすると、poppler という GNU ライブラリを C++ のために再構築することになります。そのためには、たぶん、CMAKE などが必要になります。これが、けっこう大変で、おそらく「いつまで経っても必要なものが得られない」ということになりそうです。
そこで、まず開発言語を C++ から C# に変更しようと考えています。その理由は、ただ一つで「PDFium が、おそらく使えるから」です。
PDFium は、Google が Chrome のために開発した PDF 関連のエンジンで、商用も含めて自由に使えます。
これが使えるのであれば、わざわざ C++ で苦労する必要はないだろうと思います。
というわけで、明日からは C# と PDFium を使おうと思います。
ここまでできました。 12/26 木
Windows10, Visual Studio 2019, C++ という開発環境で、アプリケーションの開発をしていますが、現時点で「ここまでできた」というものを Youtube に投稿しました。
以下を御覧ください。
画像の表示と拡大・縮小、ワクの設定と移動・拡大・縮小・削除、スクロール機能を実装しました。
でも、まだまだ、これからです。当面の最大の難関は、PDF ファィルの読み込み です。これが、非常に難しい。
がんばります。
リソースの開放に成功しました 12/25 水
昨日の記事で、リソースをどんどん浪費する様子をみていただきました。
Visual Studio 2019 で C++ でアプリを作成しています。
プログラムで使用したリソースは、プログラムの中で開放します。実際にリソースを開放するようにプログラムできたので、画面上の上から6番目の数字は、ほとんど変化しなくなりました。
具体的には、プログラム中の VM_PAINT のなかで、リソースの開放を実施しています。以下、ソースプログラムを示します(自分用メモ)。
case WM_PAINT: { // ここから実際の描写 PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); // ⇒ ReleaseDC(hWnd, hdc);で開放する HDC mem = CreateCompatibleDC(hdc); // ⇒ DeleteDC(mem);で開放する HBITMAP bmp = CreateCompatibleBitmap(hdc, width, height); HGDIOBJ obmp = SelectObject(mem, bmp); img.Draw(mem, 0, 0, width, height, 0, 0, width, height); for (int i = 0; i < maxWaku; i++) { DrawWaku(mem, i); } DrawCursor(mem); nowWaku = CheckMouse(); StretchBlt(hdc, 0, 0, cx, cy, mem, 0, myTop, width, tate, SRCCOPY); wstring wmouseMode; switch (mouseMode) { case MODE_NONE: wmouseMode = L"MODE_NONE"; break; case MODE_WAKU: wmouseMode = L"MODE_WAKU"; break; case MODE_END: wmouseMode = L"MODE_END"; break; default: wmouseMode = L"default"; break; } TextOut(hdc, 200, 50, wmouseMode.c_str(), (int)wmouseMode.length()); if (flmouse) { wstring ww = L"■"; TextOut(hdc, 180, 50, ww.c_str(), (int)ww.length()); } si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; si.nMin = 0; si.nMax = height - tate; si.nPos = myTop; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); EndPaint(hWnd, &ps); SelectObject(mem, obmp); DeleteObject(bmp); DeleteDC(mem); ReleaseDC(hWnd, hdc); } break;
GDIビューアって、すごく便利・・・12/24 火
プログラムを作っていると、作ったプログラムでコンピュータのメモリとかディスクとか、いろいろなものを消費します。あまりたくさん消費しすぎると、コンピュータ全体がモタモタしたり、ひどい場合には、コンピュータ全体が止まってしまったりします。
特に、多くの領域を使うのは、画像や動画関係の「部品」で、それを「GDI」と呼びます(厳密には違うと思うけど、まあ、そういうことで)。
なにしろ、プログラムの初心者なので、いままで「自分の作ったプログラムが、そういうコンピュータの資源をどのように消費しているのか」を自分で確認する方法を知りませんでした。
このたび、次のようなソフトウエアがあることを知りました。
このソフトは、「インストールする必要なし。解凍したらそのまま実行するだけ」という単純(?)な作りです。
で、先日、「とまっちゃうよー」と質問した欠陥プログラムについて調べてみると、ものの見事に資源を消費していました。個数がどんどん増えていって、合計 10000個を超えたところで、ピタッと止まりました(他のソフトに悪影響がないように、10000個で止まるように、あらかじめ設定してあったらしい)。
以下、Youtube の動画を御覧ください。
というわけで、がんばって、改良します。
フィットネス・・・12/23 月
#フィットネス 2019/12/22
現在の走行距離の合計、約553km
今年も残りあと1回、または2回になりました。3月中旬にトラブルもありましたが、1年間継続できたことが何よりだと思います。来年は、「基本的に現状維持」、「無理せず、すこし減らしてもよい」という考えで臨みます。
キャット&ドッグ 3回x3セット
ラット・プル (25kg+27kg+29kg)x10回
ベンチ・プレス 20kgx10+25kgx7+30kgx3+45kgx30回
トレッドミル(25分間) 2,740m ⇒2019年の累計 144,640m
ハムストリングス 23kgx10回x3セット
レッグ・エクステンション 39kgx10回x3セット
アダクション 52kgx10回x3セット
アブダクション 43kgx10回x3セット
プレス・ダウン 34kgx10回x4セット
アーム・カール 29kgx10回x4セット
レッグ・プレス 57kgx10回x3セット
腹筋 1秒x20回x3セット
ダンベル(内側) 10kgx23+12kgx7
ダンベル(外側) 4kgx20回x3セット
ライイング・トライセップス・エクステンション 10kgx40回+12.5kgx5回
フロント・プル 39kgx10回x3セット
バイク(25分間) 9,900m ⇒2019年の累計 408,810m
また、助けていただきました・・・12/22 日
「たぶん、リソースの開放がうまくいっていないんだろうなあ」と思っていたのですが、自分では場所が特定できなかったので、いつも頼りにしている teratail で質問してみました。
その結果、実際に不具合のある場所をおしえていただくことができ、アプリの動作は明らかに改善されました。具体的なプログラムを以下に、メモしておきます。
case WM_PAINT: { // ここから実際の描写 PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); // ⇒ ReleaseDC(hWnd, hdc);で開放する HDC mem = CreateCompatibleDC(hdc); // ⇒ DeleteDC(mem);で開放する HBITMAP bmp = CreateCompatibleBitmap(hdc, width, height); HGDIOBJ obmp = SelectObject(mem, bmp); img.Draw(mem, 0, 0, width, height, 0, 0, width, height); for (int i = 0; i < maxWaku; i++) { DrawWaku(mem, i); } DrawCursor(mem); nowWaku = CheckMouse(); wstring wmouseMode; switch (mouseMode) { case MODE_DONE: wmouseMode = L"MODE_DONE"; break; case MODE_CLICK: wmouseMode = L"MODE_CLICK"; break; case MODE_WAKU1: wmouseMode = L"MODE_WAKU1"; break; case MODE_WAKU2: wmouseMode = L"MODE_WAKU2"; break; case MODE_END1: wmouseMode = L"MODE_END1"; break; case MODE_END2: wmouseMode = L"MODE_END2"; break; default: wmouseMode = L"default"; break; } StretchBlt(hdc, 0, 0, cx, cy, mem, 0, myTop, width, tate, SRCCOPY); TextOut(hdc, 200, 50, wmouseMode.c_str(), (int)wmouseMode.length()); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; si.nMin = 0; si.nMax = height - tate; si.nPos = myTop; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); EndPaint(hWnd, &ps); SelectObject(mem, obmp); DeleteObject(bmp); DeleteDC(mem); ReleaseDC(hWnd, hdc); } break;
今度はアプリ全体が停まる・・・12/21 土
次から次へと、問題が発生します。
Visual Studio 2019 C++ アプリが途中で止まる。困った・・・。
画像にいくつかのワクが表示してあり、カーソルを重なると、その都度、ワクが選択されるようなプログラムを作成しています。
実際には、マウスをうごかすたびに画像を表示しなおしているのですが、何度も動かしていると途中で止まります。
おそらく、リソースが不足していると思われますが、使用したツールはきちんと DeleteObject でリソースを開放しているはずなので、現時点では原因不明です。
しかし、このままでは、まったく役に立たちません。
困りました。
とりあえず、現時点での cpp プログラムを備忘録を兼ねて貼り付けておきますが、teratail と比べてプログラムの記載が難しいですね。
・・・と思ったら、<pre>を使うと簡単に表示できることを発見。htmlは、やっぱり知っておいた方が得だなあ。
#include "framework.h" #include "ScrollBar_Waku.h" #include "strconv.h" #include "atlimage.h" #includeusing namespace std; #define MAX_LOADSTRING 100 #define MAX_WAKU 100 // グローバル変数: HINSTANCE hInst; WCHAR szTitle[MAX_LOADSTRING]; WCHAR szWindowClass[MAX_LOADSTRING]; static CString filePath; static CImage img; static int width, height, myTop, mousex, mousey, memx, memy, mouseMode; static SCROLLINFO si; static int nowWaku, maxWaku; static RECT tmpWaku; static vector myWaku(MAX_WAKU); void InitWaku() { // テスト用にワクを設定しておく(将来的には削除) mouseMode = MODE_DONE; nowWaku = 0; maxWaku = 10; for (int i = 0; i < maxWaku; i++) { myWaku.at(i).top = 10 + i*50; myWaku.at(i).left = 50; myWaku.at(i).bottom = 50 + i*50; myWaku.at(i).right = 350; } } // このコード モジュールに含まれる関数の宣言を転送します: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: ここにコードを挿入してください。 filePath = L"sample.png"; img.Load(filePath); width = img.GetWidth(); height = img.GetHeight(); mousex = 0; mousey = 0; InitWaku(); // グローバル文字列を初期化する LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadStringW(hInstance, IDC_SCROLLBARWAKU, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // アプリケーション初期化の実行: if (!InitInstance(hInstance, nCmdShow)) { return FALSE; } HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SCROLLBARWAKU)); MSG msg; // メイン メッセージ ループ: while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int)msg.wParam; } // 目的: ウィンドウ クラスを登録します。 ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEXW wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SCROLLBARWAKU)); wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_SCROLLBARWAKU); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassExW(&wcex); } // 目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { hInst = hInstance; HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_VSCROLL, // ウインドウの種類 50, // x座標 50, // y座標 800,// 幅 600,// 高さ nullptr, // 親ウインドのハンドル nullptr, // メニューハンドル nullptr はクラスメニュー hInstance, nullptr ); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } int CheckMouse() { int tmpwk = nowWaku; mouseMode = MODE_DONE; for (int i = 0; i < maxWaku; i++) { if ( (memy > myWaku.at(i).top - myTop) && (memy < myWaku.at(i).bottom - myTop) && (memx > myWaku.at(i).left) && (memx < myWaku.at(i).right)) { tmpwk = i; mouseMode = MODE_WAKU1; break; } } return tmpwk; } void DrawCursor(HDC mem) { COLORREF mycolor; mycolor = RGB(0xff, 0x00, 0x00); HPEN hpen = CreatePen(PS_SOLID, 5, mycolor); HGDIOBJ ohpen = SelectObject(mem, hpen); SelectObject(mem, GetStockObject(NULL_BRUSH)); Ellipse(mem, memx - 15, myTop + memy - 15, memx + 15, myTop + memy + 15); SelectObject(mem, ohpen); DeleteObject(hpen); } void DrawWaku(HDC mem,int wk) { COLORREF mycolor; if (wk == nowWaku) { mycolor = RGB(0xff, 0x00, 0x00); } else { mycolor = RGB(0x00, 0x00, 0xff); } HPEN hpen = CreatePen(PS_SOLID, 5, mycolor); SelectObject(mem, GetStockObject(NULL_BRUSH)); HGDIOBJ ohpen = SelectObject(mem, hpen); Rectangle(mem, myWaku.at(wk).left, myWaku.at(wk).top, myWaku.at(wk).right, myWaku.at(wk).bottom); SelectObject(mem, ohpen); DeleteObject(hpen); } // 目的: メイン ウィンドウのメッセージを処理します。 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT recDisp; GetClientRect(hWnd, &recDisp); // クライアントを取得 int cx = recDisp.right; // クライアントのヨコ int cy = recDisp.bottom; // クライアントのタテ int tate; // イメージのタテ if (cx == 0) { tate = 0; memx = 0; memy = 0; } else { tate = cy * width / cx; memx = mousex * width / cx; memy = mousey * width / cx; } switch (message) { case WM_PAINT: { // ここから実際の描写 HDC hdc = GetDC(hWnd); HDC mem = CreateCompatibleDC(hdc); HBITMAP bmp = CreateCompatibleBitmap(hdc, width, height); HGDIOBJ obmp = SelectObject(mem, bmp); img.Draw(mem, 0, 0, width, height, 0, 0, width, height); for (int i = 0; i < maxWaku; i++) { DrawWaku(mem, i); } DrawCursor(mem); nowWaku = CheckMouse(); wstring wmouseMode; switch (mouseMode) { case MODE_DONE: wmouseMode = L"MODE_DONE"; break; case MODE_CLICK: wmouseMode = L"MODE_CLICK"; break; case MODE_WAKU1: wmouseMode = L"MODE_WAKU1"; break; case MODE_WAKU2: wmouseMode = L"MODE_WAKU2"; break; case MODE_END1: wmouseMode = L"MODE_END1"; break; case MODE_END2: wmouseMode = L"MODE_END2"; break; default: wmouseMode = L"default"; break; } PAINTSTRUCT ps; BeginPaint(hWnd, &ps); StretchBlt(hdc, 0, 0, cx, cy, mem, 0, myTop, width, tate, SRCCOPY); TextOut(hdc, 200, 50, wmouseMode.c_str(), (int)wmouseMode.length()); EndPaint(hWnd, &ps); SelectObject(mem, obmp); DeleteObject(bmp); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; si.nMin = 0; si.nMax = height - tate; si.nPos = myTop; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); } break; case WM_VSCROLL: { switch (LOWORD(wParam)) { case SB_LINEUP: if (myTop > 10) { myTop -= 10; } else { myTop = 0; } break; case SB_LINEDOWN: if (myTop < height - tate - 10) { myTop += 10; } else { myTop = height - tate; } break; case SB_PAGEUP: if (myTop > tate) { myTop -= tate; } else { myTop = 0; } break; case SB_PAGEDOWN: if (myTop < height - tate * 2) { myTop += tate; } else { myTop = height - tate; } break; case SB_THUMBTRACK: myTop = HIWORD(wParam); break; } InvalidateRect(hWnd, NULL, FALSE); } break; case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_MOUSEMOVE: mousex = LOWORD(lParam); mousey = HIWORD(lParam); InvalidateRect(hWnd, NULL, FALSE); break; case WM_KEYDOWN: { switch (wParam) { case VK_ESCAPE: if (maxWaku == 0) { PostQuitMessage(0); } else { maxWaku--; nowWaku = maxWaku-1; } break; case VK_NEXT: if (myTop < height - tate * 2) { myTop += tate; } else { myTop = height - tate; } break; case VK_PRIOR: if (myTop > tate) { myTop -= tate; } else { myTop = 0; } break; case VK_DOWN: if (myTop < height - tate - 10) { myTop += 10; } break; case VK_UP: if (myTop > 10) { myTop -= 10; } break; } InvalidateRect(hWnd, NULL, FALSE); } break; case WM_COMMAND: { int wmId = LOWORD(wParam); // 選択されたメニューの解析: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // バージョン情報ボックス INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; }
スクロールバー成功♪ 12/20 金
昨日、縮んでしまった画素は、本日、原因が特定できて、きちんと表示できるようになりました。
Visual Studio 2019 C++ 画像スクロールができました
前回、うまくいかなかった原因が特定できました。
具体的には、Draw(x,y,width,height) 等の関数で、height の部分を「画像の高さ」ではなく「画像の下端の y 座標」と勘違いしていたことが原因でした。
また、画面右のスクロールバーについて、min, max, pos 等の数値を適切に設定し、きちんと機能するようにできました。
スクロールバーが縮む・・・12/19 木
今週は、ずっとスクロールバーと格闘しています。
Visual Studio 2019 C++ スクロールで行が縮む
画像を表示させて、上下にスクロールさせる部分を作成しています。
画像は表示できたのですが、スクロールさせると行がだんだん縮んでいきます。
これでは、実用に耐えません。
プログラムをあれこれ調べても原因がわからず困っています。
スクロールバー表示成功 12/18 水
ごらんのとおり、スクロールバーの表示が成功し、動き始めました。でも、なかなか思い通りには動きません。画面と、うまく連携させるためには、「計算」が必要です。こういう面倒くさい計算を、みなさんやっていたんですねえ・・・。
スクロールバーって難しい 12/17 火
画像を上手に表示することに成功しましたが、画像は縦長なので、大きく表示すると、下の方が見えなくなります。
そこで、スクロールバーを用いて、画像を動かそうと考えたのですが、これが難しい!!
こんな面倒なことをやっていたのかと、びっくりしています。うーむ。大変だあ。
フィットネス 12/16 月
#フィットネス 2019/12/14
現在の走行距離の合計、約540km
本日から、ベンチ・プレスの主要部分が「45kg×10回×3セット」になりました。このまま数週間、様子を見ます。その後、じわじわと 47.5kg にあげていく予定です。
キャット&ドッグ 3回x3セット
ラット・プル (25kg+27kg+29kg)x10回
ベンチ・プレス 20kgx10+25kgx7+30kgx3+45kgx30回
トレッドミル(25分間) 3,070m ⇒2019年の累計 141,900m
ハムストリングス 23kgx10回x3セット
レッグ・エクステンション 39kgx10回x3セット
アダクション 52kgx10回x3セット
アブダクション 43kgx10回x3セット
プレス・ダウン 34kgx10回x4セット
アーム・カール 29kgx10回x4セット
レッグ・プレス 57kgx10回x3セット
腹筋 1秒x20回x3セット
ダンベル(内側) 10kgx23+12kgx7
ダンベル(外側) 4kgx20回x3セット
ライイング・トライセップス・エクステンション 10kgx40回+12.5kgx5回
フロント・プル 39kgx10回x3セット
バイク(25分間) 10,300m ⇒2019年の累計 398,910m
「授業をはじめてちょうだい」(視覚障害者) 12/15 日
Google の動画です。視覚障害者の女子児童が、iPad と「視覚障害者用キーボード」を用いて学習し、自分自身のレポートを作成しています。「ICTで、こんなことができる」
Google Classroom accessibility empowers inclusive learning
画面を画像として保存できるようになりました。12/14 土
画面上で画像を表示したり、四角を書いたり、いろいろと加工しています。その画面を画像として保存できるようになりました。
Attach() という関数が一番大事でした。
// BitBlt_CImage.cpp : アプリケーションのエントリ ポイントを定義します。
//#include "framework.h"
#include "BitBlt_CImage.h"
#include "strconv.h"
#include "atlimage.h"
#include <string>
using namespace std;#define MAX_LOADSTRING 100
// グローバル変数:
HINSTANCE hInst; // 現在のインターフェイス
WCHAR szTitle[MAX_LOADSTRING]; // タイトル バーのテキスト
WCHAR szWindowClass[MAX_LOADSTRING]; // メイン ウィンドウ クラス名static CString filePath, filePath2;
static CImage img2,tmpImg;
static int wi2;
static int he2;
static int mymx, mymy;
static HBITMAP tmpBitmap;// このコード モジュールに含まれる関数の宣言を転送します:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);// TODO: ここにコードを挿入してください。
// PNGファイルを読み込む CImage関連
filePath = L"sample.png";
filePath2 = L"sample2.png";
img2.Load(filePath);
wi2 = img2.GetWidth();
he2 = img2.GetHeight();
img2.Save(filePath2);// グローバル文字列を初期化する
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_BITBLTCIMAGE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);// アプリケーション初期化の実行:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_BITBLTCIMAGE));
MSG msg;
// メイン メッセージ ループ:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}return (int) msg.wParam;
}ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_BITBLTCIMAGE));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_BITBLTCIMAGE);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));return RegisterClassExW(&wcex);
}// 目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // グローバル変数にインスタンス ハンドルを格納するHWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);if (!hWnd)
{
return FALSE;
}ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);return TRUE;
}LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 選択されたメニューの解析:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;case IDM_SAVE:
{
RECT recDisp;
GetClientRect(hWnd, &recDisp); // クライアントを取得
int cx = recDisp.right; // クライアントのヨコ
int cy = recDisp.bottom; // クライアントのタテstring x1 = to_string(cx);
string y1 = to_string(cy);
string ss = "(" + x1 + "," + y1 + ") (" + to_string(mymx) + "," + to_string(mymy) + ")";wstring wss = utf8_to_wide(ss) + L" です";
// ここから実際の描写
HDC hdc = GetDC(hWnd);
HDC mem = CreateCompatibleDC(hdc); //HDCを取得
HBITMAP bmp = CreateCompatibleBitmap(hdc, cx, cy); //HBITMAPを取得 ★クライアントと同じ大きさ
HBITMAP obmp = (HBITMAP)SelectObject(mem, bmp); //HBITMAPを関連付けるHPEN hpen = CreatePen(PS_SOLID, 5, RGB(0x00, 0x7f, 0xff));
// 裏画面に描写する
img2.Draw(mem, 0, 0, wi2, he2, 0, 0, wi2, he2);HPEN ohpen = (HPEN)SelectObject(mem, hpen);
MoveToEx(mem, 50, 50, NULL);
LineTo(mem, mymx, mymy);
SelectObject(mem, ohpen);
DeleteObject(hpen);TextOut(mem, 10, 10, wss.c_str(), (int)wss.length());
// セーブする
CImage saveImage;
saveImage.Attach(bmp);
saveImage.Save(L"test.bmp");
saveImage.Save(L"test.jpg");
saveImage.Save(L"test.png");
saveImage.Detach();// あれこれ削除する。
SelectObject(mem, obmp);
DeleteObject(bmp);
DeleteDC(mem);DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
}
break;case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
RECT recDisp;
GetClientRect(hWnd, &recDisp); // クライアントを取得
int cx = recDisp.right; // クライアントのヨコ
int cy = recDisp.bottom; // クライアントのタテstring x1 = to_string(cx);
string y1 = to_string(cy);
string ss = "(" + x1 + "," + y1 + ") (" + to_string(mymx) + "," + to_string(mymy) + ")";wstring wss = utf8_to_wide(ss) + L" です";
// ここから実際の描写
HDC hdc = GetDC(hWnd);
HDC mem = CreateCompatibleDC(hdc); //HDCを取得
HBITMAP bmp = CreateCompatibleBitmap(hdc, cx, cy); //HBITMAPを取得 ★クライアントと同じ大きさ
HBITMAP obmp = (HBITMAP)SelectObject(mem, bmp); //HBITMAPを関連付けるHPEN hpen = CreatePen(PS_SOLID, 5, RGB(0x00, 0x7f, 0xff));
// 裏画面に描写する
img2.Draw(mem, 0, 0, wi2, he2, 0, 0, wi2, he2);HPEN ohpen = (HPEN)SelectObject(mem, hpen);
MoveToEx(mem, 50, 50,NULL);
LineTo(mem, mymx, mymy);
SelectObject(mem, ohpen);
DeleteObject(hpen);TextOut(mem, 10, 10, wss.c_str(), (int)wss.length());
// 表画面にコピー
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
BitBlt(hdc, 0, 0, cx, cy, mem, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);// あれこれ削除する。
SelectObject(mem, obmp);
DeleteObject(bmp);
DeleteDC(mem);
}
break;case WM_MOUSEMOVE:
mymx = LOWORD(lParam);
mymy = HIWORD(lParam);
InvalidateRect(hWnd, NULL, FALSE);
break;case WM_DESTROY:
PostQuitMessage(0);
break;default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
チラチラがなくなりました。12/13 金
自分自身が覚えておくために、cpp ファイルの中身だけ、掲載しておきます。「裏で描画し、表に一度にコピーする」ということをやっています。
// BitBlt_Test.cpp : アプリケーションのエントリ ポイントを定義します。
#include "framework.h"
#include "windows.h"
#include "BitBlt_Test.h"
#include "strconv.h"
#include <string>
using namespace std;#define MAX_LOADSTRING 100
// グローバル変数:
HINSTANCE hInst; // 現在のインターフェイス
WCHAR szTitle[MAX_LOADSTRING]; // タイトル バーのテキスト
WCHAR szWindowClass[MAX_LOADSTRING]; // メイン ウィンドウ クラス名// このコード モジュールに含まれる関数の宣言を転送します:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);// TODO: ここにコードを挿入してください。
// グローバル文字列を初期化する
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_BITBLTTEST, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);// アプリケーション初期化の実行:
if (!InitInstance (hInstance, nCmdShow)) {
return FALSE;
}HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_BITBLTTEST));
MSG msg;
// メイン メッセージ ループ:
while (GetMessage(&msg, nullptr, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}// ウィンドウ クラスを登録します。
ATOM MyRegisterClass(HINSTANCE hInstance) {
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_BITBLTTEST));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_BITBLTTEST);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}// インスタンス ハンドルを保存して、メイン ウィンドウを作成・表示します
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
hInst = hInstance; // グローバル変数にインスタンス ハンドルを格納する
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);if (!hWnd) {
return FALSE;
}ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}// WM_PAINT の部分だけを抜き出している。
void mypaint(HWND hWnd, LPARAM lParam) {RECT recDisp;
GetClientRect(hWnd, &recDisp); // クライアントを取得
int cx = recDisp.right; // クライアントのヨコ
int cy = recDisp.bottom; // クライアントのタテstring x1 = to_string(cx);
string y1 = to_string(cy);
string ss = "x:" + x1 + " y:" + y1;
wstring wss = utf8_to_wide(ss) + L" です";// ここから実際の描写
HDC hdc = GetDC(hWnd);
HDC mem = CreateCompatibleDC(hdc); //HDCを取得
HBITMAP bmp = CreateCompatibleBitmap(hdc, cx, cy); //HBITMAPを取得 ★クライアントと同じ大きさ
HBITMAP obmp = (HBITMAP) SelectObject(mem, bmp); //HBITMAPを関連付ける
HBRUSH br = CreateSolidBrush(RGB(0, 0, 255)); //HBRUSHを取得
HBRUSH obr = (HBRUSH) SelectObject(mem, br); //HBRUSHをを関連付ける// 裏画面に描写する
FillRect(mem, &recDisp, br);
TextOut(mem, 10, 10, wss.c_str(), (int)wss.length());// 表画面にコピー
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
BitBlt(hdc, 0, 0, cx, cy, mem, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);// あれこれを削除する。
SelectObject(mem, obmp);
SelectObject(mem, obr);
DeleteObject(bmp);
DeleteObject(br);
DeleteDC(mem);
}// メイン ウィンドウのメッセージを処理します。
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_COMMAND: {
int wmId = LOWORD(wParam);
// 選択されたメニューの解析:
switch (wmId) {
case IDC_BITBLTTEST:
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;case WM_PAINT:
mypaint(hWnd, lParam);
break;case WM_MOUSEMOVE:
InvalidateRect(hWnd, NULL, FALSE);
// 3つ目がTRUEだと、BeginPaint() で背景を消去するのでチラチラする
break;case WM_DESTROY:
PostQuitMessage(0);
break;default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}// バージョン情報ボックスのメッセージ ハンドラーです。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
UNREFERENCED_PARAMETER(lParam);
switch (message) {
case WM_INITDIALOG:
return (INT_PTR)TRUE;case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}