首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

在网络传输中,不仅要不把文字数据、视频数据和音频数据接收过来,还要对这些数据进行显示和保存,本章通过方案来介绍如何显示和存储多媒体文件。

8.1  文字显示方案

文字的接收显示相对简单,但是只能显示单调的字体文字的通信软件是很难吸引用户的,而聊天记录在通信软件中也是及其重要的,本节来介绍一下如何显示个性字体和保存聊天记录。

8.1.1  个性文字同步显示方案

在使用聊天软件进行聊天时,常常被那些绚丽的字体所吸引,那么如何才能实现个性文字同步显示呢?

首先,可以确定的是,要使用RichEdit控件,该控件可以显示不同的字体。然后,要把每行显示的字体都交给用户控制就可以了,这时就有了一个问题,因为RichEdit控件中并没有能单独设置每行字体的方法,可是如果自己继承一个类编写起来又很麻烦,这要怎么办呢?笔者采用一个简单的方法,那就是通过剪贴板来实现,因为在复制文本的同时会将该文本的字体信息一起复制过来,只要直接粘贴到RichEdit控件中就可以了。下面将创建一个可以同步显示个性文字的聊天室程序。运行程序如图8.1 、图8.2所示。

图8.1  个性字体同步显示(服务器端)

   

图8.2  个性字体同步显示(客户端)

服务器端程序设计如下:

*  实例位置:光盘\mr\8\8.1\8.1.1\01

(1)创建一个基于对话框的应用程序,向对话框中添加一个图像控件、两个静态文本控件、一个群组控件和一个按钮控件。

(2)向工程中导入一幅图片,打开Picture控件的属性窗口,在General选项卡中,在Type组合框中选择Bitmap,在Image组合框中选择IDB_BITMAP1,就可以用Picture控件将图片显示出来。对话框设计如图8.3 所示。

图8.3  对话框设计

(3)在应用程序的InitInstance方法中初始化套接字。

WSADATA wsd;

WSAStartup(MAKEWORD(2,2),&wsd);

(4)从CSocket类派生新类CClientSocket和CServerSocket,在头文件中引用对话框的头文件和afxsock.h头文件,并对对话框类进行前导声明。

(5)绑定套接字,并开始监听客户端。

void CServerDlg::OnOK()

{

   this->UpdateData();

   m_pSocket = new CServerSocket(this);

   if (!m_pSocket->Create(70))

   {

       MessageBox("套接字创建失败");

       delete m_pSocket;

       m_pSocket = NULL;

       return;

   }

   if (!m_pSocket->Listen())

       MessageBox("监听失败");

}

(6)在对话框中添加AcceptConnect方法,用于接受客户端的连接。

void CServerDlg::AcceptConnect()

{

   CClientSocket* socket = new CClientSocket(this);

   //接受客户框的连接

   if (m_pSocket->Accept(*socket))

       m_socketlist.AddTail(socket);

   else

       delete socket;

}

(7)在对话框中添加ReceiveData方法,用于接收客户端传来的字体信息和数据,并将这些字体信息和数据发送到各个客户端。

void CServerDlg::ReceiveData(CClientSocket* socket)

{

   if(font)

   {

       LOGFONT temp;

       //接收传来的字体数据

       int factdata = socket->Receive(&temp,sizeof(temp));

       font = FALSE;

       POSITION pos = m_socketlist.GetHeadPosition();

       //将数据发送给每个客户端

       while (pos!=NULL)

       {

              CClientSocket* socket = (CClientSocket*)m_socketlist.GetNext(pos);

              if (socket != NULL)

                 socket->Send(&temp,sizeof(temp));

       }

   }

   else

   {

   char bufferdata[BUFFERSIZE];

   //接收客户端传来的数据

   int result = socket->Receive(bufferdata,BUFFERSIZE);

   bufferdata[result] = 0;

   if(bufferdata[0] == '~')

   {

       font = TRUE;

       POSITION pos = m_socketlist.GetHeadPosition();

       //将数据发送给每个客户端

       while (pos!=NULL)

       {

              CClientSocket* socket = (CClientSocket*)m_socketlist.GetNext(pos);

              if (socket != NULL)

              {

                 socket->Send(bufferdata,result);

             

              }

              Sleep(100);

       }

   }

   else

   {

       POSITION pos = m_socketlist.GetHeadPosition();

       //将数据发送给每个客户端

       while (pos!=NULL)

       {

              CClientSocket* socket = (CClientSocket*)m_socketlist.GetNext(pos);

              if (socket != NULL)

                 socket->Send(bufferdata,result);

       }

   }

   }

}

