月間予定表からの左クリックでの日付のとり方

[戻る]
こまったちゃん 2006/10/03(火) 16:51:06
■動作環境         :WindowsXP
■開発環境         :Visual C++6.0(ダイアログベース)
■データベース          :Access2000(ADO接続)

左クリックで再レスです。

ダイアログに月間予定表を貼り付けて日付をとって、それを元にして
Accessのデータを表示させるプログラムを作っています。

カレンダーのクリックした日を取りたいのですが
カレンダーにカーソルがあたっていないと取ってくれません。
(私は日にちをクリックした時点でカーソルはカレンダーにあたっていると
思っていました)
フォーカスがあたっている時は日付を取ってくれていますが、これもクリック
してとゆうよりも選択されていたら取得してるようです。

1.クリックした日をとる場合はどうすればいいか教えてください。

2.OKボタン以外はEnterを使えないようにしているのですが
 日にちを選択してEnterを押下しますと画面が消えてしまいます。
 カレンダー自体はEnterを押下しても消えないので、カレンダー
 の中の日付を制御する方法を教えてください。

3.プログラムの書き方で修正したほうがいい箇所がありましたら、
 教えてください。(独学ですので普通はこのようにやるのかとゆう不安と
 無駄な処理が多そうな気がする為)

よろしくお願い致します。

 2006年10月
日 月 火 水 木 金 土
24 25 26 27 28 29 30
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31  1  2  3  4


<以下プログラム>
BOOL CZzzDlg::PreTranslateMessage(MSG* pMsg)
{
 CString Year;
 CString Month;
 CString Day;

 // IDC_BUTTON1 以外はEnter無効
 if(GetFocus() != GetDlgItem(IDC_BUTTON1)){
  if(pMsg->wParam == VK_RETURN) {      // エンターキー
   return FALSE;
  }
  else if(pMsg->wParam == VK_ESCAPE) { //エスケープキー
   return FALSE;
  }
 }
 // フォーカスがカレンダーの時
 if(GetFocus() == GetDlgItem(IDC_MONTHCALENDAR2)){
    //左クリックしたら
  if(pMsg->wParam == VK_LBUTTON){ 
   // 月間予定表 コントロールの機能
   CMonthCalCtrl* pMonthSel;
                    
   // 月間予定表のコントロールのウィンドウハンドルを取得
   pMonthSel = (CMonthCalCtrl *)GetDlgItem(IDC_MONTHCALENDAR2);

   // 現在選択されている日付情報を取得
   SYSTEMTIME st;
   pMonthSel->GetCurSel(&st);

   // %04d, %02d 0が指定されていると、数値の前に余白があるときは、
   // 0が詰めて表示されます(省略した場合は空白が詰められます)。
   // SYSTEMTIME型 〜 CString型 + 結合
   Date.Format( "%04d/%02d/%02d", st.wYear, st.wMonth, st.wDay );

    // 日付を表示
    AfxMessageBox(Date);
  }
 }
 return CDialog::PreTranslateMessage(pMsg);
}

Blue 2006/10/03(火) 16:55:32
1.

とりあえず、MCN_SELCHANGEをハンドルして取得すればいいような気がするんだけど。

void CXXXXXDlg::OnSelchangeMonthcalendar1(NMHDR* pNMHDR, LRESULT* pResult) 
{
    // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
    NMSELCHANGE* pNMSC = ( NMSELCHANGE* )pNMHDR;
    CTime t( pNMSC->stSelStart );
    TRACE1( _T( "%s\n" ), t.Format( _T( "%Y/%m/%d" ) ) ); // ※
    *pResult = 0;
}

※AfxMessageBoxだと、無限ループしちゃうようです。(VC6)
確認用としてTRACEを使っています。[!]での実行ではなく、F5実行で、デバッグウィン
ドウで確認してみてください。
(上部のボタンやリスト等で月を変更するとMCN_SELCHANGEイベントが2度発生するっぽ)

こまったちゃん 2006/10/04(水) 10:32:57
Blueさんありがとうございます。
MFCをよく分かっていないのでいつも勉強になります。
プログラムも最初に比べたらずいぶんすっきりしました。

ほとんど真似になってしまいましたが、自分で調べてコメントをつけてみました。
間違っていたら指摘して下さい。

