antenn-a
company profile

MFC航海日記 三十四日(CListCtrlでアイテムのスワップ)

#
# 作者のぼやき
#
# はっきり言って私は文章を書くのが嫌いです(きっぱり)
# 会員さんがドキュメントが欲しいというから始めた本コーナーも
# 30話を突破してしまった。。。
# 密度はともかくとして、なかなか続いているではないですか (^^;;
# それなのに!それだというのに!!
# 激励のメールが2通しか来ないのはどういう訳だぁ!!!(ガオォォォォ)
# 別にいいけどさ・・・フン・・・
# 誰もかまってくれねえさ・・・ヘン・・・
# かわいそうな俺・・・グス・・・
#
# 激励のメール待ってますm(_ _)m

prev


前回アイテムの削除をしたので、今回はソートでもしようかとおもったのだが、それは止めて(?)スワップに挑戦してみた。

皆さんはスワップをご存知だろうか?(知っている人にしてみれば非常に失礼な言い回しだが) スワップとは、data1とdata2があった時そのデータを交換する事を言います。

つまり、リストコントロール内のデータを交換してみようという試みである。

prev


CListBox 等では、DeleteItem(), InsertItem()なる関数が存在したため、何も考えずにスワップできたのだが CListCtrl で同じ事をやろうとすると、データの再代入が起こってしまい非常に見栄えが悪いのである。

スワップしようと思ったとたんにすべてのデータを再描画するので時間がかかってしまう。 これを一瞬の内に行おうというのが今回のねらいである。

prev


以下にスワップルーチンのソースコードを示す。
void CRenameDlg::SwapSetItem( LV_ITEM* item_src, LV_ITEM* item_dst, short dt )
{
    //データのスワップ
    item_src->iItem += dt;
    item_dst->iItem -= dt;
    
    //データのセット
    m_ListCtrl.SetItem( item_src );
    m_ListCtrl.SetItem( item_dst );
    
    //データの初期化
    item_src->iItem -= dt;
    item_dst->iItem += dt;
}

void foo::SwapSelectedItem( short dt )
{
    LV_ITEM     item_src;
    CString     item1_src;
    CString     item2_src;
    CString     item3_src;
    
    LV_ITEM     item_dst;
    CString     item1_dst;
    CString     item2_dst;
    CString     item3_dst;
    
    int         nIdx;

    memset( &item_src, 0, sizeof( item_src ) );
    item_src.pszText = item1_src.GetBuffer( 512 );
    item_src.cchTextMax = 512;
    item_src.mask = LVIF_STATE | LVIF_TEXT;
    item_src.stateMask = LVIS_SELECTED;
    for( nIdx = m_ListCtrl.GetItemCount() - 1; nIdx >= 0; nIdx-- ){
        item_src.iItem = nIdx;
        m_ListCtrl.GetItem( &item_src );
        if( item_src.state == LVIS_SELECTED ){
            item1_src.ReleaseBuffer();
            item_dst = item_src;
            item_dst.iItem = nIdx + dt;

            //変更先のアイテム1を取得
            item_dst.pszText = item1_dst.GetBuffer( 512 );
            m_ListCtrl.GetItem( &item_dst );
            item1_dst.ReleaseBuffer();
            SwapSetItem( &item_src, &item_dst, dt );

            //変更もとのアイテム2を取得
            item_src.pszText = item2_src.GetBuffer( 1024 );
            item_src.iSubItem = 1;
            m_ListCtrl.GetItem( &item_src );
            item2_src.ReleaseBuffer();
            
            //変更先のアイテム2を取得
            item_dst.pszText = item2_dst.GetBuffer( 1024 );
            item_dst.iSubItem = 1;
            m_ListCtrl.GetItem( &item_dst );
            item2_dst.ReleaseBuffer();
            SwapSetItem( &item_src, &item_dst, dt );

            //変更もとのアイテム3を取得
            item_src.pszText = item3_src.GetBuffer( 20 );
            item_src.iSubItem = 2;
            m_ListCtrl.GetItem( &item_src );
            item3_src.ReleaseBuffer();
            
            //変更先のアイテム3を取得
            item_dst.pszText = item3_dst.GetBuffer( 20 );
            item_dst.iSubItem = 2;
            m_ListCtrl.GetItem( &item_dst );
            item3_dst.ReleaseBuffer();
            SwapSetItem( &item_src, &item_dst, dt );
            //
            m_ListCtrl.SetItemState( nIdx, 0, LVIS_FOCUSED );
            m_ListCtrl.PostMessage( WM_SETFOCUS, 0, 0 );
            break;
        }
    }
}

void foo::OnUpitem()
{
    SwapSelectedItem( -1 );
    CheckItemSelected();
}
void foo::OnDownitem() 
{
    SwapSelectedItem( 1 );
    CheckItemSelected();
}

prev


最終的な決めて(?)としては「CListCtrl::SetItem()」だったわけであるが、非常に込み入ったソースコードになってしまった。

本来は、カラムが三つである保証が無い為 for ループ等を使うべきなのだが、そうするとサンプルとして非常に見にくくなるのであえて3つに分割してみた。

アイテムのスワップが出来たとすると、リストコントロールに並んだ任意のアイテムを入れ替える事が出来る為、見栄えも違ってくるのではなかろうか?(と考えるのは私だけか?)

次回はカラムを押してアイテムをソートするルーチンを紹介したい。(出来るかどうかは不明)



antenn-a

prev next


antenn-a