客户端程序设计步骤如下:

*  实例位置:光盘\mr\8\8.1\8.1.1\02

(1)创建一个基于对话框的应用程序,向对话框中添加一个图像控件、2个静态文本控件、3个编辑框控件、2个RichEdit控件和3个按钮控件。

(2)向工程中导入一幅图片,用Picture控件将图片显示出来。对话框设计如图8.4 所示。

图8.4  对话框设计

(3)将1个RichEdit控件隐藏,在程序运行时使其不可见。

(4)从CSocket类中派生一个子类CMysocket。在头文件中引用Afxsock.h头文件,目的是使用CSocket类;引用主对话框的头文件,并对主对话框进行前导声明,因为在CMysocket类中需要定义主对话框类指针。

(5)在主对话框中定义一个CMysocket对象指针,创建套接字。

BOOL CClientDlg::OnInitDialog()

{

   ……//此处代码省略

   pMysocket = new CMysocket(this); //创建套接字对象

   if (!pMysocket->Create()) //创建套接字

   {

       delete pMysocket;

       MessageBox("套接字创建失败.");

       return false;

   }

   font = FALSE;

   return TRUE;

}

(6)处理“连接”按钮的单击事件,连接服务器。

void CClientDlg::OnButtonjoin()

{

   UpdateData(true);

   CString servername = m_servername; //读取服务器名称

   int port;

   port = 70; //获取端口

  

   if(!pMysocket->Connect(servername,port)) //连接服务器

   {

       MessageBox("连接服务器失败!");

       return;

   }

   CString str;

   str.Format("%s----->%s",m_name,"进入聊天室");

   pMysocket->Send(str.GetBuffer(0),str.GetLength());

   GetDlgItem(IDC_BUTTONJOIN)->EnableWindow(FALSE);

}

(7)处理“字体”按钮的单击事件,设置信息的字体。

void CClientDlg::OnButtonfont()

{

   CFontDialog dlg; //创建字体对话框对象

   if(dlg.DoModal()==IDOK)

   {

       m_Font.Detach();

       dlg.GetCurrentFont(&logfont); //获取当前字体信息

   }

}

(8)处理“发送”按钮的单击事件,把字体信息和数据发送到服务器中。

void CClientDlg::OnButtonsend()

{

   char a[1]={'~'};

   int res = pMysocket->Send(a,1);

   if(res == SOCKET_ERROR)

   {

       CString str;

       str.Format("发送数据失败,错误码:%d",WSAGetLastError());

       MessageBox(str);

       return;

   }

   Sleep(100);

   int ret = pMysocket->Send(&logfont,sizeof(logfont));

   if(ret == SOCKET_ERROR)

   {

       CString str;

       str.Format("发送数据失败,错误码:%d",WSAGetLastError());

      MessageBox(str);

       return;

   }

   CString str,temp;

   m_info.GetWindowText(str);

   if(str.IsEmpty()|m_name.IsEmpty())

       return;

   temp.Format("%s说: %s",m_name,str);

   pMysocket->Send(temp.GetBuffer(temp.GetLength()),temp.GetLength());

   m_info.SetWindowText("");

   m_info.SetFocus();

}

(9)添加ReceiveData成员方法,用于接收服务器传来的字体信息和数据,并根据字体信息设置显示的字体。

void CClientDlg::ReceiveData()

