複数のコンボボックスを連動するには・・・

[戻る]
tikira 2006/10/02(月) 15:07:49
先日もファイル読み込みでお世話になりましたものですm(__)m

CSVファイルからコンボボックスへアイテムを読み込んでいます。
コンボボックスが3つあり、コンボボックス1とコンボボックス2とコンボボックス3を連
動させたいのです。
コンボボックスからアイテムが選択されたときOnSelchangeItem()にとび
その中で、コンボボックス1で選ばれたアイテムを取得するのだと考えていますが
取得したあと、どのようにコンボボックス2へ連動するようにさせるのか
初心者に分かりやすい方法がありましたら教えてくださいm(__)m!
よろしくお願いしますm(__)m

tikira 2006/10/02(月) 15:13:55
追記です:

WindowsXP
VisualC++6.0
MFC

tikira 2006/10/02(月) 15:22:24
再び、追記ですいません。

OnSelchangeItem()内で

変数nにGetCurSel()で取得したindexを返し、その後、
GetLBTextで、文字列を取得するところまで出来ています。
これらで取得した値を、どやってコンボボックス2へ
連動させるのか、というところです。

PATIO 2006/10/02(月) 15:31:47
連動って何をしたいんですか?
簡単に連動と書いていますが、具体的な話が全く書かれていませんよ。

コンボボックス1の選択によってコンボボックス2のリストの内容を変更したいのか、
コンボボックス2の選択状態を変更したいのか、いったい何がしたいんでしょう?

同じダイアログ内のコントロールであれば、普通にコンボボックスに処理を行うのと
大差ないはずです。
連動させたいのであれば、連動に必要な情報等はダイアログボックス内に保持しておかないと
条件を判断したり、コンボボックスの状態を変更できないと思います。
コンボボックス設定したデータだけを頼りに何かしようとしても無理なのでは?
内容によってはできるかもしれませんけれど。

PATIO 2006/10/02(月) 15:33:16
訂正:
コンボボックス設定したデータだけを頼りに何かしようとしても無理なのでは?
                  ↓
コンボボックスに設定したデータだけを頼りに何かしようとしても無理なのでは?

Blue 2006/10/02(月) 15:35:36
コンボボックスのCBN_SELCHANGEをハンドルして、
その中で、変更があったコンボボックスのアイテムのインデックスを取得し、
変更がなかったコンボボックスに対して、SetCurSelで設定する。
(をコンボボックスの数分記述。下の例では3つ書く)

void CComboTestDlg::OnSelchangeCombo1() 
{
    // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
    CComboBox* pCombo1 = ( CComboBox* )this->GetDlgItem( IDC_COMBO1 );
    CComboBox* pCombo2 = ( CComboBox* )this->GetDlgItem( IDC_COMBO2 );
    CComboBox* pCombo3 = ( CComboBox* )this->GetDlgItem( IDC_COMBO3 );

    const int selectNo = pCombo1->GetCurSel();
    pCombo2->SetCurSel( selectNo );
    pCombo3->SetCurSel( selectNo );
}

ってことではない?

PATIO 2006/10/02(月) 16:19:59
単におんなじインデックスで他のコンボボックスも選択したいという話なのだとすると
なんでそこで悩んでいるのかが良く分からないですね。
何処がどう分からないのか説明できないとどう説明してよいのかも良く分からないし。

単純に既にやっている範囲の情報+SetCurSel程度で何とかなりそうな話だし。
蛇足ですけれど、学生さん向けのパッケージで.net2003を買うと2005Proを
無料でダウンロードできると言うのがあるみたいですけれど、
これって電子ドキュメントが付いていないそうですね。
何時だったかHELPで調べてくださいと書いたらHELPが付いてないと言われました。
まあ、オンライン環境ならMSDNを見に行けばいいわけですけれど、
スタンドアロン環境だったりするとこれも駄目な訳で。
本を買うしかないですねという話をしたんですが、
MSも学生さんを育成したいのなら電子ドキュメントまで付ければ良いのにと
思っていたり。まあ、オンラインを使えって事なんでしょうけれど。

