前言:这两天看Qt看到了网络通信这块,就想起了以前想写的一个小项目:标签云(当时不知道这个名,后来查了才知道的)。花了一些心思,做了个简易的标签云版本。记录在此。
本项目分以下几个部分进行记录:
1、项目概况
2、Http向服务器请求关键词分词服务
3、标签云显示
4、关键词及其权重显示
5、小结
一、项目概况
首先说下什么是标签云?
标签云是一套相关的标签以及与此相应的权重。简单来说就是通过图形化的方式显示一些关键词及其权重信息。
这个小项目整体的思路是用户输入一段文字,然后程序通过向服务器发送此段文字,并请求关键词提取服务,从服务器获得相关的数据后显示出来(通过标签云和关键词及其权重直接显示)。最后的结果如下图所示:
标签云:
关键词及其权重:
二、Http向服务器请求关键词分词服务
当用户输入待提取关键词的一段文本后,需要进行对文本提取关键词信息,以便后面的标签显示和权重信息显示。本人目前还没有独立写这个算法的能力,所以这里借用的是网上的API提取关键词及其权重信息。
网上的这种服务并不是很多,我这里使用的是玻森数据提供的分词服务,通过Http协议提交一段文本信息给服务器,然后对应的回复就包括了关键词及其权重。当然这里需要根据其API的要求将数据解析一下。具体的API使用方法可以参见:玻森数据
具体的代码如下:
//设置网络相关信息
manager = new QNetworkAccessManager(this);
request = new QNetworkRequest(QUrl(url));
request->setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json"));
request->setRawHeader("Accept","application/json");
request->setRawHeader("X-Token",myToken.toLatin1());
//关联信号和槽
connect(manager, &QNetworkAccessManager::finished,
this, &HttpPost::replyFinished);
说明:这里主要是根据API的要求进行一些Header的设置。
void HttpPost::on_OKpushButton_clicked()
{
QString send_data = ui->textEdit->toPlainText(); //获取要提取的文本信息
//上传格式化JSON数据至提取关键字服务器
if(!send_data.isEmpty())
{
QJsonObject json_obj;
json_obj.insert(send_data,1);
manager->post(*request,QJsonDocument(json_obj).toJson());
}
content.clear(); //清空上次目录内容
}
说明:这里需要将文本信息转化为JSON数据格式然后上传至远端服务器上。具体的JSON用法并不是很难,可以自己百度。
//收到服务器的返回信息
void HttpPost::replyFinished(QNetworkReply *reply)
{
QJsonParseError error;
QJsonDocument doucment = QJsonDocument::fromJson(reply->readAll(),&error); //读取JSon数据
if (!doucment.isNull() && (error.error == QJsonParseError::NoError))
{
if(doucment.isArray())
{
QJsonArray array0 = doucment.array(); //一层数组
QJsonArray array1 = array0.at(0).toArray(); //二层数组
int key_num = array1.count(); //关键字个数
for(int i = 0;i<key_num;++i)
{
QJsonArray array2 = array1.at(i).toArray(); //三层数组
QJsonValue weigh = array2.at(0); //返回的关键词权重
QJsonValue tag = array2.at(1); //返回的标签
content.insert(weigh.toDouble(),tag.toString()); //取得标签云的权重和文本信息
}
}
}
ShowTagCloud(); //显示词云标签
ShowWeiInfo(); //显示关键词权重页面
reply->deleteLater();
}
说明:从服务器中返回的信息也是JSON类型,需要进行解析。返回的JSON类型数据格式如下:
[
[
[
0.5310796475788876,
"文本"
],
[
0.5134422418759108,
"概括"
],
[
0.4609161239551629,
"关键词"
],
[
0.4586252129798319,
"常用"
],
[
0.1738515297575574,
"作为"
],
[
0.032630636042815325,
"对"
],
[
0.01617369671100372,
"是"
]
]
]
三、标签云显示
这里根据从服务器传来的数据进行解析之后,进行标签云的显示。其过程就是根据关键词构造不同的QGraphicsSimpleTextItem,根据关键词的权重使其显示不同的大小。显示的颜色是随机生成的,这就生成了TagItem(即标签)然后把这一个个标签添加至场景中以便显示。
这里要注意一点的是,在标签添加至场景的过程中要进行碰撞检测,以防两个或多个标签重叠在一起。(这里需要绘制标签的大小,用的是QFontMetrics返回文字的大小,但是好像不是很稳定,有些情况下还是会个把个的冲突)。
主要的代码如下:
//根据关键词信息设置标签Item
void TagCloudShow::SetItems()
{
int max_poi_size = 80; //字体最大值
int min_poi_size = 20; //字体最小值
int dif_size = max_poi_size-min_poi_size;
QList<double> keys = content.uniqueKeys(); //获得键值
foreach (double key, keys)
{
foreach(QString val_str,content.values(key))
{
TagItem *item = new TagItem(val_str);
//根据权重,设置标签字体大小:权重即这里的key值
int cur_size =min_poi_size+dif_size*key;
QFont font;
font.setPointSize(cur_size);
item->setFont(font);
//加入字体列表
show_items.push_back(item);
}
}
}
//将标签Item加入至场景中,这里要进行冲突检测以免标签位置冲突。
void TagCloudShow::AddToScene()
{
int length = show_items.size();
int num = (length<=50)?length:50; //最多50个标签
const int rep_num = 20; //碰撞检测尝试重复次数
for(int i = length-1;i>=(length-num);--i)
{
TagItem *item = show_items[i];
int j = 0;
//随机生成标签项的位置:不能与其他标签项冲突,也不能超出显示框
while(true)
{
//产生随机位置
QPoint pos(qrand()%1000,qrand()%600);
item->setPos(pos);
scene->addItem(item);
//bool is_col = !(scene->collidingItems(item,Qt::IntersectsItemBoundingRect).isEmpty());
//冲突检测,判断当前Item是否和其他标签Item冲突
bool is_col = !(item->collidingItems(Qt::IntersectsItemBoundingRect).isEmpty());
//防止标签超出页面
int width =item->pos().x()+item->boundingRect().width();
int height =item->pos().y()+ item->boundingRect().height();
if(width >= 1000 || width <= 0)
is_col = true;
if(height>=600 || height<=0)
is_col = true;
if(is_col)
{
if(j>rep_num) //冲突超限,丢弃此标签
{
scene->removeItem(item);
qDebug()<<item->text()<<"构造标签失败!";
break;
}
else
{
++j;
scene->removeItem(item); //移走此item,重新生成随机位置
}
}
else
break;
}
}
}
文章有点长,这部分先写到这儿。后面的见:Qt制作简单标签云(下)