在这篇文章中,简单的讲述一下在QT中设计一个模拟短信收发效果的平台。
下面先展示一下会话模块的效果图,如下所示:
界面的标题首先显示的是“会话中”,接收方后有个下拉菜单,下拉菜单初始时显示的是“无”,下拉菜单中存储了电话簿中的所有联系人,可以进行选择,当选择某个联系人后,在对应的文本框中显示与所选联系人相对应的号码,并且会话窗口的标题也会随之发生改变,如下图所示:
选择接收人后,点击“发送”按键,如果发送的内容为空,则会出现提示内容“发送内容不能为空”,提醒发送人发送的内容不能为空,如下所示:
当然,如果发送的内容如果不为空,但是接收人未选择,则也会出现提示信息“请选择收件人”,提醒发送人选择好接收人信息,如下图所示:
当选择了接收人,且发送的内容不为空时,则可以进行短信的模拟收发。接下来我们将使用到测试工具,用来模拟短信的接收和发送。测试工具中用户姓名为“李立群”,号码为“8901”,当然也可以设置为其他的信息。我们在会话窗口的接收人下拉菜单中选择“李立群”,在测试工具的接收人下拉菜单中选择之前设置好的用户信息,比方说选择了“翟卫超”,号码为“4567”,界面如下图所示:
短信模拟收发就是模拟短信的发送和接收,上面已经选择了两个人进行通信,一个是“李立群”,号码为“8901”,另外一个是“翟卫超”,号码为“4567”。
对话内容如下所示:
翟卫超:你好啊,最近怎么样?
李立群:还好啊,参加了个中兴竞赛,你呢?
翟卫超:也还行,那你先忙吧!
李立群:好的,下次一起吃饭,拜拜。
翟卫超:拜拜
模拟的短信收发界面如下所示,在发送内容对话框中写入需要发送的信息,然后点击发送,这时,在会话记录对话框中机会记录该条信息的发送人姓名,时间和发送的内容,接收时,每次接收到短信都会在会话记录对话框中添加所接收的信息的发送人信息和接收内容。
如果发送完之后,想发给其他联系人,只需要改变下拉菜单中的联系人,则原先的发送和接收记录都会清除。
将上述对话内容运行在程序中可得如下图的效果图:
上面实现了短信模拟收发的功能,下面我们讲述一下黑名单和垃圾短信过滤。
首先是黑名单,每次当我们接收到由黑名单发送过来的信息时,需要将发送信息保存到垃圾箱中,为了便于测试,我们在电话簿中设置了一个黑名单信息,姓名为“丁健”,号码为“1323”,我们定义了一个XML文件用来存储接收到的信息,在这个文件中同时存储着每条信息的存储位置。下面用例子来进行说明。
用测试工具给“翟卫超”发送两句话“你最近还好吗?”和“怎么不说话啊!”,由于发送人是“丁健”,位于黑名单中,所以其发送的信息不显示,并且直接放入到垃圾箱中。如下图所示:
如上图所示,对于黑名单的发送信息,接收方并不显示的,同时,将接收的信息直接放在垃圾箱中。如下图所示,在我们定义的存储信息内容的XMLMessage.xml文件中将该条信息的存储位置设置为了“垃圾箱”,如下图所示:
接下来,我们讲述一下垃圾短信过滤功能。在key.txt文本文件中存储了屏蔽的关键字,我们通过检查所接收到的信息中是否含有任何一个屏蔽关键字,如果有,则屏蔽该条信息,在会话记录窗口中不予显示内容,且将该条信息直接放入垃圾箱中。
在电话薄中,“翟卫超”属于白名单中,在key.txt的文本文件中我们事先设置了一些屏蔽关键字,分别为“傻逼”、“我操”、“弄死你”、“TMD”,文本文件截图如下图所示:
接下来的说明中,我们将使用“翟卫超”和“李立群”进行简单的对话,有些信息含有屏蔽关键字,有些信息不含有屏蔽关键字,看对话的具体效果及信息存储的具体位置。对话内容如下所示:
李立群:你好啊,小翟!
翟卫超:呵呵,你好啊,你那项目做的咋样了?
李立群:我操,有点难哦,只能继续努力了,呵呵。
翟卫超:对啊,只要努力就好!
李立群:对的,拜拜了
上述对话的运行结果如下图所示:
从上面的对话效果图和信息存储图可以看出,由于“李立群”发送的“我操,有点难哦,只能继续努力了,呵呵。”中含有屏蔽关键字“我操”,所以在“翟卫超”的会话记录对话框中对信息内容进行了屏蔽,而且也将信息标记到垃圾箱中。
下面附上相关的程序:
1.dialog.h文件:
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <ui_dialog.h>
#include <qhash.h>
#include<qpalette.h>
#include<QTextCodec>
#include<QtNetwork/QUdpSocket>
#include<QtNetwork/qudpsocket.h>
#include<QtNetwork/QHostAddress>
#include<QtNetwork/qhostaddress.h>
#include<QList>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog,public Ui_Dialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
void dealmessage(const QString&);
bool location(const QString,const QString);
~Dialog();
public slots:
//显示接收人的姓名和号码
void setreciever(const QString&);
//写XML文件
void writexml(const QString,const QString);
//重命名会话窗口名称
void renamewintitle(const QString&);
//定义发送函数
void send();
//定义接收函数
void recieve();
private:
QTextCodec *codec;
QPalette warning_color;
QUdpSocket *udpsocket;
//定义变量存储发送过来信息的号码
QString number;
//定义变量存储发送过来信息的内容
QString content;
//用哈希表存储电话薄
QHash<QString,QString> qhash_phone;
Ui::Dialog *ui;
//定义自身信息
QString my_number;
};
#endif // DIALOG_H
2.dialog.cpp文件
#include "dialog.h"
#include<ui_dialog.h>
#include<QFile>
#include<QString>
#include<QTextStream>
#include<QXmlStreamReader>
#include<QXmlStreamWriter>
#include<qmessagebox.h>
#include<QTime>
#include<QIODevice>
//构造函数
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
//兼容中文字符
codec = QTextCodec::codecForName("GB2312");
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);
QTextCodec::setCodecForTr(codec);
//设置自身信息
my_number="4567";
//设置提醒文本的字体颜色
warning_color.setColor(QPalette::WindowText,Qt::red);
ui->label_Warning->setPalette(warning_color);
//无发送提醒标志
ui->label_Warning->setText(tr(" "));
//设置ComboBox的最大显示个数为5个
ui->comboBox_Phone->setMaxVisibleItems(5);
//设置ComboBox的首项为空
ui->comboBox_Phone->addItem("无","char");
//qhash_phone中添加一个空对空的键值对
qhash_phone.insert("无"," ");
//打开指定位置的文本文件
QFile phonefile("PhBooks.txt");
//判断是否打开成功,只读方式打开
if(phonefile.open(QFile::ReadOnly))
{
QString phonebook;
//定义两个字符串变量存储电话薄中的姓名和电话号码
QString name,phone,inblacklist;
//定义一个文本流对象in,并用phonefile初始化
QTextStream in(&phonefile);
//检查文本流是否到达文本文件的末尾
while(!in.atEnd())
{
phonebook=in.readLine(50);
//如果没有,读取两行,分别存在姓名和电话号码变量中
inblacklist=phonebook.left(1);
phonebook=phonebook.mid(2);
name=phonebook.left(phonebook.indexOf(" "));
phone=phonebook.mid(phonebook.indexOf(" ")+1);
//将姓名和电话号码对应的保存到一个QHash变量中
qhash_phone.insert(name,phone);
//在ComboBox中添加电话薄中的联系人
ui->comboBox_Phone->addItem(name,"QString");
}
//关闭文本文件
phonefile.close();
}
else
{
//如果文件打开失败,在ComboBox中显示Error
ui->comboBox_Phone->addItem("error","char");
}
udpsocket=new QUdpSocket;
udpsocket->bind(QHostAddress::LocalHost,1573);
//ComboBox_Phone选项改变时,LineEdit_Reciever也做相应改变
QObject::connect(ui->comboBox_Phone,SIGNAL(currentIndexChanged(QString)),this,SLOT(setreciever(QString)));
//ComboBox_Phone选项改变时,对话窗口的标题随之发生变化
QObject::connect(ui->comboBox_Phone,SIGNAL(currentIndexChanged(QString)),this,SLOT(renamewintitle(QString)));
//ComboBox_Phone选项改变时,清空会话记录
QObject::connect(ui->comboBox_Phone,SIGNAL(currentIndexChanged(int)),ui->textEdit_Message,SLOT(clear()));
//点击“关闭”按键则关闭窗口
QObject::connect(ui->pushButton_Close,SIGNAL(clicked()),this,SLOT(close()));
//点击“发送”时,发送报文数据
QObject::connect(ui->pushButton_Send,SIGNAL(clicked()),this,SLOT(send()));
//接收报文数据
QObject::connect(udpsocket,SIGNAL(readyRead()),this,SLOT(recieve()));
}
//显示与ComboBox所选姓名相对应的电话号码在LineEdit_Reciever中
void Dialog::setreciever(const QString &name_select)
{
ui->lineEdit_Reciever->setText(qhash_phone[name_select]);
}
//判断信息存储位置,false表示收件箱,true表示垃圾箱
bool Dialog::location(const QString Number, const QString Content)
{
//默认情况下为收件箱
bool result=false;
//读电话薄文本文件
QFile phonenumb("PhBooks.txt");
if(phonenumb.open(QFile::ReadOnly))
{
QString words;
QTextStream in(&phonenumb);
//检查文本流是否到达文本文件的末尾
while(!in.atEnd())
{
words=in.readLine(50);
if(words.contains(Number))
{
QString flag=words.left(1);
if(flag=="1")
{
result=true;
phonenumb.close();
return result;
}
}
}
phonenumb.close();
}
else
{
ui->textEdit_Message->append("PhBooks.txt文本文件打开失败!");
}
//定义链表存储key.txt中的关键字
QList<QString> keywordlist;
//从key.txt文件中读取屏蔽关键字,并判断接收的信息内容中是否有关键字
QFile keyword("key.txt");
if(keyword.open(QFile::ReadOnly))
{
QString words;
QTextStream in(&keyword);
//检查文本流是否到达文本文件的末尾
while(!in.atEnd())
{
words=in.readLine(50);
keywordlist.append(words);
}
keyword.close();
}
else
{
ui->textEdit_Message->append("key.txt文本文件打开失败!");
}
int listlength=keywordlist.count();
for(int i=0;i<listlength;i++)
{
if(Content.contains(keywordlist.at(i)))
{
result=true;
}
}
return result;
}
//写XML文件
void Dialog::writexml(const QString Number,const QString Content)
{
//获取信息存储位置
bool loc=location(Number,Content);
//定义读文件
QFile message_xml("XMLMessage.xml");
//定义写文件
QFile message_xml_1("temp.xml");
//打开文件
if(!message_xml.open(QIODevice::Text|QIODevice::ReadOnly))
{
QMessageBox::about(this,"无法打开XMLMessage.xml文件","error");
message_xml.close();
return;
}
if(!message_xml_1.open(QIODevice::WriteOnly|QIODevice::Text))
{
QMessageBox::about(this,"无法打开temp.xml文件","error");
message_xml_1.close();
return;
}
//定义xml文件的读写流
QXmlStreamReader xmlreader(&message_xml);
QXmlStreamWriter xmlwriter(&message_xml_1);
//是否是XML文件的第一个元素,即是否是第一条短信
bool flag=true;
//设置模式
xmlwriter.setAutoFormatting(true);
xmlwriter.setCodec(codec);
//是否到文件末尾
while(!xmlreader.atEnd())
{
if(xmlreader.isStartDocument())
{
xmlwriter.writeStartDocument();
}
xmlreader.readNext();
if(xmlreader.isStartElement())
{
//如果是XML文件的第一条信息,则在之前加入新接收的信息
if(xmlreader.name().toString()=="Sms"&flag)
{
xmlwriter.writeStartElement("Sms");
xmlwriter.writeTextElement("Number",Number);
xmlwriter.writeTextElement("Name",qhash_phone.key(Number));
xmlwriter.writeTextElement("Content",Content);
if(loc)
xmlwriter.writeTextElement("Location","垃圾箱");
else
xmlwriter.writeTextElement("Location","收件箱");
xmlwriter.writeEndElement();
flag=false;
}
//读取元素属性
QXmlStreamAttributes attr=xmlreader.attributes();
//写元素名称
xmlwriter.writeStartElement(xmlreader.name().toString());
//写元素属性
if(attr.size()>0)
{
xmlwriter.writeAttributes(attr);
}
}
if(xmlreader.isCharacters())
{
xmlwriter.writeCharacters(xmlreader.text().toString());
}
if(xmlreader.isEndElement())
{
xmlwriter.writeEndElement();
}
}
xmlwriter.writeEndDocument();
//关闭读文件
message_xml.close();
//关闭写文件
message_xml_1.close();
//移除原读取文件
message_xml.remove();
//重命名
QFile::rename("temp.xml","XMLMessage.xml");
}
//重命名窗体名称
void Dialog::renamewintitle(const QString& title)
{
QString win_title="";
if(title!="无")
win_title="与"+title+"通话中";
else
win_title="会话中";
this->setWindowTitle(win_title);
}
//发送函数实现
void Dialog::send()
{
//定义存储发送内容的变量
QString message_send;
//定义接收人
QString message_reciever;
//获取发送内容
message_send=ui->textEdit_Sender->toPlainText();
//获取接收人信息
message_reciever=ui->lineEdit_Reciever->text();
//判断发送内容是否为空
if(message_send==NULL)
{
//发送内容为空时给出提醒
ui->label_Warning->setText(tr("发送内容不能为空!"));
return;
}
else
{
//清空提醒标志文本
ui->label_Warning->setText(tr(" "));
//如果接收人为空
if(message_reciever==NULL)
{
ui->label_Warning->setText(tr("请选择收件人!"));
return;
}
else
{
QString current_time;
QDateTime datetime=QDateTime::currentDateTime();
current_time=" "+datetime.time().toString("H:mm:ss");
//在会话记录中添加发送人
ui->textEdit_Message->append(qhash_phone.key(my_number)+current_time);
ui->textEdit_Message->append(" "+message_send);
}
}
//读取发件人号码
QString phonenumber=my_number;
//设置发送内容
QString temp="<Sms><Number>"+phonenumber+"</Number><Content>"+message_send+"</Content></Sms>";
//发送数据
udpsocket->writeDatagram(qPrintable(temp),256,QHostAddress::LocalHost,1600);
//清空发送内容
ui->textEdit_Sender->clear();
}
//接收函数实现
void Dialog::recieve()
{
char buffer[256];
udpsocket->readDatagram(buffer,256,0,0);
QString temp(buffer);
//处理接收到的字符串,分离出号码和内容
dealmessage(temp);
QString current_time;
//获取当前时间
QDateTime datetime=QDateTime::currentDateTime();
current_time=" "+datetime.time().toString("H:mm:ss");
//在会话记录中添加发送人
ui->textEdit_Message->append(qhash_phone.key(number)+current_time);
//判断该信息位置
bool blackflag=location(number,content);
//如果是黑名单或者信息中含有屏蔽关键字,则屏蔽信息内容
if(!blackflag)
{
ui->textEdit_Message->append(" "+content);
}
else
{
ui->textEdit_Message->append(" ");
}
//向XML文件中写入接收的信息
writexml(number,content);
}
//报文数据处理函数
void Dialog::dealmessage(const QString &numb_cont)
{
//找到发送号码的起始位置
int numb_start=numb_cont.indexOf("<Number>")+8;
QString temp=numb_cont.mid(numb_start);
//找到发送号码的结束位置
int numb_end=temp.indexOf("</Number>");
//得到发送号码
number=temp.left(numb_end);
//找到发送内容的起始位置
int cont_start=numb_cont.indexOf("<Content>")+9;
temp=numb_cont.mid(cont_start);
//找到发送内容的结束位置
int cont_end=temp.indexOf("</Content>");
//得到发送内容
content=temp.left(cont_end);
}
//析构函数
Dialog::~Dialog()
{
delete ui;
}
3.main.cpp文件
#include <QtGui/QApplication>
#include "dialog.h"
#include <QTextStream>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
说明:测试项目程序和上述程序基本相同,只需修改相应的端口号即可。