Grid上でEditしたい

  

  

サブメニュー


ここに紹介するプログラムは、WIN XP 2003/Windows 7 (32bits) - OS 環境でマイクロソフトのVisual Studio 2010 で作ったものです。

Windows XP/ Windows 7(32bits) での動作は確認済みですが…

 

ExcelのようなGridControlでデータの入力は出来ましたが、やはりGrid上で編集できれば?


製作当初より、この機能をプログラムしたかったのですが、方法がよくわからず…

メーリングリストなどを参考にやっとこの機能が出来たようです。 スピードや細かい点で、まだまだですが少しは編集がしやすくなったはずです。

 

基本的なプログラミングは、プログラムのなかで着目しているGridの位置と大きさを取得し、標準EditBoxを移動するだけです。

EditBoxの大きさを調整し移動は、CWin::MoveWidow( )という関数を使いました。 頭をひねったのは、Gridの大きさと位置をどの様に取るかでした。

 

この機能でもっとも重要な働きをする関数(EditBoxRedraw())

 

MsFlexGridを貼り付けているダイアログクラスに、Private関数を作りました。

この関数は、選択されているGridの位置を取得し、セルの位置と大きさを取得して標準のEditBoxをその位置に移動。 

もしセルに既存データがある場合これをEditBoxにコピーし編集できる機能を持たせました。

 

///////////////////////////////////////////////
// 編集用 EditBox に表示(自動スクロールなし)
void CWallDlg::EditBoxRedraw(CMSFlexGrid* pGrid, CPoint* pPt)
{
  CDC *pDC = GetDC();
  CCheckData cd;
  CString str = _T("");
  CRect rc, rc2;

  if( pPt->x > 0 ){
    GetWindowRect( &rc ); // Dailog のスクリーン座標
    m_grid.GetWindowRect( &rc2 ); // Grid のスクリーン座標

    long xx = pDC->GetDeviceCaps( LOGPIXELSX );  // 論理インチごとのピクセル数
    long yy = pDC->GetDeviceCaps( LOGPIXELSY );
    long top = pGrid->GetRowPos( pPt->y ) * yy/1440;
    long left = pGrid->GetColPos( pPt->x ) * xx/1440;
    long width = pGrid->GetColWidth( pPt->x ) * xx/1440;
    long height = pGrid->GetRowHeight( pPt->y ) * yy/1440;
     int nTitleHeight = GetSystemMetrics( SM_CYCAPTION ); //タイトルの高さを自動判別する

     long d_top = rc2.top - rc.top - nTitleHeight;
    long d_left = rc2.left - rc.left;


    str = grid->GetTextMatrix( pPt->y, pPt->x ); //既存のデータ取得
    m_ctrWallDataInput.SetWindowText( str );
    m_ctrWallDataInput.SetSel( 0, -1, FALSE ); //全選択で編集できるようにする
    m_ctrWallDataInput.MoveWindow( left+d_left, top+d_top, width-1, height-1, TRUE );
  }
}

 

選択されているセルの位置を取得するのは、MsFlexGrid関数のGetRowPos( )とGetColPos( )メソッドを使います。

GetRowCel( )とGetColCel( )メソッドでも可能ですが、 Gridの最下行より2行以下を選択するとGridが自動的にスクロールされ、矢印キーなどで最下行が選択できません。(色々とテストしてこれを選定しました)

 

MsFlexGridは、VisualBasicをターゲットとして作られたActiveXコントロールですので、 位置などを取得する値はTwips単位で返します、VisualC++は基本的にピクセル単位ですのでこれを換算する必要があります。

 

この換算には、pDC->GetDeviceCaps( LOGPIXELSX );とpDC->GetDeviceCaps( LOGPIXELSY );関数を使います。1インチは1,440 twip単位ですので、

でピクセル単位の座標が得られます。

 

Gridは、ダイアログに貼りついていますので、所定のGridセルの位置をダイアログの左上を基点とした座標で取得する必要があります。

GetWindowRect( &rc ); // Dailog のスクリーン座標
m_grid.GetWindowRect( &rc2 ); // Grid のスクリーン座標

 

この関数で得られた座標の差を取れば、ダイアログの左上からの相対座標が得られます。

しかし、ダイアログのトップにはタイトルがあるため、それを差し引く必要があります。

 

タイトルの高さを自動判別する関数が  int nTitleHeight = GetSystemMetrics( SM_CYCAPTION ); です。

AutoAC version 3.5 で修正しました、これでWindowXPでも正常に動作できるようになりました。

 long d_top = rc2.top - rc.top - nTitleHeight;
long d_left = rc2.left - rc.left;

着目しているグリッドの幅と高さは、

 long width = pGrid->GetColWidth( pPt->x ) * xx/1440;
long height = pGrid->GetRowHeight( pPt->y ) * yy/1440; で得られますが、グリッドの線幅を差し引く必要があります。

 

ここで忘れがちなのは、Windowの貼り付け順番を必ずEditBoxがGridの手前とする必要があります。