void CAbcDlg::OnSelchangeMonthcalendar1(NMHDR* pNMHDR, LRESULT* pResult) 
{
 // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください

 // NMSELCHANGE に NMHDR* pNMHDR の先頭アドレスをセット
 NMSELCHANGE* pNMSC = ( NMSELCHANGE* )pNMHDR;

 // CTime t() は CTime::GetTime の事 
 // stSelStartはユーザーの選択の範囲で最初の日のための日付を含んでいる
 //SYSTEMTIMEの構造(月間予定表で選択した日付)。
 CTime t( pNMSC->stSelStart );

 // CString型に日時を代入
 CString Date = t.Format( "%Y/%m/%d");

 *pResult = 0;
}

>2.OKボタン以外はEnterを使えないようにしているのですが
> 日にちを選択してEnterを押下しますと画面が消えてしまいます。
> カレンダー自体はEnterを押下しても消えないので、カレンダー
> の中の日付を制御する方法を教えてください。

に関しては引き続き調査をしています。

Blue 2006/10/04(水) 10:52:40
2.はおそらく、CMonthCalCtrlをクリックしてもフォーカスが移動しないからでしょう。
MCN_SELCHANGEイベントで強制的にフォーカスを移してあげれば出来るかも。

this->GetDlgItem( IDC_MONTHCALENDAR1 )->SetFocus();

PATIO 2006/10/04(水) 10:59:44
ちょっと気になったので一言。

// CTime t() は CTime::GetTime の事
と言うのはちょっと理解が違うような気がします。
この場合、CTime::CTime( const SYSTEMTIME& sysTime, int nDST = -1 );と言う
引数付きのコンストラクタを呼んでいます。
コンストラクタが分からない場合は、C++言語の入門書で確認してください。

subaru 2006/10/04(水) 11:20:02
9999年12月31日まで正常に動作させるなら
CTime→COleDateTime
としましょう。

こまったちゃん 2006/10/04(水) 12:41:54
Blueさん, PATIOさん, subaruさん ありがとうございます。
みんさんのアドバイスで上手くいきそうです。

前回質問するべきだった事なんですが・・・
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200609/06090060.txt
本来は教えてもらったように
>1.どんなウィンドウメッセージか?
>2.エンターキーまたはエスケープキーか?
>3.対象コントロールか?
この順番でif文を作りたかったのですが
if( pMsg->wParam == WM_KEYDOWN ){}を使うと IDC_BUTTON1 以外の時に
Enterを押下するとダイアログの画面が閉じてしまいます。
参考になるアドバイスがありましたら、よろしくお願い致します。

// 今現在のプログラム
BOOL CDcDlg::PreTranslateMessage(MSG* pMsg) 
{
// TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出してください

 // キーボードのキーが押下された時
 //if ( pMsg->wParam == WM_KEYDOWN ){ 動かす為にコメントにしました。
  //カーソルが IDC_BUTTON1 でない時はエンターキー, エスケープキーを無効にする
 if(GetFocus() != GetDlgItem(IDC_BUTTON1)){
  if(pMsg->wParam == VK_RETURN) {      // エンターキー
   return FALSE;
  }
  else if(pMsg->wParam == VK_ESCAPE) { //エスケープキー
   return FALSE;
  }
 }
 //}
    return CDialog::PreTranslateMessage(pMsg);
}

Blue 2006/10/04(水) 12:58:50
> if( pMsg->wParam == WM_KEYDOWN ){}を使うと IDC_BUTTON1 以外の時に
> Enterを押下するとダイアログの画面が閉じてしまいます。
何でだろ。下のようにしてもダメでしょうか?

BOOL CXXXXDlg::PreTranslateMessage(MSG* pMsg) 
{
    // TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出してくだ
さい
    if ( pMsg->message == WM_KEYDOWN )
    {
        if ( ( pMsg->wParam == VK_RETURN ) ||
             ( pMsg->wParam == VK_ESCAPE ) )
        {
            CWnd* pWnd = this->GetFocus(); 
            if (  pWnd && ( pWnd->GetDlgCtrlID() != IDC_BUTTON1 ) )
            {
                return FALSE;
            }
        }
    }
    return CDialog::PreTranslateMessage(pMsg);
}

Blue 2006/10/04(水) 13:01:09
>何でだろ。
って、対象が違うやんけ。

>if( pMsg->wParam == WM_KEYDOWN ){}
wParamじゃなくてmessage

って、もともとの
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200609/06090060.txt
のBlue 2006/09/25(月) 14:40:00のコードが間違っていました。 orz

すいません、Blue 2006/10/04(水) 12:58:50のように直しておいてください。

こまったちゃん 2006/10/04(水) 13:25:43
[[解決]]
みなさんありがとうございます。
少しづつですが、知識が増えていくのを感じる事が出来始めました。

今後ともよろしくお願い致します。

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