{

   if(font)

   {

       LOGFONT temp;

       //接收传来的字体数据

       int factdata = pMysocket->Receive((LOGFONT*)&temp,sizeof(temp));

       m_Font.Detach();

       m_Font.CreateFontIndirect(&temp); //直接创建字体

       m_RichFont.SetFont(&m_Font);          //设置字体

       font = FALSE;

   }

   else

   {

       char buffer[200];

       //接收传来的数据

       int factdata = pMysocket->Receive(buffer,200);

       buffer[factdata] = 0;

       if(buffer[0] == '~')

       {

              font = TRUE;

              return;

       }

       else

       {

              CString str;

              str.Format("%s",buffer);

              m_RichFont.SetWindowText(str);

              m_RichFont.SetSel(0,-1);

              m_RichFont.Copy();

              m_RichEdit.Paste();

       }

   }

}

8.1.2  聊天记录设计方案

对于聊天室程序来说聊天记录是非常重要的功能,而且实现起来并不复杂,在接收到信息以后将信息保存到文件中,当用户单击“聊天记录”按钮时在读取文件中的信息并显示出来。

下面就来创建一个带聊天记录功能的聊天室程序。运行程序如图8.5 、图8.6所示。

图8.5  局域网聊天室(服务器端)

   

图8.6  局域网聊天室(客户端)

服务器端程序设计如下:

*  实例位置:光盘\mr\8\8.1\8.1.2\01

(1)创建一个基于对话框的应用程序,向对话框中添加一个图像控件、两个静态文本控件、一个群组控件和一个按钮控件。

(2)向工程中导入一幅图片,打开图像控件的属性窗口,在General选项卡中,在Type组合框中选择Bitmap,在Image组合框中选择IDB_BITMAP1,就可以用图像控件将图片显示出来。对话框设计如图8.7 所示。

图8.7  对话框设计

(3)在应用程序的InitInstance方法中初始化套接字。

   WSADATA wsd;

   WSAStartup(MAKEWORD(2,2),&wsd);

(4)从CSocket类派生新类CClientSocket和CServerSocket,在头文件中引用对话框的头文件和afxsock.h头文件,并对对话框类进行前导声明。

(5)绑定套接字,并开始监听客户端。

void CServerDlg::OnOK()

{

   this->UpdateData();

   m_pSocket = new CServerSocket(this);

   if (!m_pSocket->Create(70))

   {

       MessageBox("套接字创建失败");

       delete m_pSocket;

       m_pSocket = NULL;

       return;

   }

   if (!m_pSocket->Listen())

       MessageBox("监听失败");

}

(6)在对话框中添加AcceptConnect方法,用于接受客户端的连接。

void CServerDlg::AcceptConnect()

{

   CClientSocket* socket = new CClientSocket(this);

   //接受客户框的连接

   if (m_pSocket->Accept(*socket))

       m_socketlist.AddTail(socket);

   else

       delete socket;

}

(7)在对话框中添加ReceiveData方法,用于接收客户端传来的数据。

void CServerDlg::ReceiveData(CClientSocket* socket)

{

   char bufferdata[BUFFERSIZE];

   //接收客户端传来的数据

   int result = socket->Receive(bufferdata,BUFFERSIZE);

   bufferdata[result] = 0;

   POSITION pos = m_socketlist.GetHeadPosition();

   //将数据发送给每个客户端

   while (pos!=NULL)

   {

       CClientSocket* socket = (CClientSocket*)m_socketlist.GetNext(pos);

       if (socket != NULL)

              socket->Send(bufferdata,result);

   }

}

客户端程序设计步骤如下:

*  实例位置:光盘\mr\8\8.1\8.1.2\02

(1)创建一个基于对话框的应用程序,向对话框中添加一个图像控件、3个静态文本控件、3个编辑框控件、2个ListBox控件和3个按钮控件。

(2)向工程中导入一幅图片,并用Picture控件将图片显示出来。对话框设计如图8.8 所示。

图8.8  对话框设计

(3)从CSocket类中派生一个子类CMysocket。在头文件中引用Afxsock.h头文件,目的是使用CSocket类;引用主对话框的头文件,并对主对话框进行前导声明,因为在CMysocket类中需要定义主对话框类指针。

