お世話になっています。今回もご教授お願いしたいのですが・・・。
CreateWindow(COMBOBOXを指定)で作成したコンボボックスにGetCurrentDirectory と
SetWindowText を使って現在のカレントディレクトリの表示をするところまで出来てい
るのですが、
リストビューのファイルを選択したときのそのディレクトリの表示の仕方がわかりま
せん。何となくイメージとしては、
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_COMBO:
if (HIWORD(wParam) == CBN_DBLCLK) {
(1)
}
のような処理で出来るとおもうのですが、(1)の部分をどうすればいいのかわかりま
せん。一応、SetCurrentDirectoryで処理してみたのですが、表示内容に変化はみられま
せんでした。このようなイメージで良いの?良いのだったら(1)の部分はどうしたら良い
の? CB_SETCURSELとか? 全くの的はずれ? よろしくお願いします。
環境 WinXP
VC++.NET
SDK
> リストビューのファイルを選択したときのそのディレクトリの表示
>
どこに表示したいのですか?
リストビューのアイテム選択を検出する必要があるはずですが、
掲載されているプログラムは、コンボボックスからのメッセージを処理しようとしてますよね。
それから、リストビューとコンボボックスは、同じアプリの同じ画面(例えばダイアログ)に
あるものと考えてよいのでしょうか。
> どこに表示したいのですか?
コンボボックスに表示したいとおもっています。
> それから、リストビューとコンボボックスは、同じアプリの同じ画面(例えばダイアロ
グ)にあるものと考えてよいのでしょうか。
はい。ツールバーの下にコンボボックスがあって、その下にリストビューがあります。
よろしくお願いします。
1) リストビュー内のアイテムがクリックされたことを検出できますか?
2) 選択された(クリックされた)アイテムからディレクトリを取得することはできますか?
3) 取得したディレクトリをコンボボックスに表示させる方法はご存知ですか?
4) 3)は、コンボボックスのタイプによって手法が異なるのですが、
この辺りは大丈夫ですか?
一口に「リストビューのファイルを選択したときのそのディレクトリを
コンボボックスに表示する」と言っても、
実現のためにはいくつものステップを踏まないといけませんから、
もう少し問題を細分化しないと、手がつけられなくなってしまいますよ。
> 1) リストビュー内のアイテムがクリックされたことを検出できますか?
(switch文)
case NM_CLICK:
GetCursorPos関数;
ScreenToClient関数;
ListView_HitTest関数;
これで、リストビュー内のアイテムがクリックされたことを検出できると思います。
> 2) 選択された(クリックされた)アイテムからディレクトリを取得することはできます
か?
上記のListView_HitTest関数;以下のところで、GetCurrentDirectory関数で取得し
て、SetCurrentDirectory関数で設定するのでしょうか。すみません、よくわかっていま
せん。
> 3) 取得したディレクトリをコンボボックスに表示させる方法はご存知ですか?
全くの勘違いでした。よくわかっていません。
> 4) 3)は、コンボボックスのタイプによって手法が異なるのですが、
この辺りは大丈夫ですか?
タイプとしては、レバーコントロールに
CreateWindow(COMBOBOX, ", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,・・・・)
で作成したコンボボックスをのせているのですが・・・。
よろしくご教授のほどお願いします。
ひとつひとつ解決していきましょう、一度にすべてはムリです。
まず1番目ですが、「検出できると思う」のなら、本当にできるかどうか試してみましょう。
「百聞は一見に如かず」です。
NM_CLICKで間違いではありませんが、アイテムではないところをクリックしても
発生するので、その点は気をつけてください。
あと、GetCursorPos()以下3関数ですが、何のために使うのでしょう。
少なくともアイテムクリックの検出には必要ないと思われますが。
2番目ですが、このアプリケーション固有の仕様になる部分ですよね、
初めに「リストビューのファイルを選択したときのそのディレクトリの表示」と言ってますが、
ここでいうディレクトリって、何のディレクトリなんですか?
GetCurrentDirectory()は、アプリケーションの現在のディレクトリを返すだけですが、
それは仕様としてあっているのですか?
3番目ですが、最初の発言で「コンボボックスにカレントディレクトリの表示をするところ
まで出来ている」とありますが。
何か矛盾してませんか?
4番目ですが、コンボボックスがリバーコントロール上にあるということは、大事なことです。
これは初めに言っておかなければなりません。
ただ、コンボボックスのウィンドウハンドルさえ保持していれば、何でもできますよ。
> まず1番目ですが、「検出できると思う」のなら、本当にできるかどうか試してみま
しょう。
case NM_CLICK:
MessageBox(hWnd,ディレクトリを表示したいよ,がんばれ!,MB_OK);
break;
これでリストビュー内のアイテムをクリックするとメッセージボックスが出現され、ア
イテム外だとメッセージボックスは出現されませんでした。これで検出の確認は出来た
と思うのですが・・・。
> 2番目ですが、このアプリケーション固有の仕様になる部分ですよね、
初めに「リストビューのファイルを選択したときのそのディレクトリの表示」と言って
ますが、ここでいうディレクトリって、何のディレクトリなんですか?
クリックして選択されたアイテムのディレクトリ(絶対パス)であって、
C:\マイドッキュメント\マイソフトウエア\のような感じのものです。(エクスプローラ
のアドレス欄に表示される文字列と同じものです。)
> GetCurrentDirectory()は、アプリケーションの現在のディレクトリを返すだけです
が、それは仕様としてあっているのですか?
あっ、これも間違っていました。アプリケーションの現在のディレクトリは必要ないか
も・・・。
> 3番目ですが、最初の発言で「コンボボックスにカレントディレクトリの表示をする
ところまで出来ている」とありますが。何か矛盾してませんか?
WM_CREATE のところでコンボボックスを作成すると同時にGetCurrentDirectory() と
SetWindowText()を実行してしまったのですが、これもおかしいですね。間違ってまし
た。
> コンボボックスのウィンドウハンドルさえ保持していれば、何でもできますよ。
コンボボックスのウィンドウハンドルをグローバル変数に保持すればOKですね。
よろしくお願いします。
アイテムのクリックは大丈夫そうですね。
ところで、ディレクトリはアイテム毎に異なるものを持つことを想定しているようですが。
どこのディレクトリのなんていう名前のファイルかは、
どこかに保持しておかなければなりませんよ。
フルパス名をアイテムやサブアイテムの名称に設定しているなら話は別ですが、
そうでないなら、パス情報を保持する工夫を別途施す必要があります。
コンボボックスを生成する時にCBS_DROPDOWNスタイルを設定しているので、
ドロップダウンコンボというタイプであると推測されます。
(コンボボックスの種類についてはMSDNで調べてください。)
このタイプのコンボボックスは、SetWindowText()で「表示」は可能です。
しかし、ダウンリストの方へは追加されません。
追加する場合はCB_ADDSTRINGメッセージを使ってください。
この辺りはコンボボックスの基本ですので、しっかりおさえておくようにしましょう。
ありがとうございます。
> ところで、ディレクトリはアイテム毎に異なるものを持つことを想定しているようで
すが。どこのディレクトリのなんていう名前のファイルかは、どこかに保持しておかな
ければなりませんよ。
自信ありませんが、char szfname[MAX_PATH]; で保持できるような気がするのです
が・・・。
それと、前出(2002/07/22(月) 18:14:42)の
> 2) 選択された(クリックされた)アイテムからディレクトリを取得することはできま
すか?
なのですが、この辺が特に理解できていないのですが。どの関数でディレクトリを取得
すればいいのでしょうか。ご指導お願いできないでしょうか。
> char szfname[MAX_PATH]; で保持できるような気がするのですが・・・。
>
方向としてはあってます。
ただ、各アイテム毎に異なるディレクトリ情報があるわけですから、
リストビューに追加したアイテムの数だけ、バッファを用意する必要があります。
このバッファをどこに配置するかが考えどころです。
アイテム数が固定であるならグローバルで宣言しておくのもよいですが、
不定である場合、事前にいくつ分のバッファを用意すればよいかが定まりません。
そのような場合は、アイテムを追加する度にmalloc()等で動的にメモリを確保する手段を
お勧めします。
アイテムをリストに追加する際に使用するLVITEM構造体には、
lParamというメンバがあります。
ここに任意の数値データを格納することができるので、確保したメモリのアドレスは
ここにセットしておけばよいでしょう。
「選択されたアイテムからディレクトリを取得することができるか」というのは、
選択したアイテムと、上記で説明したバッファの対応付けができているか、ということです。
lParamにアドレスを格納しておけば、対応付けは特に考える必要もありません。
この辺りは、リストコントロール(人によってはリストビューコントロール)の基本です。
おさえておきましょう。
ありがとうございます。
アイテム数は不定であるので、lParam にmalloc()等で動的に確保したメモリのアドレ
スをセットする仕方でやろうと思います。でも、具体的にはどのような感じで・・・。
よろしくご指導お願いします。
まずは自分でコードを組んでみましょう。
ダメだったら、ダメなコードをたたき台として提示してください。
そうすれば、ここがダメ、あそこがダメと具体的な話ができます。
(1)動的に確保したメモリに任意のディレクトリをセットし、
そのアドレスをlParamにセットしてリストコントロールにアイテム追加を行うところ
(2)NM_CLICKを受けた時に選択状態にあるアイテムを認識し、
そのアイテムのlParamを取得して、そこにセットされてる文字列(具体的には
ディレクトリ)を得るところ
上記2点について考えられれば、かなりゴールに近づくのではないでしょうか。
メモリを動的に確保する方法がわからないなら、リストコントロール云々の前に
そちらを勉強する必要があります。
尚、話の流れの中で説明を省略してしまいましたが、
メモリを動的に確保した場合、その方法論によらず、
不要になった時は必ずそのメモリを解放してあげなければなりませんから、
忘れないようにして下さい。
ありがとうございます。
あれから頭で色々と考えてコードの組み立てをしょうとしているのですが、すみませ
ん、もう、最初から分からないです。
> 動的に確保したメモリに任意のディレクトリをセットし・・・
ですが、
動的にメモリを確保→ sgm=SHGetMalloc(&lpMalloc);
開放→ lpMalloc->・・・->Release(lpMalloc);
はこれでいいように思うのですが・・・、
> 任意のディレクトリ
がよく分かりません。ディレクトリは取得するものと思っているのですが、ここで言う
任意のディレクトリとは何なのか教えてください。
どこからかGET!するもの?ひょっとして自前でこしらえるもの?
ご指導お願いします。
> 動的にメモリを確保→ sgm=SHGetMalloc(&lpMalloc);
> 開放→ lpMalloc->・・・->Release(lpMalloc);
>
すみません、その関数、私使ったことがないもんで、ちょっとよくわかんないです。
シンプルに、
確保→ char *p = (char*)malloc(sizeof(char) * MAX_PATH);
解放→ free(p);
でよろしいかと。
> > 任意のディレクトリ
> がよく分かりません。ディレクトリは取得するものと思っているのですが、ここで言う
> 任意のディレクトリとは何なのか教えてください。
>
!ちょっと待ってください、どうやら認識にズレがあるようです。
リストビューにあるアイテムは、Aディレクトリのファイル、Bディレクトリのファイル...
の各アイテムがあるのではないのですか?
だからこそ、アイテムをクリックした時に、パス名をコンボボックスに表示するのだと
認識していたのですが。
「リストビューのファイルを選択したときのそのディレクトリの表示」という発言は、
そういう意味ではなかったのでしょうか?
ちょっと話がそれてしまいましたが、少なくとも私はそういう認識だったため、
各アイテム(=各ファイル)の所在するパス名を、
別途確保したメモリに保持しておく必要があると判断しました。
ここが違うと、前提が変わってしまいますね...(汗
横槍になりますけれど、
普通にランタイム関数のmallocしても良いような気がします。
あとは、GlobalAllocを使う手もあるかと。
IMallocまで行かなくてもいいような。
メモリの確保方法は色々あるので確認しておいたほうがいいと思いますよ。
あと、リストボックスのアイテムと対応するディレクトリに関する情報は
どこから提供されるのかがわからないと返答のしようが無いと思いますよ。
その情報はプログラマ側で予めわかる物なのですか?
それとも外側から与えられる物なのでしょうか?
そもそも、リストボックス内のアイテムとディレクトリの関係がどんな物なのか
あなた自身は把握しているのでしょうか?