スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

ListViewのヘッダ幅を固定してみる(C++/CLI & win32)



なんかやっぱり流行りというかAndroid関連での検索が引っかかってくる今日この頃。
そんな中 windowsformアプリ関連(C++/CLI)のことをちょこっと。しかも今更な内容。
正直Windowsアプリはwin32APIでゴリゴリに書く人で、.Netってな~に?って状態ですので、間違ってても責任取りません。
ってかむしろこういう方法あるよ!、みたいな素敵な指摘が欲しいです。


内容としては ListView header幅固定 を C++/CLIにwin32APIを混ぜて実現したもの
ちなみにヘッダの境界線にマウスが来た際にマウスカーソルが変更されるのも阻止。
まとめると
・ListViewのヘッダ幅がマウスで弄れないこと
・ヘッダの境界線上でマウスカーソルが変わらないこと
なお、会社で確認した動作確認はXP SP3
開発はVS2008 standerd sp1
家での確認は 7 pro のVC++ 2008 Express Edition


スゲー簡単な方法


// stdafx.hに追加
	#include"windows.h"
	#include "commctrl.h"

// Form1.hの適当なところに追加
// 略
	EnableWindow( ListView_GetHeader( reinterpret_cast(this->listView1->Handle.ToInt32()) ), FALSE);
// 略

ぶっちゃけ、 Google先生に「ListView ヘッダ固定」で聞いてTOPに返ってくる内容ですが…。
上記内容をフォームのコンストラクタの中にでも突っ込んでおけばOK。
その辺から拾ってきたのを足しただけですので、ありなのかどうかすら分かりませんが、一応目的は果たせます。


上記の注意点


windows form アプリ的にはあまりwin32APIを使用されたくなさそうです。
環境にもよりますが、多分上記はまずリンカエラーとなるでしょう。
これもググれば答えが返ってきますが、一応方法を。

vs2008 standerd sp1 の場合は、うろ覚えですが、
・プロジェクト → プロパティ → C/C++ → 全般 → 追加のインクルードなんたら → 親からなんたら にチェック
で通るようになるかと。
何でも2005位からformアプリ作成時の初期設定では、win32用のライブラリが軒並み外されているとかで、自分で設定が必要らしいです。
もちろん個別に必要なライブラリをリンクしてもいいんですけど。

VC++ 2008 Express Edition
上記と同じ方法で行けると思いきや、駄目でした。
そこで取った方法は次の方法。
・Win32コンソールアプリを作成
・プロジェクト → プロパティ → リンカ → コマンドライン からlibファイル名をコピー
・Formアプリの同じ場所にコピーした内容を貼付け
超強引ですがこれで行けますwww

ちなみにコピーした内容はこれ
kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
不要なものも居るけどその辺は無視。


ちょっと面倒な方法


お作法的にいいのかどうかは全く分かりませんが、上記にたどり着いて気がついたのは 「余裕でwin32APIガンガン使えるじゃん!」ってことです。
ウィンドウハンドル取得できれば結構やりたい放題ですよね。
さて、上記のようにHeaderを無効化することで目的を果たすと、楽は楽なのですがこんな要望が来たらアウト。
・ヘッダ部分のクリックはしたい!
更に、私が確認した環境では上記方法ではヘッダ部分をクリックすると、何故か一行目のアイテムがクリックされたと認識することも発覚。
というわけで、ListViewもヘッダ部分もサブクラス化してしまへ。


//****************
// Form1.hとか
//****************

	HWND hList = reinterpret_cast(this->listView1->Handle.ToInt32());
	HWND hHeader = ListView_GetHeader( hList);
	
	OrgList = (WNDPROC)GetWindowLongPtr( hList, GWLP_WNDPROC);
	SetWindowLongPtr( hList, GWLP_WNDPROC, (LONG_PTR)ListViewSubWindowProc);
	
	OrgListHeader = (WNDPROC)GetWindowLongPtr( hHeader, GWLP_WNDPROC);
	SetWindowLongPtr( hHeader, GWLP_WNDPROC, (LONG_PTR)ListViewHeaderSubWindowProc);


//****************
// hoge.cpp/h 色々略
//****************

WNDPROC OrgList, OrgListHeader;


LRESULT CALLBACK    ListViewHeaderSubWindowProc( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
	switch(msg){
	case WM_SETCURSOR:
		return TRUE;
	}
	return (CallWindowProc(OrgListHeader, hWnd, msg, wp, lp));
}

LRESULT CALLBACK    ListViewSubWindowProc( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
	NMHEADER* pnmhdr;
	switch(msg){
	case WM_NOTIFY:
		pnmhdr = (NMHEADER*)lp;
		
		switch(pnmhdr->hdr.code){
		case HDN_ENDTRACK:
		case HDN_BEGINTRACK:
		case HDN_TRACK:
		case HDN_DIVIDERDBLCLICKW:
			return TRUE;
		}
		break;
	}
	return (CallWindowProc(OrgList, hWnd, msg, wp, lp));
}

上記のソースもその辺探せば幾らでも出てきます。
・Header部分でカーソルを変更させない
・カラム幅をいじらせない
それぞれを自前で実装したというか、本来の実装へ渡さないだけですが。

ちなみにヘッダをクリックできるとか出来ないとかは、ListView::HeaderStyleで変更出来ますので、
まあ、わざわざwin32APIを使用するまででもないでしょう。

なお、恐らくこの段階ではまたもエラーになると思います。
コンパイル時に「 /clr:pure または /clr:safe と共にコンパイルされた関数に対する呼び出し規約 '__stdcall ' が無効です」というエラーがでると思います。
その指摘に従って
・プロジェクト → プロパティ → 共通言語ランタイム サポート
を /clr:pure から /clr へ変更することで、コンパイルが通るようになります。


また、Vistaから「HDS_NOSIZING」なるスタイルが追加されたようなのですが、 もしかするとこれらの実装(サブクラス化)をしなくても、このスタイル設定一発で終わる可能性も大ですね。
ま、めんどくて確認していませんし、そもそも私の場合XPで動作することが前提ですから。
誰か結果を教えてください。

ってか、こんな実装ありなんだろうか…
ぶっちゃけ何処がC++/CLIなんだか、普通にwin32じゃん…
C++/CLI 使いの方教えてください。
むしろ一番目に書くべきな気もしますが、貼り付けたコンソールのウィンドウハンドルって結構簡単に取れるよ!ってことが言いたいだけです。


関連記事

テーマ : プログラミング
ジャンル : コンピュータ

tag : サンプルソース

コメントの投稿

非公開コメント

プロフィール

駄猫

Author:駄猫

Twitter
その他
最新記事
カテゴリ
月別アーカイブ
検索フォーム
RSSリンクの表示
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。