tikira 2006/10/02(月) 17:20:05
説明が不十分ですいませんでしたm(__)m

>コンボボックス1の選択によってコンボボックス2のリストの内容を変更したいのか、
>コンボボックス2の選択状態を変更したいのか、いったい何がしたいんでしょう?

コンボボックス1の選択によって、コンボボックス2のリストの内容を
変更する処理です。

さやぴ 2006/10/02(月) 17:27:34
コンボ2に対して、AddString関数やInsertString関数で
追加するだけではないのでしょうか?

Blue 2006/10/02(月) 17:30:31
変更する内容がどこかにあるのであれば、OnSelchangeCombo1でGetCurSelの値によって
切り分ければいいのでは?

void CComboTestDlg::OnSelchangeCombo1() 
{
    // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
    CComboBox* pCombo1 = ( CComboBox* )this->GetDlgItem( IDC_COMBO1 );
    CComboBox* pCombo2 = ( CComboBox* )this->GetDlgItem( IDC_COMBO2 );

    pCombo2->ResetContent();
    switch ( pCombo1->GetCurSel() )
    {
    case 0:
        pCombo2->AddString( _T( "あ" ) );
        pCombo2->AddString( _T( "い" ) );
        pCombo2->AddString( _T( "う" ) );
        break;
    case 1:
        pCombo2->AddString( _T( "か" ) );
        pCombo2->AddString( _T( "き" ) );
        pCombo2->AddString( _T( "く" ) );
        break;
    case 2:
        pCombo2->AddString( _T( "さ" ) );
        pCombo2->AddString( _T( "し" ) );
        pCombo2->AddString( _T( "す" ) );
        break;
    case 3:
        pCombo2->AddString( _T( "た" ) );
        pCombo2->AddString( _T( "ち" ) );
        pCombo2->AddString( _T( "つ" ) );
        break;
    }
}

上の例は、カナリ気の利かないコードの例です。(ベタ書きの例)

PATIO 2006/10/03(火) 10:23:20
> コンボボックス1の選択によって、コンボボックス2のリストの内容を
> 変更する処理です。

そういう事ならコンボボックス1の選択によってコンボボックス2に設定すべき
内容をどのように管理するのかと言うところまで考えないと駄目ですね。
最悪べた書きという手もありますけれど、変更がありえるとか外のケースへの
流用できるようなロジックとかと言う観点からするときちんと管理できるような
仕組みを考えた方が良いと思います。

但し、コントロールを制御する方法については既にさやぴさんとBlueさんが
書かれている通りなので特に付け加える事はありません。
この辺の制御ならコンボボックス1で既にやっているはずなので
質問するような部分は無いと思いますけれど。

ちなみ管理方法は御自分で考えて見てください。
それこそどうにでもできる話です。

tikira 2006/10/04(水) 11:55:26
皆さん色々とありがとうございます。
連動の管理について、考えてみました。
現状、コンボボックスに表示しているアイテムは
外部CSVファイルから読み込んでいます。
CSVファイルの内容により、表示するアイテムが変わることがあっても
大丈夫なようにしたいと思います。

CSVファイルの内容の例は下記の通りです。

コンボ1のCSVファイル:

id   item
1    動物
2  野菜
3  果物
4  乗り物

コンボ2のCSVファイル:


id  key   item
1  1  ねこ
2  1  いぬ
3  2  キャベツ
4  3  みかん
5  3  ぶどう
6  4  電車

このように、コンボ1のidとコンボ2のkeyで連動するようにしたいと思います。
例えば、コンボ1で、「野菜」が選択されると、コンボ2では「キャベツ」が
表示されるようにといった感じです。

この管理方法で、連動させようとしたとき、
OnSelchangeCombo1()内で、if文で条件判断して
pCombo2->AddString()すればよいのでしょうか?


