您的位置:首页 > 其它

多行多列,无限滚动文本显示控件

2012-02-24 17:14 316 查看
//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();
	}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: