这是因为你创建工程的时候选择了UNICODE。
修改方法一:
将项目属性->配置属性->常规 中的字符集改为“未设置”。
修改方法二:
在所有常量字符串前面加一个“_T”:
txxt.Open(_T"C:\\1.txt",CFile::modeRead); 。
另外:C语言中,字符串中的“\”要用“\\” 。
先来介绍REPORT类型的CListCtrl:
首先使用下面的语句设置CListCtrl的style:
DWORD SetExtendedStyle( DWORD dwNewStyle );。
其中
LVS_EX_CHECKBOXES 表示添加CheckBox。
LVS_EX_FULLROWSELECT 表示选择整行。
LVS_EX_GRIDLINES 表示添加表格线。
如果设置了LVS_EX_CHECKBOXES属性,则可以用。
BOOL GetCheck( int nItem ) const;。
来得到某一行是否Checked。
可以先用下面的语句来删除以前的东西:
for(int k=2;k>=0;k--) //注意要从后往前删,否则出错。
m_ListCtrl.DeleteColumn(k);。
m_ListCtrl.DeleteAllItems();。
用下面的语句新建列:
m_ListCtrl.InsertColumn(0,_T('文件名'),LVCFMT_IMAGE|LVCFMT_LEFT);。
m_ListCtrl.InsertColumn(1,_T('仪器类别'));。
m_ListCtrl.InsertColumn(2,_T('项目类别'));。
其中LVCFMT_IMAGE表示可以在第一列加入图标。如果不要图标可以删去。
然后设置列宽:
for(j=0;j<3;j++)。
m_ListCtrl.SetColumnWidth(j ,100);。
以下为列表加入图标,如果不需要图标,可以跳过这一步。注意只在第一次加入,如果多次加入会出错!
先在头文件中加入声明:
CImageList m_ImageList;。
这是必要的,如果在cpp的某个函数中加入由于生命期结束,CImageList自动释放,则效果是列表中看不到图标,只看到一个白方块。
下面生成CImageList,并将其绑定到CListCtrl中,这是CImageList中还没有图标,只是一个容器:
static int flag=2;。
if(flag==2){//只调用一次SetImageList,否则出错。
m_ImageList.Create(128, 128, ILC_COLORDDB|ILC_MASK, 20, 1); 。
m_ListCtrl.SetImageList(&m_ImageList,LVSIL_SMALL);。
flag=(flag+1)%2;。
如果CListCtrl已经用过,曾经加过图标进去,这时就要删除上次放进m_ImageList中的Image。
for(int kk=0;kk<M_IMAGELIST.GETIMAGECOUNT();KK++)。
m_ImageList.Remove(k);。
下面介绍如何向CListCtrl里面加入行,并同时为每一行动态加入图标:
假设m_listRowCount为要加入的行数。
CBitmap* bitmap;。
bitmap=new CBitmap[m_list1rowCount];。
HBITMAP hbitmap; 。
for(int i = 0; i < m_listRowCount; i++)。
//为每一行插入相应的缩略图
CFile f;
CFileException e; 。
if( !f.Open(m_FileName, CFile::modeRead, &e )){ //m_FileName为bmp文件名,由你来定。
hbitmap = (HBITMAP)LoadImage(NULL,path+'blank.bmp',IMAGE_BITMAP,0,0,。
LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE);。
}else{
f.Close();
hbitmap = (HBITMAP)LoadImage(NULL,bmpFile,IMAGE_BITMAP,0,0,。
LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE);。
bitmap[i].Attach(hbitmap);。
m_ImageList.Add(&bitmap[i], RGB(0, 128, 128));。
//插入行
m_ListCtrl.InsertItem(i,m_FileName,i);。
m_ListCtrl.SetItemText(i,1,type);。
m_ListCtrl.SetItemText(i,2,m_Path);。
//记得删除已经没用的临时文件。
if(m_list1rowCount!=0)。
delete[] bitmap;。
2。如果是ICON类型的CListCtrl,则要做一点点改动:
把绑定图标集的代码由
SetImageList(&m_ImageList,LVSIL_SMALL);。
改为
SetImageList(&m_ImageList,LVSIL_NORMAL);。
插入行时只用
InsertItem(i,mainSet.m_FileName,i);。
不用
SetItemText(i,1,type);。
之类的代码。
1. ListCtrl 风格
LVS_ICON: 为每个item显示大图标。
LVS_SMALLICON: 为每个item显示小图标。
LVS_LIST: 显示一列带有小图标的item。
LVS_REPORT: 显示item详细资料。
直观的理解:windows资源管理器,“查看”标签下的“大图标,小图标,列表,详细资料”
--------------------------------------------------------------------------------。
2. 设置listctrl 风格及扩展风格。
LONG lStyle;。
lStyle = GetWindowLong(m_list.m_hWnd, GWL_STYLE);//获取当前窗口style。
lStyle &= ~LVS_TYPEMASK; //清除显示方式位。
lStyle |= LVS_REPORT; //设置style。
SetWindowLong(m_list.m_hWnd, GWL_STYLE, lStyle);//设置style。
DWORD dwStyle = m_list.GetExtendedStyle();。
dwStyle |= LVS_EX_FULLROWSELECT;//选中某行使整行高亮(只适用与report风格的listctrl)
dwStyle |= LVS_EX_GRIDLINES;//网格线(只适用与report风格的listctrl)
dwStyle |= LVS_EX_CHECKBOXES;//item前生成checkbox控件。
m_list.SetExtendedStyle(dwStyle); //设置扩展风格。
--------------------------------------------------------------------------------。
3. 插入数据
m_list.InsertColumn( 0, 'ID', LVCFMT_LEFT, 40 );//插入列。
m_list.InsertColumn( 1, 'NAME', LVCFMT_LEFT, 50 );。
int nRow = m_list.InsertItem(0, “11”);//插入行。
m_list.SetItemText(nRow, 1, “jacky”);//设置数据。
--------------------------------------------------------------------------------。
4. 一直选中item
选中style中的Show selection always,或者在上面第2点中设置LVS_SHOWSELALWAYS。
--------------------------------------------------------------------------------。
5. 选中和取消选中一行
int nIndex = 0;。
//选中
m_list.SetItemState(nIndex, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);。
//取消选中
m_list.SetItemState(nIndex, 0, LVIS_SELECTED|LVIS_FOCUSED);。
--------------------------------------------------------------------------------。
6. 得到listctrl中所有行的checkbox的状态。
m_list.SetExtendedStyle(LVS_EX_CHECKBOXES);。
CString str;。
for(int i=0; i。
{
if( m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED || m_list.GetCheck(i))。
{
str.Format(_T('第%d行的checkbox为选中状态'), i);。
AfxMessageBox(str);。
}
}
--------------------------------------------------------------------------------。
7. 得到listctrl中所有选中行的序号。
方法一:
CString str;。
for(int i=0; i。
{
if( m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED )。
{
str.Format(_T('选中了第%d行'), i);。
AfxMessageBox(str);。
}
}
方法二:
POSITION pos = m_list.GetFirstSelectedItemPosition();。
if (pos == NULL)。
TRACE0('No items were selected!\n');。
else
{
while (pos)。
{
int nItem = m_list.GetNextSelectedItem(pos);。
TRACE1('Item %d was selected!\n', nItem);。
// you could do your own processing on nItem here。
}
}
--------------------------------------------------------------------------------。
8. 得到item的信息
TCHAR szBuf[1024];。
LVITEM lvi;。
lvi.iItem = nItemIndex;。
lvi.iSubItem = 0;。
lvi.mask = LVIF_TEXT;。
lvi.pszText = szBuf;。
lvi.cchTextMax = 1024;。
m_list.GetItem(&lvi);。
--------------------------------------------------------------------------------。
9. 得到listctrl的所有列的header字符串内容。
LVCOLUMN lvcol;。
char str[256];。
int nColNum;。
CString strColumnName[4];//假如有4列。
nColNum = 0;。
lvcol.mask = LVCF_TEXT;。
lvcol.pszText = str;。
lvcol.cchTextMax = 256;。
while(m_list.GetColumn(nColNum, &lvcol))。
{
strColumnName[nColNum] = lvcol.pszText;。
nColNum++;。
}
--------------------------------------------------------------------------------。
10. 使listctrl中一项可见,即滚动滚动条。
m_list.EnsureVisible(i, FALSE);。
--------------------------------------------------------------------------------。
11. 得到listctrl列数。
int nHeadNum = m_list.GetHeaderCtrl()->GetItemCount();。
--------------------------------------------------------------------------------。
12. 删除所有列
方法一:
while ( m_list.DeleteColumn (0))。
因为你删除了第一列后,后面的列会依次向上移动。
方法二:
int nColumns = 4;。
for (int i=nColumns-1; i>=0; i--)。
m_list.DeleteColumn (i);。
--------------------------------------------------------------------------------。
13. 得到单击的listctrl的行列号。
添加listctrl控件的NM_CLICK消息相应函数。
void CTest6Dlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult)。
{
// 方法一:
/*
DWORD dwPos = GetMessagePos();。
CPoint point( LOWORD(dwPos), HIWORD(dwPos) );。
m_list.ScreenToClient(&point);。
LVHITTESTINFO lvinfo;。
lvinfo.pt = point;。
lvinfo.flags = LVHT_ABOVE;。
int nItem = m_list.SubItemHitTest(&lvinfo);。
if(nItem != -1)。
{
CString strtemp;。
strtemp.Format('单击的是第%d行第%d列', lvinfo.iItem, lvinfo.iSubItem);。
AfxMessageBox(strtemp);。
}
*/
// 方法二:。
/*
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;。
if(pNMListView->iItem != -1)。
{
CString strtemp;。
strtemp.Format('单击的是第%d行第%d列',。
pNMListView->iItem, pNMListView->iSubItem);。
AfxMessageBox(strtemp);。
}
*/
*pResult = 0;。
}
--------------------------------------------------------------------------------。
14. 判断是否点击在listctrl的checkbox上。
添加listctrl控件的NM_CLICK消息相应函数。
void CTest6Dlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult)。
{
DWORD dwPos = GetMessagePos();。
CPoint point( LOWORD(dwPos), HIWORD(dwPos) );。
m_list.ScreenToClient(&point);。
LVHITTESTINFO lvinfo;。
lvinfo.pt = point;。
lvinfo.flags = LVHT_ABOVE;。
UINT nFlag;。
int nItem = m_list.HitTest(point, &nFlag);。
//判断是否点在checkbox上。
if(nFlag == LVHT_ONITEMSTATEICON)。
{
AfxMessageBox('点在listctrl的checkbox上');。
}
*pResult = 0;。
}
--------------------------------------------------------------------------------。
15. 右键点击listctrl的item弹出菜单。
添加listctrl控件的NM_RCLICK消息相应函数。
void CTest6Dlg::OnRclickList1(NMHDR* pNMHDR, LRESULT* pResult)。
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;。
if(pNMListView->iItem != -1)。
{
DWORD dwPos = GetMessagePos();。
CPoint point( LOWORD(dwPos), HIWORD(dwPos) );。
CMenu menu;。
VERIFY( menu.LoadMenu( IDR_MENU1 ) );。
CMenu* popup = menu.GetSubMenu(0);。
ASSERT( popup != NULL );。
popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this );。
}
*pResult = 0;。
--------------------------------------------------------------------------------。
16. item切换焦点时(包括用键盘和鼠标切换item时),状态的一些变化顺序。
添加listctrl控件的LVN_ITEMCHANGED消息相应函数。
void CTest6Dlg::OnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult)。
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;。
// TODO: Add your control notification handler code here。
CString sTemp;。
if((pNMListView->uOldState & LVIS_FOCUSED) == LVIS_FOCUSED && 。
(pNMListView->uNewState & LVIS_FOCUSED) == 0)。
{
sTemp.Format('%d losted focus',pNMListView->iItem);。
}
else if((pNMListView->uOldState & LVIS_FOCUSED) == 0 &&。
(pNMListView->uNewState & LVIS_FOCUSED) == LVIS_FOCUSED)。
{
sTemp.Format('%d got focus',pNMListView->iItem);。
}
if((pNMListView->uOldState & LVIS_SELECTED) == LVIS_SELECTED &&。
(pNMListView->uNewState & LVIS_SELECTED) == 0)。
{
sTemp.Format('%d losted selected',pNMListView->iItem);。
}
else if((pNMListView->uOldState & LVIS_SELECTED) == 0 &&。
(pNMListView->uNewState & LVIS_SELECTED) == LVIS_SELECTED)。
{
sTemp.Format('%d got selected',pNMListView->iItem);。
}
*pResult = 0;。
}
--------------------------------------------------------------------------------。
17. listctrl的 subitem 添加图标。
注意: 首先要用 InsertItem() 插入一行的第一列, 然后才能用 SetItem 设置其他项 。
m_list.SetExtendedStyle(LVS_EX_SUBITEMIMAGES);。
m_userlist.SetItem(..); 。
--------------------------------------------------------------------------------。
18. 在CListCtrl显示文件,并根据文件类型来显示图标。
网上找到的代码,自己试用并改正过, share。
步骤1: 设置 list 的图像列表为 系统图像列表 。
BOOL SetSystemImageList( CListCtrl & list )。
{
HIMAGELIST himlSmall;。
HIMAGELIST himlLarge;。
SHFILEINFO sfi;。
char cSysDir[MAX_PATH];。
CString strBuf;。
memset(cSysDir, 0, MAX_PATH);。
GetWindowsDirectory(cSysDir, MAX_PATH);。
strBuf = cSysDir ;。
// SHGetFileInfo:。
// If uFlags contains SHGFI_SYSICONINDEX, the return value is a handle to 。
// an image list that contains the large icon images. 。
// If SHGFI_SMALLICON is included with SHGFI_SYSICONINDEX, the return value 。
// is the handle to an image list that contains the small icon images.。
//
himlSmall = (HIMAGELIST)SHGetFileInfo ( (LPCSTR)cSysDir, 。
0,
&sfi, 。
sizeof(SHFILEINFO), 。
SHGFI_SYSICONINDEX | SHGFI_SMALLICON );。
himlLarge = (HIMAGELIST)SHGetFileInfo((LPCSTR)cSysDir, 。
0,
&sfi, 。
sizeof(SHFILEINFO), 。
SHGFI_SYSICONINDEX | SHGFI_LARGEICON);。
if (himlSmall && himlLarge)。
::SendMessage(list.m_hWnd, LVM_SETIMAGELIST, 。
(WPARAM)LVSIL_SMALL, (LPARAM)himlSmall);。
::SendMessage(list.m_hWnd, LVM_SETIMAGELIST, 。
(WPARAM)LVSIL_NORMAL, (LPARAM)himlLarge);。
return TRUE;
步骤2: 给列表添加指定的文件, 同时获得该文件的的图标索引, 给 list 添加图标。
int GetIconIndex(LPCTSTR lpszPath, BOOL bIsDir, BOOL bSelected) ; // 向前声明。
void AddFiles(CListCtrl & list, LPCTSTR lpszFileName, BOOL bAddToDocument)。
int nIcon = GetIconIndex(lpszFileName, FALSE, TRUE);。
CString strSize;。
CFileFind filefind;。
// get file size。
if ( filefind.FindFile(lpszFileName))。
filefind.FindNextFile();。
strSize.Format('%d', filefind.GetLength());。
else
strSize = '0';。
// split path and filename。
CString strFileName = lpszFileName;。
CString strPath;。
int nPos = strFileName.ReverseFind('\\');。
if (nPos != -1)。
strPath = strFileName.Left(nPos);。
strFileName = strFileName.Mid(nPos + 1);。
// insert to list。
int nItem = list.GetItemCount();。
//list.InsertItem(nItem, strFileName, nIcon);。
//list.SetItemText(nItem, 1, strSize);。
//
// 此处可以根据实际需要修改代码。
//
--------------------------------------------------------------------------------。
19. listctrl内容进行大数据量更新时,避免闪烁。
m_list.SetRedraw(FALSE);。
//更新内容
m_list.SetRedraw(TRUE);。
m_list.Invalidate();。
m_list.UpdateWindow();。
20. 清除 ListCtrl 以重新初始化:。
// 删除所有行。
m_ctrllist.DeleteAllItems() ; 。
// 删除所有列
int iColCount = m_ctrllist.GetHeaderCtrl()->GetItemCount() ;。
// 方法 1
// 原理: 删除第一列后, 其他列向前移动。
while( m_ctrllist.DeleteColumn(0) ) ;。
// 方法 2
for (int i=0; i < iColCount ; i++)。
m_ctrllist.DeleteColumn(0); 。
C++ exception handling uses the try, catch, and throw statements to implement exception handling. With C++ exception handling, your program can communicate unexpected events to a higher execution context that is better able to recover from such abnormal events. These exceptions are handled by code that is outside the normal flow of control.。
Note The Win32 structured exception-handling mechanism works with both C and C++ source files. However, it is not specifically designed for C++. You can ensure that your code is more portable by using C++ exception handling. Also, C++ exception handling is more flexible, in that it can handle exceptions of any type. For C++ programs, it is recommended that you use the C++ exception-handling mechanism (try, catch, throw) described in this topic.。
try-block :
try compound-statement handler-list。
handler-list :
handler handler-listopt。
handler :
catch ( exception-declaration ) compound-statement。
exception-declaration :。
type-specifier-list declarator。
type-specifier-list abstract-declarator。
type-specifier-list。
...
throw-expression :。
throw assignment-expressionopt。
The compound-statement after the try clause is the guarded section of code. The throw-expression “throws” (raises) an exception. The compound-statement after the catch clause is the exception handler, and “catches” (handles) the exception thrown by the throw-expression. The exception-declaration statement indicates the type of exception the clause handles. The type can be any valid data type, including a C++ class. If the exception-declaration statement is an ellipsis (...), the catch clause handles any type of exception, including a C exception. Such a handler must be the last handler for its try-block.。
The operand of throw is syntactically similar to the operand of a return statement.。
Note Microsoft C++ does not support exception-specifications, as described in section 15.4 of the ANSI C++ draft. In addition, it does not support function-try-block described in section 15 of the ANSI C++ draft.。
For more information on C++ exception handling, see Exception Handling Topics (C++). For information on exception handling in general, see Exception Handling: Overview. 。
END C++ Specific。
Example
In the following example, the try block attempts to write the headers. The catch block then handles a specific file exception, and passes all other exceptions on to the outer block with the throw macro:。
// Example of the try and catch statements。
try
// Write the file header。
file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));。
//
// Write the DIB header and the bits。
file.WriteHuge(lpBI, dwDIBSize);。
catch (CFileException* e)。
{
::GlobalUnlock((HGLOBAL) hDib);。
throw;
}
::GlobalUnlock((HGLOBAL) hDib);。
return TRUE;。
给个文件夹中合并所有文件为一个文件的程序做参考。
CString Directory=%%1+"*.*";。
CFileFind FFile;。
CFile Out;
if(Out.Open(%%2,CFile::modeWrite|CFile::modeCreate)){。
BOOL bFound=FFile.FindFile(Directory);。
while(bFound)
{
bFound=FFile.FileNextFile();。
if(!FFile.IsDirectory() && !FFile.IsDots())。
{
CString Filename=FFile.GetFileName();。
CFile In;
if(In.Open(Filename,CFile::modeRead)){。
char cbBuffer[4096];。
int nFIlesize=In.GetLength();。
while(nFIlesize>0){。
{
int nSize=sizeof(cbBuffer);。
if(nSize>nFilesize)。
nSize=nFilesize;。
try {
In.Read(cbBuffer,nSize);。
}
catch(CFileException *e){。
char *lpMsgBuf;。
if(FormatMessage(。
FORMAT_MESSAGE_ALLOCATE_BUFFER |。
FORMAT_MESSAGE_FROM_SYSTEM,。
NULL,e->m_lOsError,。
MAKELANGID(LANG_NEUTRAL,。
SUBLANG_DEFAULT),。
(LPSTR)&lpMsgBuf,0,NULL)>0){。
AfxMessageBox(lpMsgBuf);。
LocalFree(lpMsgBuf);。
}
e->Delete();。
return;
}
try {
Out.Write(cbBuffer,nSize);。
}
catch(CFileException *e){。
char *lpMsgBuf;。
if(FormatMessage(。
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,。
NULL,e->m_lOsError,。
MAKELANGID(LANG_NEUTRAL,。
SUBLANG_DEFAULT),。
(LPSTR)&lpMsgBuf,0,NULL)>0){。
AfxMessageBox(lpMsgBuf);。
LocalFree(lpMsgBuf);。
}
e->Delete();。
return;
}
nFilesize=nSize;。
}
}
else
AfxMessageBox("不能打开"+Filename);。
}
}
}
else
AfxMessageBox("不能创建输出文件");。
copy过来的,应该能解决你的问题。
原文http://www.2cto.com/kf/201309/241029.html。
本文主要研究了一下如何把树形结构的数据保存到文件并读取出来。为了更形象说明用了一个界面程序显示,程序用了model/view框架。 。
数据类
DataItem 就是保存在树形结构的基本数据。其最重要的保存数据的函数是SerialzeData。
[cpp]
{
public:
DataItem(int id = 100,QString name = "root"); 。
~DataItem(); 。
void SetRoot(DataItem *root); 。
void SerialzeData(bool isSave,QDataStream &stream); 。
void Clear(); 。
void Init(); 。
//protected: 。
int GetID() 。
{
return ID; 。
}
QString GetName() 。
{
return Name; 。
}
void SetID(int id) 。
{
ID = id; 。
}
void SetName(QString name) 。
{
Name = name; 。
}
int GetSize() 。
{
return dataVec.size(); 。
}
void AddItem(DataItem *pItem); 。
void DeleteItem(DataItem *pItem); 。
void DeleteItem(int index); 。
DataItem *GetItem(int index); 。
DataItem *GetParent() 。
{
return pRoot; 。
}
int indexOf(DataItem* pItem); 。
private:
int ID;
QString Name; 。
vector<DataItem*> dataVec; 。
DataItem *pRoot; 。
};
[cpp]
DataItem::DataItem( int id,QString name ):ID(id),Name(name),pRoot(NULL) 。
{
//pRoot = new DataItem(100,"Root"); 。
}
DataItem::~DataItem() 。
{
}
//SerialzeData 原来是,保存数据时,先保存每个项的数据,在后面保存该项的子节点个数,并递归保存各个子节点数据 。
void DataItem::SerialzeData( bool isSave,QDataStream &stream ) 。
{
if (isSave) 。
{
stream<<GetID()<<GetName(); //save ID and Name 。
stream<<dataVec.size(); //save the number of child 。
for(int i = 0; i < dataVec.size(); ++i) 。
{
dataVec[i]->SerialzeData(isSave,stream); 。
}
}
else
{
int id; 。
int size; 。
QString name; 。
stream>>id>>name; //Get ID and Name 。
SetID(id); 。
SetName(name); 。
stream>>size; //Get the number of child 。
for(int i = 0; i < size; ++i) 。
{
DataItem *pItem = new DataItem(0,"name"); 。
pItem->SerialzeData(isSave,stream); 。
AddItem(pItem); 。
}
}
}
void DataItem::AddItem( DataItem *pItem ) 。
{
pItem->SetRoot(this); 。
dataVec.push_back(pItem); 。
}
void DataItem::DeleteItem( DataItem *pItem ) 。
{
vector<DataItem*>::iterator it = dataVec.begin(); 。
for (it; it != dataVec.end(); ++it) 。
{
if (*it == pItem) 。
{
dataVec.erase(it); 。
break; 。
}
}
}
void DataItem::DeleteItem( int index ) 。
{
if (index < dataVec.size()) 。
{
vector<DataItem*>::iterator it = dataVec.begin(); 。
it = it + index; 。
dataVec.erase(it); 。
}
}
void DataItem::Init() 。
{
for (int i = 0; i < 5; ++i) 。
{
DataItem *pItem = new DataItem(i,QString("child%1").arg(i)); 。
pRoot->AddItem(pItem); 。
for (int j = 0; j < 2; ++j) 。
{
DataItem *pChild = new DataItem(j,QString("grandchild%0 -%1").arg(i).arg(j)); 。
pItem->AddItem(pChild); 。
}
}
}
void DataItem::SetRoot( DataItem *root ) 。
{
pRoot = root; 。
}
void DataItem::Clear() 。
{
dataVec.clear(); 。
}
DataItem * DataItem::GetItem( int index ) 。
{
if (index < dataVec.size()) 。
{
return dataVec[index]; 。
}
else
{
return NULL; 。
}
}
int DataItem::indexOf( DataItem* pItem ) 。
{
int index = -1; 。
for (int i = 0; i < dataVec.size(); ++i) 。
{
if (dataVec[i] == pItem) 。
{
index = i; 。
break; 。
}
}
return index; 。
}
数据模型
TreeDataModel的底层数据就是上面定义的DataItem。用这种视图/模型的编程方式可以尽量减少数据与界面的耦合性。由于继承了QAbstractItemModel。所以必须重写其中的五个纯虚函数columnCount (),data(),index (),parent ()和rowCount()。
[cpp]
class TreeDataModel:public QAbstractItemModel 。
{
Q_OBJECT
public:
TreeDataModel(QObject *parent = NULL); 。
~TreeDataModel(); 。
void SetRoot(DataItem *pRoot) 。
{
m_pTreeData = pRoot; 。
}
QModelIndex parent ( const QModelIndex & index ) const; 。
QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const ; 。
QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; 。
QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const; 。
int columnCount ( const QModelIndex & parent = QModelIndex() ) const; 。
int rowCount ( const QModelIndex & parent = QModelIndex() ) const; 。
DataItem* dataFromIndex(const QModelIndex &index) const; 。
void SaveData(QDataStream &out); 。
void LoadData(QDataStream &in); 。
protected:
private:
DataItem *m_pTreeData; 。
};
[cpp]
TreeDataModel::TreeDataModel( QObject *parent /*= NULL*/ ):QAbstractItemModel(parent) 。
{
m_pTreeData = NULL; 。
}
TreeDataModel::~TreeDataModel() 。
{
}
QVariant TreeDataModel::data( const QModelIndex & index, int role /*= Qt::DisplayRole */ ) const 。
{
DataItem *pItem = dataFromIndex(index); 。
if ((pItem)&&(role == Qt::DisplayRole)) 。
{
switch (index.column()) 。
{
case 0: 。
return pItem->GetID(); 。
case 1: 。
return pItem->GetName(); 。
}
}
return QVariant(); 。
}
QVariant TreeDataModel::headerData( int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole */ ) const 。
{
if ((section <2) && (orientation == Qt::Horizontal)&& (role == Qt::DisplayRole)) 。
{
switch (section) 。
{
case 0: 。
return tr("编号"); 。
case 1: 。
return tr("名称"); 。
default: 。
return QVariant(); 。
}
}
else
{
return QVariant(); 。
}
}
QModelIndex TreeDataModel::index( int row, int column, const QModelIndex & parent /*= QModelIndex() */ ) const 。
{
if (!m_pTreeData ||row < 0 || column < 0) 。
{
return QModelIndex(); 。
}
else
{
DataItem *pItem = dataFromIndex(parent); 。
if (pItem) 。
{
DataItem *pChild = pItem->GetItem(row); 。
if (pChild) 。
{ 。
return createIndex(row,column,pChild); 。
} 。
}
return QModelIndex(); 。
}
}
int TreeDataModel::columnCount( const QModelIndex & parent /*= QModelIndex() */ ) const 。
{
return 2; 。
}
int TreeDataModel::rowCount( const QModelIndex & parent /*= QModelIndex() */ ) const 。
{
DataItem *pItem = dataFromIndex(parent); 。
if (pItem) 。
{
return pItem->GetSize(); 。
}
return 0; 。
}
DataItem* TreeDataModel::dataFromIndex( const QModelIndex &index ) const 。
{
if (index.isValid()) 。
{
return static_cast<DataItem*>(index.internalPointer()); 。
}
else
{
return m_pTreeData; //这里不要返回NULL 。
}
}
QModelIndex TreeDataModel::parent( const QModelIndex & index ) const 。
{
if (index.isValid()) 。
{
DataItem *pItem = dataFromIndex(index); 。
if (pItem) 。
{
DataItem *pParent = pItem->GetParent(); 。
if (pParent) 。
{ 。
DataItem *pGrandParent = pParent->GetParent(); 。
if (pGrandParent) 。
{ 。
int row = pGrandParent->indexOf(pParent); 。
return createIndex(row,index.column(),pParent); 。
} 。
} 。
}
}
return QModelIndex(); 。
}
void TreeDataModel::SaveData( QDataStream &out ) 。
{
m_pTreeData->SerialzeData(true,out); 。
}
void TreeDataModel::LoadData( QDataStream &in ) 。
{
m_pTreeData->SerialzeData(false,in); 。
}
主框架类
这个类主要实现左边的树形把数据保存到文件中,然后在右边的树形结构加载显示出来。
[cpp]
class MainWidget:public QWidget 。
{
Q_OBJECT
public:
MainWidget(QWidget *patent = NULL); 。
~MainWidget(); 。
protected slots: 。
void leftSelectBtnSlot(); 。
void rightSelectBtnSlot(); 。
void saveBtnSlot(); 。
void loadBtnSlot(); 。
private:
QSplitter *m_pSplitter; 。
QTreeView *m_pLeftTreeView; 。
QTreeView *m_pRightTreeView; 。
QPushButton *m_pLeftSaveBtn; 。
QPushButton *m_pRightLoadBtn; 。
QPushButton *m_pLeftSelectBtn; 。
QPushButton *m_pRightSelectBtn; 。
QLineEdit *m_pLeftLEdit; 。
QLineEdit *m_pRightLEdit; 。
QGridLayout *m_pLeftLayout; 。
QGridLayout *m_pRightLayout; 。
TreeDataModel *m_pLeftModel; 。
TreeDataModel *m_pRightModel; 。
};