Chinaunix首页 | 论坛 | 博客
  • 博客访问: 589052
  • 博文数量: 752
  • 博客积分: 40000
  • 博客等级: 大将
  • 技术积分: 5005
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-13 14:47
文章分类

全部博文(752)

文章存档

2011年(1)

2008年(751)

我的朋友

分类:

2008-10-13 16:47:14

类似 MSN 带转义字符的信息发送框的制作(下)


作者:北方工业大学




一、实现了上回说到的多功能文本框之后,接下去的任务就是做一个表情符号选择器。CIconPicker。

说明:本来是想实现图标选择的,但是后来有需要改成了位图选择器,但是类名没有改过来,还是叫 CIconPicker。附带工程中有图标选择器。

二、图标/位图选择器(以下简称选择器)的实现原理

  当用户按下选择器的时候,应该把所有的图像用一个图片列表显示出来;如果用户选择了其中一个图片,则记录该图片的编号,并把图片列表关闭。如果用户没有选择图片 ,那么直接把图片列表关闭 ( 响应 WM_KILLFOCUS 消息 )。
  首先,从 CButton 派生一个类 CIconPicker 。给它增加一些成员用来实现"选择器"的功能。如下所述:

  • 1、图片列表:CArray 存放所有下拉图片,每个图片都有一个编号,即它在图片数组中的序号
  • 2、GetBitmapAt():顾名思义,按序号获取图片
  • 3、AddBitmap():添加一张图片
  • 4、GetCurrentBitmapIndex():返回选中图片的序号
  • 当 CIconPicker 收到 WM_LBUTTONDOWN 消息时先不忙给父窗体发送 WM_COMMAND消息 ,而是创建一个图片列表CIconContainer(容器),然后在容器上面创建和图片数量一样多的按钮,每个按钮显示一张图片。当然,为了
    实现这个功能还得从CButton再派生一个类CInnerButton用来显示图片,感应鼠标事件。

    三、源代码说明

    1、创建容器

    void CIconPicker::OnLButtonDown(UINT nFlags, CPoint point) 
    {
    	if(m_bState) return ;
    	m_bState=TRUE;
    	this->SetState(TRUE);
    	
    	
    	RECT rect;
    	this->GetWindowRect(&rect);
    	
    	POINT pt;
    	pt。x=rect。left;pt。y=rect。bottom;
    	
    	//创建一个图片列表容器
    	m_pIconContainer=new CIconContainer;
    	
    	///把图片数组当作参数传过去
    	if(m_pIconContainer->Create(pt,this,&m_BitmapArray))
    	{
    		m_pIconContainer->ShowWindow(SW_SHOW);
    		m_pIconContainer->UpdateWindow();
    		m_pIconContainer->SetFocus();
    	}
    }
    
    2、为每一张图片在容器内创建一个按钮CInnerButton。我把这个工作交给容器来完成。重载容器(CIconContainer)的Create()函数,如下:
    BOOL CIconContainer::Create(POINT pt,CButton* pParentButton,CArray *pBitmapArray) 
    {
    	if(pBitmapArray->GetSize()<=0)return FALSE;
    	
    	m_pParentButton=pParentButton;
    	
    	///根据每张图片的大小创建IconContainer
    	m_nCol=int(sqrt(pBitmapArray->GetSize()))+1;    //计算列数
    	BITMAP bm;
    	pBitmapArray->GetAt(0)->GetBitmap(&bm);   //以图片列表中的第0号图片的大小为
    	
    	基准
    		m_nCellWidth=bm。bmWidth+4;      //内部单元的宽度
    	m_nCellHeight=bm。bmHeight+4;     //内部单元的高度
    	
    	CRect rect;
    	rect。left=pt。x,rect。top=pt。y;
    	rect。right=pt。x+m_nCellWidth*m_nCol;   //容器的宽度
    	
    	if(pBitmapArray->GetSize()%m_nCol==0)   //计算行数
    	{
    		m_nRow=pBitmapArray->GetSize()/m_nCol;
    	}
    	else
    	{
    		m_nRow=pBitmapArray->GetSize()/m_nCol+1;
    	}
    	rect。bottom=pt。y+m_nCellHeight*m_nRow+2+46;  ///容器的高度=(行数+2)*单元宽度
    	
    	//pParentButton->GetParent()->ScreenToClient(&rect);
    	
    	///创建容器
    	//CWnd::Create(NULL, NULL, WS_VISIBLE | WS_CHILD,
    	//rect,pParentButton->GetParent(),IDC_ICONCONTAINER, NULL);
    
    	CWnd::CreateEx(WS_EX_LEFT,AfxRegisterWndClass(0),NULL,WS_VISIBLE|WS_POPUP,rect,NULL,NULL );
    
    	///创建图片张数+2个按钮
    	for(int i=0;iGetSize();j++)
    		{
    			///计算按钮的位置
    			CRect innerrect;
    			innerrect。left=j*m_nCellWidth;
    			innerrect。top=i*m_nCellHeight;
    			innerrect。right=innerrect。left+m_nCellWidth;
    			innerrect。bottom=innerrect。top+m_nCellHeight;
    			
    			innerrect。DeflateRect(2,2);
    			
    			///新建按钮
    			CInnerButton *pInnerButton;
    			pInnerButton=new CInnerButton;
    			pInnerButton->Create(NULL,WS_CHILD |WS_VISIBLE,
    				innerrect,this,IDC_INNERBUTTON+i*m_nCol+j);
    			
    			///设置按钮的图标
    			pInnerButton->SetBitmap(pBitmapArray->GetAt(i*m_nCol+j));
    			pInnerButton->ShowWindow(SW_SHOW);
    			
    			///记录该按钮的指针
    			m_InnerButtonArray。Add(pInnerButton);
    		}
    	}
    	
    	
    	////创建两个扩展功能按钮
    	this->GetClientRect(&rect);
    	CInnerButton *pInnerButton;
    	pInnerButton=new CInnerButton;
    	
    	rect。left=2;
    	rect。right-=2;
    	rect。top=m_nRow*m_nCellHeight+3;
    	rect。bottom=rect。top+20;  //按钮的高度为22
    	
    	
    	pInnerButton->Create(NULL,WS_CHILD |WS_VISIBLE,
    		rect,this,IDC_INNERBUTTON-1);
    	pInnerButton->SetFont(m_pParentButton->GetParent()->GetFont());
    	pInnerButton->SetWindowText("显示更多的图释");
    	
    	pInnerButton=new CInnerButton;
    	
    	rect。top=rect。bottom+3;
    	rect。bottom=rect。top+20;
    	pInnerButton->Create(NULL,WS_CHILD |WS_VISIBLE,
    		rect,this,IDC_INNERBUTTON-2);
    	pInnerButton->SetWindowText("我的自定义图释");
    	pInnerButton->SetFont(m_pParentButton->GetParent()->GetFont());
    	
    	return TRUE;
    }
    
       当用户单击了其中的一个按钮时,把序号记录下来(可以根据InnerButton的ID,创建的时候ID是递增的)并给父窗体(CIconPicker)发送一个消息,把序号送过去。
    BOOL CIconContainer::OnCommand(WPARAM wParam, LPARAM lParam) 
    {
    	if(LOWORD(wParam)-IDC_INNERBUTTON==-1)
    	{
    		////在这里响应"显示更多的图释"
    	}
    	if(LOWORD(wParam)-IDC_INNERBUTTON==-2)
    	{
    		////在这里响应"我的自定义图释"
    		CFileDialog SelectFileDlg(TRUE,"bmp","noname",OFN_FILEMUSTEXIST,
    			"Bitmap File(*。bmp)|*。bmp",m_pParentButton);
    		if(SelectFileDlg。DoModal()==IDOK)
    		{
    			((CIconPicker*)m_pParentButton)->AddBitmap(SelectFileDlg。GetPathName());
    		}
    	}
    	///关闭本窗口
    	Close(LOWORD(wParam)-IDC_INNERBUTTON); ///在这里根据ID取得序号
    	///消息发送的语句在Close()中
    	return TRUE;
    }
    
    这样容器的任务就完成了。如何显示图片那是内部按钮(CInnerButton)的事。

    3、实现内部按钮(CInnerButton)
       只是一个自画按钮而已,感应鼠标事件,自画,贴图等等都是老生常谈了。我就不一一赘述了。若有疑问请看本文附
    带的源代码。最后的效果如下图所示:



       这样,一个图标/图片选择器就基本完成了。呵呵,由于水平有限再加上时间仓卒,功能还很不完善,代码也乱七八糟,大家别用鸡蛋砸我,鸡蛋用来砸我多可惜啊(要砸也别砸脸,砸我邮箱 :querw@sina.com :)

    --------------------next---------------------

    我以前也做过类似的,需要的话,E我 ( cqz5777 发表于 2008-10-6 15:59:00)
     
    圣诞节要到了,祝你圣诞快乐! ( dyj057 发表于 2004-12-23 16:02:00)
     
    不要说害了我们,我觉得这个东西对我的帮助特别大,而且你为人也不错, 我给你发了几封邮件, 你都回复了。而且也为我解决了一些问题.经过我测试,有个问题,我一直没有办法解决:在XP的专业版VC 6.0的Richedit控件引入的是Richedit20.DLL在调试模式下插入位图说:内存不足,无法完成创建新的OLE对象.我怎么也无法解决。 ( dyj057 发表于 2004-12-23 15:58:00)
     
    你做的很好,但是怎么在edit控件中显示gif呢?好像msn中显示的是动画形式的,不是bmp或者图标 ( onlyone 发表于 2004-9-16 14:25:00)
     
    老实说这个东西问题很多,而且也没做完.当时写完的时候一时头脑发热发表了出去,害了不少人,很惭愧. ( querw 发表于 2004-8-28 11:25:00)
     
    有好多网友跟我提到在Release版本下会非法操作,我查看了一下是CIconPicker::OnSelectICON(int index);
    应该改为CIconPicker::OnSelectICON(WPARAM w,LPARAM l). ( querw 发表于 2004-8-28 11:24:00)
     
    请教chzy,你有没有关于转义字符的代码给小弟参考参考啊? ( dylan_ding 发表于 2004-4-29 8:43:00)
     
    在点图片选择器时,会在任务栏上多一窗口,怎么改代码不出现新窗口.
    下面是代码:
    m_pIconContainer=new CIconContainer;
    if(m_pIconContainer->Create(pt,this,&m_BitmapArray))
    {
    m_pIconContainer->ShowWindow(SW_SHOW);
    m_pIconContainer->UpdateWindow();
    m_pIconContainer->SetFocus();
    } ( kenan_2001 发表于 2004-4-26 11:18:00)
     
    转义替换很简单的, 在每次输入之后检查输入的是否是转义服,如果是的, 就去掉结尾的转义符,插入对应的图片就是了(要保存转义符的位置). 而保存的文本中不应该有插入的图片,只有转义符, 装入时再替换成图片. ( chzy 发表于 2004-4-16 21:39:00)
     
    不必使用这么多的按钮的, 使用一个窗口, 在窗口中显示图片矩阵, 根据鼠标位置计算图片号.  选择之后隐藏窗口, 按下选择按钮时再显示选择窗口 ( chzy 发表于 2004-4-16 21:35:00)
     
    .......................................................

    --------------------next---------------------

    阅读(278) | 评论(0) | 转发(0) |
    给主人留下些什么吧!~~