少し、最初の質問トピとずれているかもしれませんが
ご教授のほどよろしくお願いしますm(__)m

Blue 2006/10/04(水) 12:18:03
構造体を要素にもつ配列やリストを使ったりして検索するなりしてCSVファイルの情報を
うまいこと構築してください。(ADOを使うのも手だが)

というか、こういうことを考えたりするのがプログラマの重要なところだと思うのです
が。実際にどうコードに書けばいいかわからないのを聞くのであればいいけど、日本語
でこんなデータ構造にするとかそういうのも考えないのはプログラマとしては全然ダメ
ダメです。

とりあえず、日本語でこんなデータ構造にして、こうやって情報を取り出したいという
ことをまとめてみてください。


一応、リストとして使えそうなもの。
STL : vector, list, map
MFC : CArray, CList, CMap
※これらを使わなくとも、構造体の配列や自己参照構造体を使っても出来る。

さやぴ 2006/10/04(水) 13:39:22
>コンボ1のCSVファイル:
>id   item
>1    動物
>2  野菜
>3  果物
>4  乗り物
>
>コンボ2のCSVファイル:
>id  key   item
>1  1  ねこ
>2  1  いぬ
>3  2  キャベツ
>4  3  みかん
>5  3  ぶどう
>6  4  電車
>
>このように、コンボ1のidとコンボ2のkeyで連動するようにしたいと思います。
>例えば、コンボ1で、「野菜」が選択されると、コンボ2では「キャベツ」が
>表示されるようにといった感じです。

コンボ1で[動物]が選択された時、コンボ2は、[ねこ][いぬ]の複数を表示
させたいということでしょうか?

tikira 2006/10/04(水) 13:44:41
度々、追記と質問です。
今は、CSVから拾ってきてコンボに表示するアイテムは
CString型のDataItem[]という配列に入れて作っています。

今の、コンボ1に対してのコードを記述してみます。

if(fp.Open("item1.csv",CFile::modeRead)==NULL){
    AfxMessageBox("File Open failed");
    return;
    }    
CComboBox* pcmb = (CComboBox*)this->GetDlgItem(IDC_PROJECT);
    while(fp.ReadString(name)){ 
     //コンマを分解
     fn = fm = id = 0;
     name.Replace("\"", ""); // ""をreplace
     len = name.GetLength(); // 一行の文字列長を取得
     for (ix = 0; ix < len; ix++)
     { 
        if (name[ix] == (CString)",")
        { // コンマが見つかった場合
            fm = ix - 1;  // コンマ直前のIndexを取得
            if (fn < fm)  
              DataItem[id] = name.Mid(fn, fm - fn + 1);
            else  // 文字列が空の場合
              DataItem[id] = "";
               fn = ix + 1;  // 次の文字列の開始位置を設定
               id++;  // 配列格納位置をインクリメント
              if (id > 2) // 3つ分の分解が終わったら終了
              break;
        }
     }
        if (fn < (len - 1))
            DataItem[2] = name.Mid(fn, len - fn);
        //AddStringでコンボボックスに2番目のアイテムを追加
        pcmb->AddString((LPCTSTR)DataItem[1]);
    }
    fp.Close();

これらの要領で、コンボ2とコンボ3・・・のアイテムも
取得して表示しています。
このDataItem[]の配列を使ってどうやって
コード上、連動していったらいいのでしょうか?

tikira 2006/10/04(水) 13:47:40
>さやびさん

>コンボ1で[動物]が選択された時、コンボ2は、[ねこ][いぬ]の複数を表示
>させたいということでしょうか?

そうです。
一つとは決まっていないので。。

たいちう 2006/10/05(木) 08:58:46
コンボ2で[ねこ]を選んだら、コンボ3に[みけ][たま]とかを表示する仕様かな?

struct combo2Item {
    int id;
    int key;
    CString name;
};