(4)在主对话框中定义一个CMysocket对象指针,创建套接字,并使对话框中聊天记录的部分隐藏。

BOOL CClientDlg::OnInitDialog()

{

   ……//此处代码省略

   pMysocket = new CMysocket(this); //创建套接字对象

   if (!pMysocket->Create()) //创建套接字

   {

       delete pMysocket;

       MessageBox("套接字创建失败.");

       return FALSE;

   }

   m_bExpand=FALSE;

   CRect rcDlg, rcMarker;

   GetWindowRect(rcDlg);

   m_nExpandedHeight = rcDlg.Height();

   GetDlgItem(IDC_STATIC1)->GetWindowRect(rcMarker);

   m_nNormalHeight = (rcMarker.top - rcDlg.top);

   Display();

   ::GetCurrentDirectory(256,buf); //获取程序根目录路径

   strcat(buf,"\\聊天记录.txt");

   return TRUE;

}

(5)处理“连接”按钮的单击事件,连接服务器。

void CClientDlg::OnButtonjoin()

{

   UpdateData(true);

   CString servername = m_servername; //读取服务器名称

   int port;

   port = 70; //获取端口

  

   if  (! pMysocket->Connect(servername,port)) //连接服务器

   {

       MessageBox("连接服务器失败!");

       return;

   }

   CString str;

   str.Format("%s----->%s",m_name,"进入聊天室");

   int num = pMysocket->Send(str.GetBuffer(0),str.GetLength());

}

(6)处理“发送”按钮的单击事件,发送数据到服务器。

void CClientDlg::OnButtonsend()

{

   CString str,temp;

   m_info.GetWindowText(str);

   if (str.IsEmpty()|m_name.IsEmpty())

       return;

   temp.Format("%s说: %s",m_name,str);

   int num = pMysocket->Send(temp.GetBuffer(temp.GetLength()),temp.GetLength());

   m_info.SetWindowText("");

   m_info.SetFocus();

}

(7)添加ReceiveData成员方法,用于接收服务器传来的数据,并将聊天信息保存到文本文件中。

void CClientDlg::ReceiveData()

{

   char buffer[200];

   //接收传来的数据

   int factdata =  pMysocket->Receive(buffer,200);

  

   buffer[factdata] = '\0';

   CString str;

   str.Format("%s",buffer);

   int i = m_list.GetCount();

   //将数据添加到列表框中

   m_list.InsertString(m_list.GetCount(),str);

   str += "\r\n~";

   m_File.Open(buf,CFile::modeWrite);

   m_File.SeekToEnd();

   m_File.Write(str,str.GetLength());

   m_File.Close();

}

(8)处理“聊天记录”按钮的单击事件,控制显示或隐藏聊天记录。

void CClientDlg::OnNote()

{

   m_bExpand = !m_bExpand;

   Display();

}

(9)添加Display方法,当显示聊天记录时将文本文件中的数据添加到列表控件中。

void CClientDlg::Display()

{

   m_note.ResetContent();

   CRect rcDlg;

   GetWindowRect(rcDlg);

   if(m_bExpand)

   {

       rcDlg.SetRect( rcDlg.left, rcDlg.top,

       rcDlg.left + rcDlg.Width(),

       rcDlg.top + m_nExpandedHeight);

   }

   else

   {

       rcDlg.SetRect(rcDlg.left, rcDlg.top,

       rcDlg.left + rcDlg.Width(),

       rcDlg.top + m_nNormalHeight);

   }

   MoveWindow(rcDlg);

   if(m_bExpand)

   {

       m_File.Open(buf,CFile::modeRead);

       DWORD size = m_File.GetLength();

       char read[256];

       m_File.Read(read,size);

       CString str="";

       for(int i=0;i<size;i++)

       {

              if(read[i]!='~')

              {

                 str += read[i];

              }

              else

              {

                 m_note.AddString(str);

                 str = "";

              }

       }

       m_File.Close();

   }

}

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论