ひとりも見捨てないことを、あきらめない

学校教育、社会教育、数学、技術家庭科、Youtube、EdTech、ICT、プログラミング、その他

あきらめました・・・12/27 金

 昨日も書いた、PDF ファイルの読み込みですが、フリーのライブラリがありません。正確にいうと、C++ で使えるライブラリがありません。

 強いてやろうとすると、poppler という GNU ライブラリを C++ のために再構築することになります。そのためには、たぶん、CMAKE などが必要になります。これが、けっこう大変で、おそらく「いつまで経っても必要なものが得られない」ということになりそうです。

 そこで、まず開発言語を C++ から C# に変更しようと考えています。その理由は、ただ一つで「PDFium が、おそらく使えるから」です。

 PDFium は、GoogleChrome のために開発した PDF 関連のエンジンで、商用も含めて自由に使えます。

 これが使えるのであれば、わざわざ C++ で苦労する必要はないだろうと思います。

 というわけで、明日からは C# と PDFium を使おうと思います。

f:id:takase_hiroyuki:20191123160855p:plain

 

 

ここまでできました。 12/26 木

Windows10, Visual Studio 2019, C++ という開発環境で、アプリケーションの開発をしていますが、現時点で「ここまでできた」というものを Youtube に投稿しました。

以下を御覧ください。

 

 画像の表示と拡大・縮小、ワクの設定と移動・拡大・縮小・削除、スクロール機能を実装しました。

 でも、まだまだ、これからです。当面の最大の難関は、PDF ファィルの読み込み です。これが、非常に難しい。

 がんばります。

f:id:takase_hiroyuki:20191123160855p:plain

 

リソースの開放に成功しました 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;

f:id:takase_hiroyuki:20191123160855p:plain

GDIビューアって、すごく便利・・・12/24 火

 プログラムを作っていると、作ったプログラムでコンピュータのメモリとかディスクとか、いろいろなものを消費します。あまりたくさん消費しすぎると、コンピュータ全体がモタモタしたり、ひどい場合には、コンピュータ全体が止まってしまったりします。

 特に、多くの領域を使うのは、画像や動画関係の「部品」で、それを「GDI」と呼びます(厳密には違うと思うけど、まあ、そういうことで)。

 なにしろ、プログラムの初心者なので、いままで「自分の作ったプログラムが、そういうコンピュータの資源をどのように消費しているのか」を自分で確認する方法を知りませんでした。

 このたび、次のようなソフトウエアがあることを知りました。

  このソフトは、「インストールする必要なし。解凍したらそのまま実行するだけ」という単純(?)な作りです。

  で、先日、「とまっちゃうよー」と質問した欠陥プログラムについて調べてみると、ものの見事に資源を消費していました。個数がどんどん増えていって、合計 10000個を超えたところで、ピタッと止まりました(他のソフトに悪影響がないように、10000個で止まるように、あらかじめ設定してあったらしい)。

 以下、Youtube の動画を御覧ください。


リソースの開放に失敗すると、GDI が増えます。

 というわけで、がんばって、改良します。

f:id:takase_hiroyuki:20191224090555p:plain

 

フィットネス・・・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

f:id:takase_hiroyuki:20190519162425p:plain

 

また、助けていただきました・・・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;

f:id:takase_hiroyuki:20191123160855p:plain

今度はアプリ全体が停まる・・・12/21 土

次から次へと、問題が発生します。


Visual Studio 2019 C++ アプリが途中で止まる。困った・・・。

 

画像にいくつかのワクが表示してあり、カーソルを重なると、その都度、ワクが選択されるようなプログラムを作成しています。

実際には、マウスをうごかすたびに画像を表示しなおしているのですが、何度も動かしていると途中で止まります。

おそらく、リソースが不足していると思われますが、使用したツールはきちんと DeleteObject でリソースを開放しているはずなので、現時点では原因不明です。

しかし、このままでは、まったく役に立たちません。

困りました。

 

とりあえず、現時点での cpp プログラムを備忘録を兼ねて貼り付けておきますが、teratail と比べてプログラムの記載が難しいですね。

・・・と思ったら、<pre>を使うと簡単に表示できることを発見。htmlは、やっぱり知っておいた方が得だなあ。

#include "framework.h"
#include "ScrollBar_Waku.h"
#include "strconv.h"
#include "atlimage.h"
#include 
using 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;
}

f:id:takase_hiroyuki:20191123160855p:plain

スクロールバー成功♪ 12/20 金

昨日、縮んでしまった画素は、本日、原因が特定できて、きちんと表示できるようになりました。


Visual Studio 2019 C++ 画像スクロールができました

前回、うまくいかなかった原因が特定できました。

具体的には、Draw(x,y,width,height) 等の関数で、height の部分を「画像の高さ」ではなく「画像の下端の y 座標」と勘違いしていたことが原因でした。

また、画面右のスクロールバーについて、min, max, pos 等の数値を適切に設定し、きちんと機能するようにできました。

f:id:takase_hiroyuki:20191123160855p:plain

 

スクロールバーが縮む・・・12/19 木

今週は、ずっとスクロールバーと格闘しています。


Visual Studio 2019 C++ スクロールで行が縮む

画像を表示させて、上下にスクロールさせる部分を作成しています。

画像は表示できたのですが、スクロールさせると行がだんだん縮んでいきます。

これでは、実用に耐えません。

プログラムをあれこれ調べても原因がわからず困っています。

f:id:takase_hiroyuki:20191123160855p:plain

 

スクロールバー表示成功 12/18 水

ごらんのとおり、スクロールバーの表示が成功し、動き始めました。でも、なかなか思い通りには動きません。画面と、うまく連携させるためには、「計算」が必要です。こういう面倒くさい計算を、みなさんやっていたんですねえ・・・。

f:id:takase_hiroyuki:20191218070436p:plain

 

スクロールバーって難しい 12/17 火

画像を上手に表示することに成功しましたが、画像は縦長なので、大きく表示すると、下の方が見えなくなります。

そこで、スクロールバーを用いて、画像を動かそうと考えたのですが、これが難しい!!

こんな面倒なことをやっていたのかと、びっくりしています。うーむ。大変だあ。

f:id:takase_hiroyuki:20191218050345p:plain

 

フィットネス 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
 

f:id:takase_hiroyuki:20190519162425p:plain



「授業をはじめてちょうだい」(視覚障害者) 12/15 日

Google の動画です。視覚障害者の女子児童が、iPad と「視覚障害者用キーボード」を用いて学習し、自分自身のレポートを作成しています。「ICTで、こんなことができる」


Google Classroom accessibility empowers inclusive learning

f:id:takase_hiroyuki:20191215091928p:plain

 

画面を画像として保存できるようになりました。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;
}

f:id:takase_hiroyuki:20191123160855p:plain


 

チラチラがなくなりました。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;
}

 

f:id:takase_hiroyuki:20191123160855p:plain