リソースエディタで、ダイアログを作るとき、必ずタブセットを行いEditBoxがGridより若い番号としてください。

これを行わなかったため、動作がおかしくなり、3日3晩苦しみました。

 

マウスのクリックイベントが発生した場合

GetMouseRow( )GetMouseCol( )関数でマウスが指している行と列を取得します。

取得した行と列が指定範囲内のとき、SetCurrentCel( )関数を使いGridの着目セルを、マウスでクリックした位置に移動する。

EditBoxRedraw()関数で、着目セルの位置にEditBoxを移動する。

着目セルに既存データがある場合、全選択状態でEditBoxにコピーする。フォーカスをEditBoxに移す。

 

矢印キーでの着目セルの移動

PreTranslateMessage(MSG* pMsg)関数をオーバーライドしここに各矢印キーが押されたときの関数をコーディングする。

右矢印キーが押されたとき    MoveCurRight()関数が呼ばれる

左矢印キーが押されたとき    MoveCurLeft()関数が呼ばれる

下向き矢印キーが押されたとき  MoveCurDown()関数が呼ばれる

上向き矢印キーが押されたとき  MoveCurUp()関数が呼ばれる

 

MoveCurRight関数

矢印キーが押されたとき、指定行や列の範囲内のときは、着目列を右に1つずらし、SetCurrentCel関数で設定する。EditBoxRedraw関数でEditBoxも移動する。

void CAlloadDlg::MoveCurRight()

{

              CGridControl gc;

              long row = m_rc.y;

              long col = m_rc.x;

 

              if( col>2 && col<7 ) {

                            col++; // 着目列を右に1つずらす

                            m_rc = gc.SetCurrentCel( m_grid, m_nMaxRow, row, col );

                            EditBoxRedraw(&m_grid, &m_rc);

              }

}

 

同様にMoveCurLeft・MoveCurDownMoveCurUp関数を作成する。

///////////////////////////////////////////////

// 左矢印キー

void CAlloadDlg::MoveCurLeft()

{

              CGridControl gc;

              long row = m_rc.y;

              long col = m_rc.x;

 

              if( col>3 && col<=7 ) {

                            col--;// 着目列を左に1つずらす

                            m_rc = gc.SetCurrentCel( m_grid, m_nMaxRow, row, col );

                            EditBoxRedraw(&m_grid, &m_rc);

              }

}

 

///////////////////////////////////////////////

// 下矢印キー

void CAlloadDlg::MoveCurDown()

{

              CGridControl gc;

              long row   = m_rc.y;

              long col   = m_rc.x;

              int nLine  = m_nData;

 

              if( row>0 && row<nLine ) {

                            row++;// 着目列を下に1つずらす

 

                            if( row > ( m_nTopRow + m_nInitia_maxrow - 3 )) {

                                          m_nTopRow++;

                                          m_grid.SetTopRow( m_nTopRow );

                            }

                            m_rc = gc.SetCurrentCel( m_grid, m_nMaxRow, row, col );

                            EditBoxRedraw(&m_grid, &m_rc);

              }

}

 

///////////////////////////////////////////////

// 上矢印キー

void CAlloadDlg::MoveCurUp()

{

              CGridControl gc;

              long row  = m_rc.y;

              long col  = m_rc.x;

              int nLine = m_nData;

 

              if( row>1 && row <= nLine ) {

                            row--;// 着目列を上に1つずらす

 

                            if(( m_nMaxRow - ( m_nInitia_maxrow - 2 )) > row) {

                                          m_nTopRow = m_grid.GetTopRow();

                                          if( m_nTopRow > 1) m_nTopRow--;

                                          m_grid.SetTopRow( m_nTopRow );

                            }

                            m_rc = gc.SetCurrentCel( &m_grid, m_nMaxRow, row, col );    

                            EditBoxRedraw(&m_grid, &m_rc);

              }

}

 

これで、セルを自由に移動出来るようになりました。次は、データを入力する部分です。

フォーカスは、常にEditBoxにありスタンバイ状態になっています。従ってキーボードからデータが入力されると、EN_UPDATEメッセージが発生します。

 

そこで、このメッセージに対応した仮想関数のOnUpDateをオーバーライドしてここにコーディングしておけばよい事がわかります。

入力データは、正しいデータかどうか判断したり、予め決められたデータとの照合をしたりする必要があります。 更に空白データが含まれていないかもチェックする必要があります。

 

正しくないデータや空白が含まれていると、あとの計算部分で予期しないエラーが発生する可能性があります。

データのメモリーに一時保存する方法なども決めておかなければなりません。 これらを考慮してプログラムするのが最も頭を痛めた部分です。

 

各行のデータが正しく全て入力されていることを判断して一時メモリーのArrayに追加するようにしました。

編集の時、Arrayの途中のデータに空白や不正データが入り込まないようなチェックが必要です。

次のページへ


ページ先頭に戻る
最終更新日: 2020/02/04