こんなのを作って、CPtrArrayに放り込んでおいて、
コンボ1のOnSelchangeで、全ての要素のkeyを比較して、
1つずつコンボ2にセットするかどうかを決めるのが簡単かと。

まずコンボ3は忘れて、ここまで作ってはどうでしょう。

PATIO 2006/10/05(木) 09:09:48
表示と書いてしまうからおかしくなる訳でリストに追加と書くべきですね。
CSV上のデータをそのまま展開するだけでも可能だとは思いますけれど、
もう一歩踏み込んで自分が実現したいデータ構造をクラス化すると言うのも
一つの考え方でしょう。
単純に構造体を使って構築するもよしですし。
Blueさんも書かれている通り、この部分をどう構築するかがプログラマの腕の見せ所です。
うまく料理すれば、汎用的なデータ構造を作成できるかもしれません。
まあ、習作であればそこまで突き詰めずにまずは動作させる事を目標に考えても
良いかも知れませんけれど。

一ついえる事は、CString型のDataItem[]という配列だけで済ませようとしても駄目です。
これだけではコンボボックス1とコンボボックス2の関連を保持する事が出来ません。
せっかくCSVの形式まで考えたんですからもう一歩か二歩進めて見てはどうですか?
あと、CString型のDataItem[]という配列がダイアログのメンバー変数なら変数名の
最初にm_とかつけてm_DataItem[]とかにした方が後でソースを見たときにわかりやすいです。
ローカル変数ならその関数から抜けてしまうと開放されてしまうので注意が必要です。
まあ、どうせならCArrayなりCListなりを使うとかして可変長配列にした方が良いと
思いますけどね。

とにかく、まずは自分で仕組みまで含めて頭をひねってみてください。
こういうロジックは人から聞いて実装しても身につかないです。

PATIO 2006/10/05(木) 09:13:04
もとい、
CListは可変長リストですね。
可変長配列と言えるのはCArrayの方です。
両方ともMFCのクラスなので調べるのは簡単です。
(付属のHELPで調べられます)

さやぴ 2006/10/05(木) 12:13:48
コンボ2に複数のアイテムを表示させるとの事ですが、
コンボボックスのアイテムは一つしか表示できません。
(えっ?私が知らないだけ?)

一つのアイテムを複数行で表示させるのは、オーナードローで出来ますが・・・。

2006/10/05(木) 13:36:54
同時に選択させるのじゃなくって
コンボのリストに入れるということでは??

PATIO 2006/10/05(木) 13:40:33
多分、私もそうだと思います。
というか、私もそう書いているし。

επιστημη 2006/10/06(金) 09:19:46
> 今の、コンボ1に対してのコードを記述してみます。

CSVから切り出すコード示されてもしゃぁねぇですよ。
"キモ"は「どんな構造でデータを持てば望みの動きが実現するか」ですから。
コンボボックスはただの"見てくれ"でしかないし。

動物 → ねこ, いぬ
野菜 → キャベツ
...

という対応表を如何にプログラムで表現するか、でしょうが。
それさえできれば:
 クリックされたのを拾う/対応表を引く/その結果をコンボに乗せる
でオシマイなんだから。

tikira 2006/10/06(金) 13:05:33
[[解決]]
皆さん、ありがとうございます。
επιστημηさんも言う通り、
もっと動作に対してのプログラムをシンプルに考えながら
やってみようと思います!

επιστημη 2006/10/06(金) 14:06:40
> 動作に対してのプログラムをシンプルに考えながら

というより「(見た目はともかく)要はなにがしたいのよ?」
と常に自問しながらコード書いてください。

大切なのは「どうすればいいか」より「なにがしたいか」です。

PATIO 2006/10/06(金) 14:26:39
実はこういう仕組みを考えるのって結構面白いんですけどね。
いかに無駄なくうまく動く仕組みを作るかって言うのは
一種のパズル的要素もあって面白いと思いますよ。

古いスレッドには追加発言できません。