04.リストコントロールに行を追加する

今回は、リストコントロールに行を追加する方法です。具体的には、スライドパズルの問題として下記の内容の input.txt を用意し、それを読み込んでリストコントロールに表示します。

3,3,138046752
3,3,584370261
3,4,2941B3750A68
3,4,923160754A8B
4,4,41EC86709BA532FD
3,4,7BA3149=2650
3,4,91B6475=032A
3,5,=B0264A=5E3D9C7
3,5,=5BD7AE=4C90362

input.txtの各行は、スライドパズルの幅,高さ,初期状態を示します。初期状態は、0が空きパネル、1〜9, A〜Zの順に数字の1〜35を表します。ただし、通常のスライドパズルと違い移動できない壁があり=で表します。
それでは始めましょう。
 
1.スライドパズルの問題を保持するSPDataクラスを定義します。幅、高さ、初期状態を保持できるようにしました。

class SPData {
public:
  SPData(int w, int h, const char *data)
  : m_Width(w), m_Height(h), m_Data(data)
  {
  }

  int GetWidth()const{return m_Width;}
  int GetHeight()const{return m_Height;}
  const std::string& GetData()const{return m_Data;}

private:
    int m_Width;
    int m_Height;
    std::string m_Data;
};

 
2.CSlidePuzzleDlg にinput.txtファイルを読み込むLoadInputFile関数と読み込んだ問題を保持するm_DataContainer変数を定義します。

// CSlidePuzzleDlg.h
class CSlidePuzzleDlg {
  std::vector<SPData> m_DataContainer;
  BOOL LoadInputFile(const wchar_t *path);
};
// CSlidePuzzleDlg.cpp
BOOL CSlidePuzzleDlg::LoadInputFile(const wchar_t *path)
{
  m_DataContainer.clear();

  ifstream fi(path);
  if(!fi.is_open()){
    return FALSE;
  }

  //input.txt の内容を読み込む
  vector<char> v(256);
  while(fi.getline(&v[0], v.size())){
    const int w = atoi(&v[0]);
    const int h = atoi(&v[2]);
    const string s(&v[4]);
    SPData spd;
    if(!spd.Initialize(w,h,s)){
      return FALSE;
    }
    m_DataContainer.push_back(spd);
  }

  return TRUE;
}

 
3.m_DataContainerの内容をリストコントロールに反映するRefreshListCtrl関数を定義します。

void CSlidePuzzleDlg::RefreshListCtrl()
{
  m_LC.SetRedraw(FALSE);
  m_LC.DeleteAllItems();
  CString s;
  int num = 0;
  for(auto it = m_DataContainer.cbegin(); it != m_DataContainer.cend(); ++it, ++num){
    s.Format(L"%d", num+1);
    const int nItem = m_LC.InsertItem(m_LC.GetItemCount(), s);

    s.Format(L"w=%d, h=%d, ", it->GetWidth(), it->GetHeight());
    
    //文字コードを変換します。※1
    {
      const string mbstr = it->GetData().c_str();
      const int size = ::MultiByteToWideChar(CP_ACP, 0, mbstr.c_str(), -1, 0, 0);
      std::vector<wchar_t> buff(size+1, 0);
      ::MultiByteToWideChar(CP_ACP, 0, mbstr.c_str(), -1, &buff[0], (int)buff.size());
      s += &buff[0];
    }

    m_LC.SetItemText(nItem, 1, s);

    m_LC.SetItemText(nItem, 2, L"");
  }
  m_LC.SetRedraw(TRUE);
}

※1 input.txtから読み込んだ文字列はマルチバイトの文字列です。MFC Feature Packは、wchar_t型のUTF-16の文字列を扱うので変換しています。
 
4.CSlidePuzzleDlgのOnInitDialog関数で、2と3で定義したメンバ関数を実行します。これでinput.txtを読み込んでからダイアログが表示されるようになります。

BOOL CSlidePuzzleDlg::OnInitDialog()
{
    // ... 省略

    //スライドパズルの問題を読み込みます。
    LoadInputFile(L"input.txt");

    //リストコントロールを更新します。
    RefreshListCtrl();

    return TRUE;
}

 
5.アプリを実行して動作を確認します。
下図のダイアログが表示されたら成功です。