![]()
![]()
| 1,リスト | 選択データの取得 ファイル表示 |
| 2,コンボボックス | |
| 3,スクロールバー | よりスクロールバーらしく |
リストは複数の項目を表示して、ユーザーに1つ(複数)をその中から
選択するというものです。選択した部分は色が反転しています。
前回と同じように基本クラスをCViewをCFormViewにしたアプリを作成します。
コントロールからリストボックスを選択して配置してください。
コントロールをダブルクリックするとプロパティウィンドウが現れます。
IDは「IDC_LIST1」にします。(おそらく自動でそうなっています。)
この時点でコンパイルをすると次のようになります。

ここで、マウスのダブルクリックに対応するメッセージハンドラを作成してください。
次のような関数が作成されていると思います。
| クラス | メッセージ | メンバ関数 |
| CNamaeView | 左ダブルクリック | OnLButtonDblClk |
void CNamaeView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CFormView::OnLButtonDblClk(nFlags, point);
}
ここで、ListBoxのプロパティの「ソート」のチェックをはずしておいてください。
(自動的に昇順にソートされるため)
そして、次のように書き加えてください。
void CNamaeView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CListBox* b=(CListBox*)GetDlgItem(IDC_LIST1);
b->InsertString(-1,"first word");
b->InsertString(-1,"secound words");
CFormView::OnLButtonDblClk(nFlags, point);
}
InsertString(-1,"word")というのは最後の行に「word」という語を加えるという意味です。
InsertString(0,"word")というのは最初の行に加えます。

ただ、これではダブルクリックをするたびに語句が増えていってしまいます。
そこで、初期化もかねて次のようにします。
void CNamaeView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CListBox* b=(CListBox*)GetDlgItem(IDC_LIST1);
int n,i;
n=b->GetCount();
for (i=n-1;i>=0; i--)
b->DeleteString(i);
b->InsertString(0,"first word");
b->InsertString(1,"secound words");
CFormView::OnLButtonDblClk(nFlags, point);
}
GetCount関数でリストに何項目のデータがあるかが得られます。
DeleteString(i)でi行目のデータを削除できます。
削除は後ろからやります。前の方を先に削除すると2行目がデータがなくて
3行目はあるといったようにデータが連続でなくなってしまいます。
これは、InsertStringでデータを書き加える場合も同じです。
ユーザーが選択したデータは取得する必要があります。
そこで、クラスウィザードを使ってリストボックスが変化したときに呼び出される
OnDblclkList1というメッセージハンドラを作成してください。
そして次のようにコードを加えます。
| クラス | メッセージ | メンバ関数 |
| CNamaeView | Window上で左ダブルクリック | OnLButtonDblClk |
| CNamaeView | IDC_LIST1ボックス内でダブルクリック | OnDblclkList1 |
void CNamaeView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CListBox* b=(CListBox*)GetDlgItem(IDC_LIST1);
int n,i;
n=b->GetCount();
for (i=n-1;i>=0; i--)
b->DeleteString(i);
b->InsertString(0,"first word");
b->InsertString(1,"secound words");
CFormView::OnLButtonDblClk(nFlags, point);
}
void CNamaeView::OnDblclkList1()
{
CListBox* b=(CListBox*)GetDlgItem(IDC_LIST1);
CDC* pDC=GetDC();
char buf[50];
b->GetText(b->GetCurSel(),buf);
pDC->TextOut(0,200,buf);
ReleaseDC(pDC);
}
OnLButtonDblClk関数は変更はしていません。新たなメッセージハンドラとして
OnDblclkList1関数を以上のようにします。
GetCurSel関数は何行目が選択されたかという数字を返します。
GetText関数は指定された行に対応する文字データを変数に代入します。
実行すると以下のようになります。

ファイルの表示は以外と簡単にできます。
| クラス | メッセージ | メンバ関数 |
| CNamaeView | Window上で左ダブルクリック | OnLButtonDblClk |
| CNamaeView | IDC_LIST1ボックス内でダブルクリック | OnDblclkList1 |
void CNamaeView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CListBox* b=(CListBox*)GetDlgItem(IDC_LIST1);
int n,i;
n=b->GetCount();
for (i=n-1;i>=0; i--)
b->DeleteString(i);
b->Dir(DDL_READWRITE,"a:\\windows\\*.*");
CFormView::OnLButtonDblClk(nFlags, point);
}
void CNamaeView::OnDblclkList1()
{
CListBox* b=(CListBox*)GetDlgItem(IDC_LIST1);
CDC* pDC=GetDC();
char buf[50];
b->GetText(b->GetCurSel(),buf);
pDC->TextOut(0,200,buf);
ReleaseDC(pDC);
}
先ほどのコードのOnLButtonDblClk関数を修正してDir関数を使っただけです。
Dir関数のDDL_READWRITEは読み書き可能ファイルを表示するというものです。
ソートプロパティをOnにしておくと昇順になります。
また、スクロールバーもOnにすることによって自動的に登場します。

