//ConTable.H class ConTable : public base::View{ protected: base::Header header; base::ScrollWnd table; typedef class _Line : public base::_class{ public: base::StringList Texts; base::IntegerList<int> States; int Color; _Line(){Color = 0;} }; base::ObjectLink<_Line> _line; base::Menu _rMenu; base::IntegerList<_Line*> _selLines; uint _maxCount,_lineH; base::IntegerList<int> _colWidths; base::Font _defFont; base::Brush _selBkColor; int _style;//目前只支持TS_LASTCOL_AUTOSIZE base::CriticalSection cs; void onHScroll(base::Message* msg); void onNotify(base::CtrlMsg* cm); void onDraw(base::DC* dc); void onMouse(base::Mouse* m); void onCommand(WORD id); void onSize(base::Twain16 cs); void onTableSize(base::Twain16 cs); void onCreate(); //calculate header control size and set it. void refreshHeaderSize(); //clear all item's select flag void clearSelState(); //init context menu. void initMenu(); public: ConTable(); //set a column width. bool SetColWidth(int index,int width); //set a column title. bool SetColText(int index,LPCWSTR title); //set a column title and width. bool SetColumn(int index,LPCWSTR title,int width); //add a column,return new column index. int AddColumn(LPCWSTR title,int width,int index = -1); //delete the column of index. bool DelColumn(int index); //add a new line,return new line index. int AddLine(int index = -1); //delete line of index; bool DelLine(int index); //set a unit text,return true or false if column or line is out bound of index. bool SetLine(int line,LPCWSTR txt,int column); //get a unit text,return null if column or line is not exist. LPCWSTR GetLine(int column,int line); //clear all line. void Clear(); //return all line's count. int GetLineCount(){return _line.Count();} //ConTable control auto delete line in head,if add new line and all line count exceed this value. void SetMaxCount(int lineCount); //return the limit of line count. int GetMaxCount(){return _maxCount;} //scroll client to show line of index. void ScrollToLine(int index = -1); //set line text color. void SetLineColor(int index,int color); //set font size void SetFontSize(int size); //add a line and set text of column,param str is a string separate by param sep. int AddLine(LPCWSTR str,LPCWSTR sep,int index = -1); };
//ConTable.CPP #define ITEM_STATE_SELECT 1 #define TS_LASTCOL_AUTOSIZE 1 //header control height,this value is a const. static int headerHeight = 37; //ConTable void ConTable::onCreate(){ header.Create(_Handle); //set headerHeight const value. headerHeight = header.AdjustSize(_Handle); table.Create(_Handle); } void ConTable::onSize(base::Twain16 cs){ table.SetDimension(0,headerHeight,cs.x,cs.y-headerHeight); if(_style&TS_LASTCOL_AUTOSIZE){ int index = _colWidths.Count() - 1; if(index<0) return; int x = 0; for(int i=0;i<index;i++){ x += _colWidths[i]; } _colWidths[index] = cs.x - x; header.SetItemWidth(index,_colWidths[index]); } } void ConTable::onTableSize(base::Twain16 cs){ refreshHeaderSize(); } void ConTable::refreshHeaderSize(){ base::Twain16 cs; table.GetClientSize(cs); base::Rect r; table.GetRect(r); int width = table.MinSize().x; if(width>cs.x)//have vertical scroll bar. width += r.Width()-cs.x; if(width<r.Width()) width = r.Width(); header.AdjustSize(_Handle,-table.Scr().x,0,width); } void ConTable::onDraw(base::DC* dc){ base::Twain16 cs; table.GetClientSize(cs); dc->SetBkColor(RGB(49,106,197)); dc->SetBkTransparent(); _defFont.Select(dc->Handle()); int i = 0; base::Twain scr = table.Scr(); for(_line.First();!_line.OverFlow();_line.Step(1),i++){ _Line* line = _line.Element(); if((i*_lineH+_lineH-scr.y)<0) continue; if((int)(i*_lineH-scr.y)>(int)cs.y) break; dc->SetTextColor(line->Color); int x = -scr.x; int y = i*_lineH - scr.y; for(uint j=0;j<line->Texts.Count();j++){ base::Rect cr(x,y,x+_colWidths[j],y+_lineH); if(ITEM_STATE_SELECT&line->States[j]){ ::FillRect(*dc,cr,_selBkColor); //dc->SetTextColor() } ::DrawText(dc->Handle(),line->Texts[j],line->Texts[j].Length(),cr,DT_SINGLELINE); x += _colWidths[j]; } } _defFont.Select(dc->Handle()); } void ConTable::SetMaxCount(int lineCount){ base::LocalCriticalSection lcs(cs); if(_maxCount==lineCount) return; _maxCount = lineCount; while((uint)_line.Count()>_maxCount) { _line.Delete(0); } table.Invalidate(); } bool ConTable::SetColText(int index,LPCWSTR title){ return header.SetItemText(index,title); } bool ConTable::SetColWidth(int index,int width){ return header.SetItemWidth(index,width); } bool ConTable::SetColumn(int index,LPCWSTR title,int width){ return header.SetItem(index,title,width); } bool shiftPress(){ int state = (USHORT)GetAsyncKeyState(VK_SHIFT); return 0!=(state&0x8000); } void ConTable::clearSelState(){ for(uint i=0;i<_selLines.Count();i++){ _Line* line = _selLines.Element(i); for(uint j=0;j<line->States.Count();j++){ line->States[j] |= ITEM_STATE_SELECT; line->States[j] -= ITEM_STATE_SELECT; } } _selLines.Clear(); } void ConTable::onMouse(base::Mouse* m) { switch(m->Event) { case WM_LBUTTONDOWN: { if(!shiftPress()) clearSelState(); if(::GetFocus()!=_Handle) SetFocus(_Handle); int index = (m->Y+table.Scr().y)/_lineH; if(index>=_line.Count()) break; _line.First(); _line.Step(index); _Line* line = _line.Element(); _selLines.Add(line); int x = table.Scr().x + m->X; int right = 0; for(uint i=0;i<_colWidths.Count();i++){ right += _colWidths[i]; if(x<=right){ line->States[i] |= ITEM_STATE_SELECT; break; } } table.Invalidate(); } break; case WM_RBUTTONUP:{ POINT pt; pt.x = m->X; pt.y = m->Y; ::ClientToScreen(table,&pt); _rMenu.Popup((short)pt.x,(short)pt.y,table); } break; } } void SetClipboardText(base::String& str) { if(!OpenClipboard(0)) return; EmptyClipboard(); HGLOBAL hM = GlobalAlloc(GMEM_MOVEABLE,str.Length()*2+2);//不能用GMEM_FIXED。 wchar_t* hg = (wchar_t*)GlobalLock(hM); hg[str.Length()] = 0; memcpy(hg,str.Handle(),str.Length()*2); GlobalUnlock(hM); SetClipboardData(CF_UNICODETEXT,hM); GlobalFree(hM); CloseClipboard(); } void ConTable::onCommand(WORD id) { base::String str; switch(id) { case IDC_COPY_SELECT:{ base::String str; for(int i=0;i<(int)_selLines.Count();i++){ _Line* line = _selLines[i]; bool newLine = true; base::String sLine; for(uint i=0;i<line->States.Count();i++){ if(line->States[i]&ITEM_STATE_SELECT){ LPCWSTR s; if(line->Texts.Count()>i) s = line->Texts[i]; else s = L""; if(!sLine.IsNull()) sLine += L"\t"; sLine += s; } } if(!sLine.IsNull()){ if(!str.IsNull()) str += L"\r\n"; str += sLine; } } SetClipboardText(str); } break; case IDC_CLEAR_TEXT: Clear(); break; case IDC_CLEAR_SELECT: for(int i=0;i<(int)_selLines.Count();i++){ _Line* line = _selLines[i]; for(uint i=0;i<line->States.Count();i++){ line->States[i] |= ITEM_STATE_SELECT; line->States[i] -= ITEM_STATE_SELECT; } } _selLines.Clear(); table.Invalidate(); break; case IDC_SELECT_ALL: _selLines.Clear(); for(_line.First();!_line.OverFlow();_line.Step(1)){ _Line* line = _line.Element(); for(uint i=0;i<line->States.Count();i++){ line->States[i] |= ITEM_STATE_SELECT; } _selLines.Add(line); } table.Invalidate(); break; } } void ConTable::onNotify(base::CtrlMsg* cm){ NMHEADER* pnh = (NMHEADER*)cm->lParam; if(pnh->hdr.code==HDN_TRACK){ _colWidths[pnh->iItem] = pnh->pitem->cxy; int width = 0; for(uint i=0;i<_colWidths.Count();i++){ width += _colWidths[i]; } table.SetMinSize(width,-1); refreshHeaderSize(); table.Invalidate(); }else if(pnh->hdr.code==HDN_ITEMCLICK){ if(!shiftPress()) clearSelState(); for(_line.First();!_line.OverFlow();_line.Step(1)){ _Line* line = _line.Element(); line->States[pnh->iItem] |= ITEM_STATE_SELECT; _selLines.Add(line); } table.Invalidate(); } } int ConTable::AddColumn(LPCWSTR title,int width,int index){ base::LocalCriticalSection lcs(cs); index = header.AddItem(title,width,index); if(index<0) return -1; _colWidths.Add(width,index); for(_line.First();!_line.OverFlow();_line.Step(1)){ _Line* line = _line.Element(); if((int)line->Texts.Count()>index) line->Texts.Add(0,index); line->States.Add(0,index); } width = 0; for(uint i=0;i<_colWidths.Count();i++){ width += _colWidths[i]; } table.SetMinSize(width,-1); refreshHeaderSize(); table.Invalidate(); return index; } int ConTable::AddLine(int index){ base::LocalCriticalSection lcs(cs); _Line* line; if(index==-1){ line = _line.Add(); index = _line.Count()-1; }else if(index==0){ line = _line.Add(0); index = 0; }else{ _line.First(); _line.Step(index); line = _line.Add(1); } for(uint i=0;i<_colWidths.Count();i++) line->States.Add(0); if(_maxCount<(uint)_line.Count()) _line.Delete(0); table.SetMinSize(-1,_lineH*_line.Count()); return index; } int ConTable::AddLine(LPCWSTR str,LPCWSTR sep,int index){ base::LocalCriticalSection lcs(cs); _Line* line; if(index==-1){ line = _line.Add(); index = _line.Count()-1; }else if(index==0){ line = _line.Add(0); index = 0; }else{ _line.First(); _line.Step(index); line = _line.Add(1); } for(uint i=0;i<_colWidths.Count();i++) line->States.Add(0); base::StringList sl; sl.SplitString(str,sep); for(uint i=0;i<sl.Count();i++){ if(i>=_colWidths.Count()) break; if(line->Texts.Count()<=i) line->Texts.Add(sl[i]); else line->Texts[i] = sl[i]; } if(_maxCount<(uint)_line.Count()) _line.Delete(0); table.SetMinSize(-1,_lineH*_line.Count()); return index; } bool ConTable::SetLine(int iline,LPCWSTR txt,int column){ base::LocalCriticalSection lcs(cs); if(_line.Count()<=iline) return false; int nCol = header.GetCount(); if(column>=nCol) return false; _line.First(); _line.Step(iline); _Line* line = _line.Element(); while((int)line->Texts.Count()<=column){ line->Texts.Add(0); } line->Texts.Element(column) = txt; return true; } void ConTable::Clear(){ base::LocalCriticalSection lcs(cs); _selLines.Clear(); _line.Clear(); table.SetMinSize(-1,_lineH*_line.Count()); table.Invalidate(); } bool ConTable::DelColumn(int index){ base::LocalCriticalSection lcs(cs); if(!header.DelItem(index)) return 0; _colWidths.Remove(index); for(_line.First();!_line.OverFlow();_line.Step(1)){ _Line* line = _line.Element(); line->Texts.Delete(index); line->States.Remove(index); } refreshHeaderSize(); table.Invalidate(); return 1; } bool ConTable::DelLine(int index){ base::LocalCriticalSection lcs(cs); if(index>=_line.Count()) return 0; _line.First(); _line.Step(index); _selLines.RemoveValue(_line.Element()); _line.Delete(); table.SetMinSize(-1,_lineH*_line.Count()); table.Invalidate(); return 1; } LPCWSTR ConTable::GetLine(int index,int col){ base::LocalCriticalSection lcs(cs); if(index>=_line.Count()) return 0; if(col>=(int)_colWidths.Count()) return 0; _line.First(); _line.Step(index); _Line* line = _line.Element(); return line->Texts[col]; } void ConTable::onHScroll(base::Message* msg){ header.SetLocation(-table.Scr().x,0); } void ConTable::SetFontSize(int size){ _defFont.LogFont()->lfHeight = size; _defFont.Create(); _lineH = size*4/3; table.SetMinSize(-1,_lineH*_line.Count()); } void ConTable::ScrollToLine(int index){ if(index<0){ table.ScrollEnd(0,1); return; } base::Twain16 cs; table.GetClientSize(cs); int dy = (index+1)*_lineH - cs.y - table.Scr().y; table.Scroll(0,dy); } void ConTable::SetLineColor(int index,int color){ _line.First(); _line.Step(index); _Line* line = _line.Element(); line->Color = color; } void ConTable::initMenu(){ _rMenu.Create(1); _rMenu.AddItem(-1,L"复制选择文本",IDC_COPY_SELECT); _rMenu.AddSplit(-1); _rMenu.AddItem(-1,L"全选",IDC_SELECT_ALL); _rMenu.AddItem(-1,L"清除选择",IDC_CLEAR_SELECT); _rMenu.AddSplit(-1); _rMenu.AddItem(-1,L"清除所有文本",IDC_CLEAR_TEXT); } ConTable::ConTable():_maxCount(200),_style(TS_LASTCOL_AUTOSIZE){ //table.SetBkgndColor(0); _defFont.LogFont()->lfHeight = 12; _defFont.Create(); _lineH = _defFont.LogFont()->lfHeight*4/3; _selBkColor.Create(RGB(51,153,255)); Param->ClassStyle -= CS_DBLCLKS; //Param->AddStyle(WS_DLGFRAME); table.Param->ExStyle = (WS_EX_WINDOWEDGE); table.OnDraw.Add(this,&ConTable::onDraw); table.OnMouse.Add(this,&ConTable::onMouse); table.OnCommand.Add(this,&ConTable::onCommand); OnCreate.Add(this,&ConTable::onCreate); OnSize.Add(this,&ConTable::onSize); table.OnSize.Add(this,&ConTable::onTableSize); table.GetMsgHook(WM_HSCROLL)->Add(this,&ConTable::onHScroll); header.OnNotify.Bind(this,&ConTable::onNotify); initMenu(); }
多行多列,无限滚动文本显示控件
最新推荐文章于 2023-03-19 08:57:51 发布