Win32APIでWM_LBUTTONDOWN→再描画の処理がうまくいきません

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
keito
記事: 33
登録日時: 3年前

Win32APIでWM_LBUTTONDOWN→再描画の処理がうまくいきません

#1

投稿記事 by keito » 2年前

こんにちはです、Win32APIについての質問です(C/C++、Win32APIは勉強中なので知識はあやふや)

ウィンドウにグラフをマウスで作成して最短距離を求めるアプリケーションを作りたいと思っています。
現在マウス左ボタンが押された時にノードが作成されてグラフを再描画する処理を行いたいのですが、
case WM_LBUTTONDOWN:(左クリックを押した時)の処理がうまくいきません。

クリックした場所にノードが描画される(円が表示される)......と思うのですが、何も起きません。
問題点が分からないので、もし分かる方いたら問題点と解決策をお願いします

コード:

//WindowsProject1(一部)
//...
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	Window_Graph mygraph;
	
	switch (message)
	{
	case WM_COMMAND:
	{
		//...
	}
	case WM_LBUTTONDOWN: 
		mygraph.create_node(LOWORD(lParam),HIWORD(lParam) ); //クリック箇所にノード作成
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		//TODO: Add any drawing code that uses hdc here...
		//mygraph.create_node(100,100); <--ここに書くと描画されるけどクリックに対応しない...	
		mygraph.paint_graph(hdc); //グラフの描画
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}
//...

コード:

//create_graph.h
#pragma once
#include"paint.h"
#include<vector>
#include<list>
#include<iterator>
using namespace std;
//OPTION : 通過は任意のノード
//PASS : 通過しなければならないノード
//PAIR : STARTとGOALの両方をあわせ持つノード(但し別のノードを1個以上通過)
enum Node_Type { OPTION, PASS, START, GOAL, PAIR };
enum Edit_Mode { NODE, EDGE }; //編集中
//作成できるノードの最大、各ノードの描画サイズ
static const int max_node = 65535;
static const int option_size = 15;
static const int pass_size = 15;
static const int start_size = 20;
static const int goal_size = 20;
static const int pair_size = 20;


struct Edge { //エッジの情報
	int next_node_num; //エッジの終点
	int cost = 1; //エッジのコスト
};

struct Node { //ノードの情報
	Node_Type type = OPTION; //ノードの種類
	int x; //座標
	int y;
	list<Edge> next = {}; //エッジで移動可能なノード
};

class Graph { //グラフの情報
public: //後にpublicからprotectedに変更
	vector<Node> node_vec = {};
	bool create_node(const int new_x, const int new_y); //ノードの作成
	bool change_node(const int change_node_num, const Node_Type change_type); //ノードの種類を変更
	bool delete_node(const int del_num); //ノードを削除
	void move_node(const int move_node_num, const int to_x, const int to_y); //ノードの座標を変更
	bool create_edge(const int begin_num, const int end_num, const int set_cost = 1); //エッジの作成
	bool delete_edge(const int begin_num, const int end_num); //エッジの削除
};

class Window_Graph :public Graph { //+Graphクラスにウィンドウでの処理をするため必要な関数を追加
	Edit_Mode now_edit = NODE; //ノードを編集するかエッジを編集するかの設定
	int check_ride(LPARAM lParam); //マウスポインタ上にあるノードを調べる
public:
	void node_lbuttondown(const LPARAM lParam); //ノード編集中に左ボタンを押した時の処理
	void node_rbuttondown(const LPARAM lParam); //TODO: ノード編集中に右ボタンを押した時の処理
	void edge_lbuttondown(const LPARAM lParam); //TODO: ノード編集中に左ボタンを押した時の処理
	void edge_rbuttondown(const LPARAM lParam); //TODO: エッジ編集中に右ボタンを押した時の処理
	void change_edit_mode(); //now_editを変更
	bool paint_graph(const HDC hdc); //グラフの描画
	void shortest_pass(); //TODO: グラフから最短距離を探す
};

コード:

//create_graph.cpp(一部)
//...
bool Graph::create_node(const int new_x, const int new_y) {
	if (node_vec.size() >= max_node)return false;
	node_vec.push_back({ OPTION,new_x,new_y,{} });
	return true;
}
//...
bool Window_Graph::paint_graph(const HDC hdc) {
	HBRUSH hbrush;
	WCHAR str[100];
	for (auto f_iter = cbegin(node_vec); f_iter != cend(node_vec); ++f_iter) {
		for (auto s_iter = cbegin(f_iter->next); s_iter != cend(f_iter->next); ++s_iter)
			paint_line(hdc, f_iter->x, f_iter->y,
				node_vec[s_iter->next_node_num].x, node_vec[s_iter->next_node_num].y); //線を描画する関数
	}

	for (auto iter = cbegin(node_vec); iter != cend(node_vec); ++iter) {
		switch (iter->type) {
		case OPTION:
			hbrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
			SelectObject(hdc, hbrush);
			paint_circle(hdc, iter->x, iter->y, option_size); //円を描画する関数
			DeleteObject(hbrush);
			break;
		case PASS:
			hbrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
			SelectObject(hdc, hbrush);
			paint_square(hdc, iter->x, iter->y, pass_size); //四角形を描画する関数
			DeleteObject(hbrush);
			break;
		case START:
			hbrush = (HBRUSH)GetStockObject(GRAY_BRUSH);
			SelectObject(hdc, hbrush);
			paint_square(hdc, iter->x, iter->y, start_size);
			DeleteObject(hbrush);
			break;
		case GOAL:
			hbrush = (HBRUSH)GetStockObject(BLACK_BRUSH);
			SelectObject(hdc, hbrush);
			paint_square(hdc, iter->x, iter->y, goal_size);
			DeleteObject(hbrush);
			break;
		case PAIR:
			hbrush = (HBRUSH)CreateHatchBrush(HS_DIAGCROSS, RGB(0, 0, 0));
			SelectObject(hdc, hbrush);
			paint_square(hdc, iter->x, iter->y, pair_size);
			DeleteObject(hbrush);
			break;
		default:
			return false;
		}
	}
	return true;
}
(長くて分かりにくい説明とコードすみません……)

アバター
みけCAT
記事: 6225
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: Win32APIでWM_LBUTTONDOWN→再描画の処理がうまくいきません

#2

投稿記事 by みけCAT » 2年前

WM_LBUTTONDOWNの処理で更新されているmygraphは自動変数なので、WndProc()の別の呼び出しで前の呼び出しの時のデータは利用できません。
すなわち、WM_LBUTTONDOWNの処理の時の更新はWM_PAINTの時にはなかったことになります。
例えば、Window_Graph mygraph;の前にstaticをつけて静的変数にするか、Window_Graph mygraph;をWndProcの前に出してグローバル変数にすると、改善されると思われます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

keito
記事: 33
登録日時: 3年前

Re: Win32APIでWM_LBUTTONDOWN→再描画の処理がうまくいきません

#3

投稿記事 by keito » 2年前

staticをつけることで無事解決しました!ありがとうございます!

返信

“C言語何でも質問掲示板” へ戻る