Qt制作简单标签云(上)

前言:这两天看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制作简单标签云(下)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值