コンボボックスは、リストボックスとほぼ同じです。従って、
CListBox* b=(CListBox*)GetDlgItem(IDC_LIST1);
を
CComboBox* b=(CComboBox*)GetDlgItem(IDC_COMBO1);
に変更することによって対応できます。
ただし、GetText関数は、GetLBTextに変更する必要があります。
また、コンボボックスにはユーザー自身がデータの入力が行える「ドロップダウン」というタイプと、
データー入力が行えない「ドロップダウンリスト」という2種類があります。
「ドロップダウン」の場合、エディターとリストがセットになっているものと考えます。
従ってメンバ関数を定義すれはエディターのようにデータの取得、表示ができます。
これは、もうおなじみのスクロールバーのことです。
エディターでもリストボックスでも少し紹介しました。
まず前回と同じように基本クラスをCViewをCFormViewにしたアプリを作成します。
コントロールから以下のように配置してください。

文字がありますが、これは「スタティックテキスト」というもので「赤」「緑」「青」
を配置しています。このIDは自動ですべて「IDC_STATIC」になります。
スクロールバーのIDは上から「IDC_SCROLLBAR1」「IDC_SCROLLBAR2」「IDC_SCROLLBAR3」
になっています。
つぎに、クラスウィザードでメッセージ「WM_SHOWWINDOW」に対応するOnShowWindow関数
をつくります。
さらに、スクロールされた場合に呼び出される関数をつくるのですが個々にメッセージは
発行されません。まとめて処理するのです。
水平方向が「WM_VSCROLL」、垂直方向が「WM_HSCROLL」というメッセージです。
ここでは水平方向のメッセージハンドラOnHScrollをつくります。
| クラス | メッセージ | メンバ関数 |
| CNamaeView | Windowが現れた | OnShowWindow |
| CNamaeView | 水平方向のスクロールがあった | OnHScroll |
void CNamaeView::OnShowWindow(BOOL bShow, UINT nStatus)
{
CFormView::OnShowWindow(bShow, nStatus);
int id[3]={IDC_SCROLLBAR1,IDC_SCROLLBAR2,IDC_SCROLLBAR3};
CScrollBar* s;
for(int i=0;i<3;i++){
s=(CScrollBar*)GetDlgItem(id[i]);
s->SetScrollRange(0,255);
s->SetScrollPos(0);
}
}
void CNamaeView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
static int t,r=0,g=0,b=0;
t=pScrollBar->GetScrollPos();
if (nSBCode==SB_LINELEFT && t>=10) t=t-10;
if (nSBCode==SB_LINERIGHT && t<=245)t=t+10;
pScrollBar->SetScrollPos(t);
if (pScrollBar==GetDlgItem(IDC_SCROLLBAR1)) r=t;
if (pScrollBar==GetDlgItem(IDC_SCROLLBAR2)) g=t;
if (pScrollBar==GetDlgItem(IDC_SCROLLBAR3)) b=t;
CDC* pDC=GetDC();
CBrush brush(RGB(r,g,b));
CBrush* oldbrush=pDC->SelectObject(&brush);
pDC->Rectangle(10,10,80,200);
pDC->SelectObject(oldbrush);
ReleaseDC(pDC);
CFormView::OnHScroll(nSBCode, nPos, pScrollBar);
}
OnShowWindow関数には、それぞれの最小,最大値を設定と初期位置を決めています。
OnHScroll関数でスクロールバーの位置を移動し、r,g,b変数に代入し描画しています。
ただ、これだけでは、矢印の部分を押したときしか動きません。
ここで、注目すべきはnSBCodeです。
| nSBCode | 何が起きたか |
| 0 | 左の矢印ボタン |
| 1 | 右の矢印ボタン |
| 2 | 左側のつまみと矢印ボタン間 |
| 3 | 右側のつまみと矢印ボタン間 |
| 4 | スクロールつまみがドラックされて離された |
| 5 | スクロールつまみがドラック中 |
また、nPosは現在のつまみの位置です。
これらを使ってOnHScroll関数を以下のようにするとスクロールバーらしくなります。
void CNamaeView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
static int t,r=0,g=0,b=0;
t=pScrollBar->GetScrollPos();
if (nSBCode==0 && t>=10)t=t-10;
if (nSBCode==1 && t<=245)t=t+10;
if (nSBCode==2 && t>=10)t=t-30;
if (nSBCode==3 && t<=245)t=t+30;
if (nSBCode==4)t=nPos;
if (nSBCode>=0 && nSBCode<5)pScrollBar->SetScrollPos(t);
if (pScrollBar==GetDlgItem(IDC_SCROLLBAR1)) r=t;
if (pScrollBar==GetDlgItem(IDC_SCROLLBAR2)) g=t;
if (pScrollBar==GetDlgItem(IDC_SCROLLBAR3)) b=t;
CDC* pDC=GetDC();
CBrush brush(RGB(r,g,b));
CBrush* oldbrush=pDC->SelectObject(&brush);
pDC->Rectangle(10,10,80,200);
pDC->SelectObject(oldbrush);
ReleaseDC(pDC);
CFormView::OnHScroll(nSBCode, nPos, pScrollBar);
}
C++のPageに戻る