当前位置: 首页 > news >正文

【QT开发】天气预报项目(详细注释版)

1 项目概述

  • stylesheet界面美化
  • Json数据解析
  • HTTP通信
  • 自定义控件绘制温度
  • 多控件
  • 代码整合调试能力
    在这里插入图片描述

2 stylesheet样式

设置边框弧度

border-radius: 4px;

设置某方向边框弧度

border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;

设置背景颜色

background-color: rgba(60, 60, 60, 100);

父控件影响

父控件指定某类控件的样式,子控件都要遵守此样式进行显示,除非子控件内部有做相关修改

QLabel {background-color: rgba(0, 200, 200, 200);border-radius: 4px;
}

3 窗体无状态栏-关闭

设置无状态栏

setWindowFlag(Qt::FramelessWindowHint);

设置左键弹窗关闭功能

menuQuit = new QMenu(this);
QAction *closeAct = new QAction(QIcon(":/res/close.png"), tr("退出"), this);
menuQuit->addAction(closeAct);
connect(menuQuit,&QMenu::triggered,this,[=]{this->close();
});
void Widget::mousePressEvent(QMouseEvent *event)
{if(event->button() == Qt::RightButton){//qDebug() << "right Mouse clicked!";menuQuit->exec(QCursor::pos());}
}

4 窗口跟随移动

void Widget::mousePressEvent(QMouseEvent *event)
{if(event->button() == Qt::RightButton){//qDebug() << "right Mouse clicked!";menuQuit->exec(QCursor::pos());}//鼠标当前位置 event->globalPos();,//窗口当前位置 this->pos()窗口新位置event->globalPos() - mOffsetif(event->button() == Qt::LeftButton){// qDebug() << event->globalPos() << this->pos();mOffset = event->globalPos()-this->pos();}
}
//鼠标左键按下后的移动,导致这个事件被调用,设置窗口的新位置
void Widget::mouseMoveEvent(QMouseEvent *event)
{this->move(event->globalPos() - mOffset);
}

实现的逻辑

在这里插入图片描述

5 天气预报数据接口

当日版:
http://gfeljm.tianqiapi.com/api?unescape=1&version=v61&appid=21554592&appsecret=h45CVZpY

返回数据

{"cityid": "101080101","date": "2025-11-09","week": "星期日","update_time": "17:56","city": "呼和浩特","cityEn": "huhehaote","country": "中国","countryEn": "China","wea": "晴","wea_img": "qing","tem": "4.4","tem1": "7","tem2": "-5","win": "东南风","win_speed": "1级","win_meter": "5km/h","humidity": "39%","visibility": "30km","pressure": "903","air": "49","air_pm25": "16","air_level": "优","air_tips": "空气质量令人满意,基本无空气污染。","alarm": {"alarm_type": "","alarm_level": "","alarm_title": "","alarm_content": ""},"rain_pcpn": "0","uvIndex": "0","uvDescription": "低","wea_day": "晴","wea_day_img": "qing","wea_night": "晴","wea_night_img": "qing","sunrise": "07:12","sunset": "17:20","aqi": {"update_time": "17:56","cityid": "101080101","city": "呼和浩特市","cityEn": "","country": "","countryEn": "","air": "49","air_level": "优","air_tips": "空气质量令人满意,基本无空气污染。","pp": "—","pm25": "16","pm25_desc": "优","pm10": "49","pm10_desc": "优","o3": "66","o3_desc": "","no2": "18","no2_desc": "","so2": "9","so2_desc": "","co": "0.4","co_desc": "","kouzhao": "不用佩戴口罩","yundong": "适宜运动","waichu": "适宜外出","kaichuang": "适宜开窗","jinghuaqi": "不需要打开"},"nums": 0
}
//七天版
http://gfeljm.tianqiapi.com/api?unescape=1&version=v9&appid=21554592&appsecret=h45CVZpY

返回数据

{"cityid": "101080101","city": "呼和浩特","cityEn": "huhehaote","country": "中国","countryEn": "China","update_time": "2025-11-09 17:56:00","data": [{"day": "09日(星期日)","date": "2025-11-09","week": "星期日","wea": "晴","wea_img": "qing","wea_day": "晴","wea_day_img": "qing","wea_night": "晴","wea_night_img": "qing","tem": "4.4","tem1": "7","tem2": "-5","humidity": "39%","visibility": "30km","pressure": "903","win": ["西南风","东南风"],"win_speed": "3-4级转<3级","win_meter": "5km/h","sunrise": "07:12","sunset": "17:20","air": "49","air_level": "优","air_tips": "空气质量令人满意,基本无空气污染。","alarm": {"alarm_type": "","alarm_level": "","alarm_title": "","alarm_content": ""},"hours": [{"hours": "08时","wea": "晴","wea_img": "qing","tem": "-3","win": "西风","win_speed": "<3级"},{"hours": "09时","wea": "晴","wea_img": "qing","tem": "-1","win": "西风","win_speed": "<3级"},{"hours": "10时","wea": "晴","wea_img": "qing","tem": "0","win": "西南风","win_speed": "3-4级"},{"hours": "11时","wea": "晴","wea_img": "qing","tem": "2","win": "西南风","win_speed": "3-4级"},{"hours": "12时","wea": "晴","wea_img": "qing","tem": "3","win": "西南风","win_speed": "3-4级"},{"hours": "13时","wea": "晴","wea_img": "qing","tem": "5","win": "西南风","win_speed": "3-4级"},{"hours": "14时","wea": "晴","wea_img": "qing","tem": "6","win": "西南风","win_speed": "3-4级"},{"hours": "15时","wea": "晴","wea_img": "qing","tem": "7","win": "西南风","win_speed": "3-4级"},{"hours": "16时","wea": "晴","wea_img": "qing","tem": "7","win": "西南风","win_speed": "3-4级"},{"hours": "17时","wea": "晴","wea_img": "qing","tem": "4","win": "西南风","win_speed": "3-4级"},{"hours": "18时","wea": "晴","wea_img": "qing","tem": "1","win": "西南风","win_speed": "3-4级"},{"hours": "19时","wea": "晴","wea_img": "qing","tem": "0","win": "西南风","win_speed": "3-4级"},{"hours": "20时","wea": "晴","wea_img": "qing","tem": "0","win": "西南风","win_speed": "3-4级"},{"hours": "21时","wea": "晴","wea_img": "qing","tem": "-2","win": "南风","win_speed": "3-4级"},{"hours": "22时","wea": "晴","wea_img": "qing","tem": "-3","win": "东南风","win_speed": "<3级"},{"hours": "23时","wea": "晴","wea_img": "qing","tem": "-3","win": "东南风","win_speed": "<3级"},{"hours": "00时","wea": "晴","wea_img": "qing","tem": "-3","win": "东南风","win_speed": "<3级"},{"hours": "01时","wea": "晴","wea_img": "qing","tem": "-3","win": "东南风","win_speed": "<3级"},{"hours": "02时","wea": "晴","wea_img": "qing","tem": "-3","win": "西风","win_speed": "<3级"},{"hours": "03时","wea": "晴","wea_img": "qing","tem": "-4","win": "东南风","win_speed": "<3级"},{"hours": "04时","wea": "晴","wea_img": "qing","tem": "-3","win": "东风","win_speed": "<3级"},{"hours": "05时","wea": "晴","wea_img": "qing","tem": "-4","win": "东南风","win_speed": "<3级"},{"hours": "06时","wea": "晴","wea_img": "qing","tem": "-5","win": "东风","win_speed": "<3级"},{"hours": "07时","wea": "晴","wea_img": "qing","tem": "-4","win": "东风","win_speed": "<3级"}],"index": [{"title": "紫外线指数","level": "强","desc": "涂擦SPF大于15、PA+防晒护肤品。"},{"title": "减肥指数","level": "较适宜","desc": "风力较强且气温较低,请进行室内运动。"},{"title": "血糖指数","level": "极不易发","desc": "无需担心过敏,可放心外出,享受生活。"},{"title": "穿衣指数","level": "冷","desc": "建议着棉衣加羊毛衫等冬季服装。"},{"title": "洗车指数","level": "较不宜","desc": "风力较大,洗车后会蒙上灰尘。"},{"title": "空气污染扩散指数","level": "良","desc": "气象条件有利于空气污染物扩散。"}],"uvIndex": "1","uvDescription": "低"},{"day": "10日(星期一)","date": "2025-11-10","week": "星期一","wea": "晴","wea_img": "qing","wea_day": "晴","wea_day_img": "qing","wea_night": "晴","wea_night_img": "qing","tem": "9","tem1": "9","tem2": "-2","humidity": "57%","visibility": "","pressure": "","win": ["西南风","东风"],"win_speed": "<3级","win_meter": "","sunrise": "07:14","sunset": "17:19","air": "81","air_level": "良","air_tips": "","alarm": {"alarm_type": "","alarm_level": "","alarm_content": ""},"hours": [{"hours": "08时","wea": "晴","wea_img": "qing","tem": "-4","win": "东北风","win_speed": "<3级"},{"hours": "09时","wea": "晴","wea_img": "qing","tem": "0","win": "东风","win_speed": "<3级"},{"hours": "10时","wea": "晴","wea_img": "qing","tem": "0","win": "南风","win_speed": "<3级"},{"hours": "11时","wea": "晴","wea_img": "qing","tem": "6","win": "西南风","win_speed": "<3级"},{"hours": "12时","wea": "晴","wea_img": "qing","tem": "7","win": "西南风","win_speed": "<3级"},{"hours": "13时","wea": "晴","wea_img": "qing","tem": "8","win": "西南风","win_speed": "<3级"},{"hours": "14时","wea": "晴","wea_img": "qing","tem": "8","win": "西南风","win_speed": "<3级"},{"hours": "15时","wea": "晴","wea_img": "qing","tem": "9","win": "西风","win_speed": "<3级"},{"hours": "16时","wea": "晴","wea_img": "qing","tem": "9","win": "西风","win_speed": "<3级"},{"hours": "17时","wea": "晴","wea_img": "qing","tem": "6","win": "西北风","win_speed": "<3级"},{"hours": "18时","wea": "晴","wea_img": "qing","tem": "4","win": "西南风","win_speed": "<3级"},{"hours": "19时","wea": "晴","wea_img": "qing","tem": "3","win": "南风","win_speed": "<3级"},{"hours": "20时","wea": "晴","wea_img": "qing","tem": "4","win": "东风","win_speed": "<3级"},{"hours": "21时","wea": "晴","wea_img": "qing","tem": "2","win": "东南风","win_speed": "<3级"},{"hours": "22时","wea": "晴","wea_img": "qing","tem": "0","win": "东南风","win_speed": "<3级"},{"hours": "23时","wea": "晴","wea_img": "qing","tem": "0","win": "东北风","win_speed": "<3级"},{"hours": "00时","wea": "晴","wea_img": "qing","tem": "0","win": "东南风","win_speed": "<3级"},{"hours": "01时","wea": "晴","wea_img": "qing","tem": "-1","win": "东南风","win_speed": "<3级"},{"hours": "02时","wea": "晴","wea_img": "qing","tem": "-1","win": "东风","win_speed": "<3级"},{"hours": "03时","wea": "晴","wea_img": "qing","tem": "-1","win": "东风","win_speed": "<3级"},{"hours": "04时","wea": "晴","wea_img": "qing","tem": "-1","win": "东风","win_speed": "<3级"},{"hours": "05时","wea": "晴","wea_img": "qing","tem": "-1","win": "东风","win_speed": "<3级"},{"hours": "06时","wea": "晴","wea_img": "qing","tem": "-1","win": "东风","win_speed": "<3级"},{"hours": "07时","wea": "晴","wea_img": "qing","tem": "0","win": "东北风","win_speed": "<3级"}],"index": [{"title": "紫外线指数","level": "强","desc": "涂擦SPF大于15、PA+防晒护肤品。"},{"title": "减肥指数","level": "较适宜","desc": "气温较低,在户外运动请注意增减衣物。"},{"title": "血糖指数","level": "极不易发","desc": "无需担心过敏,可放心外出,享受生活。"},{"title": "穿衣指数","level": "较冷","desc": "建议着厚外套加毛衣等服装。"},{"title": "洗车指数","level": "适宜","desc": "天气较好,适合擦洗汽车。"},{"title": "空气污染扩散指数","level": "中","desc": "易感人群应适当减少室外活动。"}],"uvIndex": "2","uvDescription": "低"},{"day": "11日(星期二)","date": "2025-11-11","week": "星期二","wea": "晴","wea_img": "qing","wea_day": "晴","wea_day_img": "qing","wea_night": "晴","wea_night_img": "qing","tem": "11","tem1": "11","tem2": "-2","humidity": "61%","visibility": "","pressure": "","win": ["西风","南风"],"win_speed": "<3级","win_meter": "","sunrise": "07:15","sunset": "17:18","air": "91","air_level": "良","air_tips": "","alarm": {"alarm_type": "","alarm_level": "","alarm_content": ""},"hours": [{"hours": "08时","wea": "晴","wea_img": "qing","tem": "0","win": "东风","win_speed": "<3级"},{"hours": "09时","wea": "晴","wea_img": "qing","tem": "3","win": "东风","win_speed": "<3级"},{"hours": "10时","wea": "晴","wea_img": "qing","tem": "3","win": "东风","win_speed": "<3级"},{"hours": "11时","wea": "晴","wea_img": "qing","tem": "8","win": "东风","win_speed": "<3级"},{"hours": "12时","wea": "晴","wea_img": "qing","tem": "9","win": "东南风","win_speed": "<3级"},{"hours": "13时","wea": "晴","wea_img": "qing","tem": "9","win": "西南风","win_speed": "<3级"},{"hours": "14时","wea": "晴","wea_img": "qing","tem": "10","win": "西风","win_speed": "<3级"},{"hours": "15时","wea": "晴","wea_img": "qing","tem": "10","win": "西南风","win_speed": "<3级"},{"hours": "16时","wea": "晴","wea_img": "qing","tem": "10","win": "南风","win_speed": "<3级"},{"hours": "17时","wea": "晴","wea_img": "qing","tem": "10","win": "东北风","win_speed": "<3级"},{"hours": "18时","wea": "晴","wea_img": "qing","tem": "7","win": "东北风","win_speed": "<3级"},{"hours": "19时","wea": "晴","wea_img": "qing","tem": "7","win": "东北风","win_speed": "<3级"},{"hours": "20时","wea": "晴","wea_img": "qing","tem": "4","win": "东北风","win_speed": "<3级"},{"hours": "21时","wea": "晴","wea_img": "qing","tem": "3","win": "东北风","win_speed": "<3级"},{"hours": "22时","wea": "晴","wea_img": "qing","tem": "2","win": "东风","win_speed": "<3级"},{"hours": "23时","wea": "晴","wea_img": "qing","tem": "0","win": "东风","win_speed": "<3级"},{"hours": "00时","wea": "晴","wea_img": "qing","tem": "0","win": "东南风","win_speed": "<3级"},{"hours": "01时","wea": "晴","wea_img": "qing","tem": "0","win": "南风","win_speed": "<3级"},{"hours": "02时","wea": "晴","wea_img": "qing","tem": "0","win": "南风","win_speed": "<3级"},{"hours": "03时","wea": "晴","wea_img": "qing","tem": "0","win": "南风","win_speed": "<3级"},{"hours": "04时","wea": "晴","wea_img": "qing","tem": "-1","win": "西南风","win_speed": "<3级"},{"hours": "05时","wea": "晴","wea_img": "qing","tem": "-1","win": "南风","win_speed": "<3级"},{"hours": "06时","wea": "晴","wea_img": "qing","tem": "-1","win": "南风","win_speed": "<3级"},{"hours": "07时","wea": "晴","wea_img": "qing","tem": "-1","win": "东风","win_speed": "<3级"}],"index": [{"title": "紫外线指数","level": "强","desc": "涂擦SPF大于15、PA+防晒护肤品。"},{"title": "减肥指数","level": "较适宜","desc": "天气凉,在户外运动请注意增减衣物。"},{"title": "血糖指数","level": "极不易发","desc": "无需担心过敏,可放心外出,享受生活。"},{"title": "穿衣指数","level": "较冷","desc": "建议着厚外套加毛衣等服装。"},{"title": "洗车指数","level": "适宜","desc": "天气较好,适合擦洗汽车。"},{"title": "空气污染扩散指数","level": "中","desc": "易感人群应适当减少室外活动。"}],"uvIndex": "3","uvDescription": "中等"},{"day": "12日(星期三)","date": "2025-11-12","week": "星期三","wea": "晴","wea_img": "qing","wea_day": "晴","wea_day_img": "qing","wea_night": "晴","wea_night_img": "qing","tem": "9","tem1": "9","tem2": "-6","humidity": "53%","visibility": "","pressure": "","win": ["西风","东南风"],"win_speed": "<3级","win_meter": "","sunrise": "07:16","sunset": "17:17","air": "86","air_level": "良","air_tips": "","alarm": {"alarm_type": "","alarm_level": "","alarm_content": ""},"hours": [{"hours": "08时","wea": "晴","wea_img": "qing","tem": "-1","win": "东南风","win_speed": "<3级"},{"hours": "11时","wea": "晴","wea_img": "qing","tem": "6","win": "西南风","win_speed": "<3级"},{"hours": "14时","wea": "晴","wea_img": "qing","tem": "8","win": "西风","win_speed": "<3级"},{"hours": "17时","wea": "晴","wea_img": "qing","tem": "6","win": "西风","win_speed": "<3级"},{"hours": "20时","wea": "晴","wea_img": "qing","tem": "1","win": "东北风","win_speed": "<3级"},{"hours": "23时","wea": "晴","wea_img": "qing","tem": "-1","win": "东风","win_speed": "<3级"},{"hours": "02时","wea": "晴","wea_img": "qing","tem": "-3","win": "东风","win_speed": "<3级"},{"hours": "05时","wea": "晴","wea_img": "qing","tem": "-5","win": "东南风","win_speed": "<3级"}],"index": [{"title": "紫外线指数","level": "强","desc": "涂擦SPF大于15、PA+防晒护肤品。"},{"title": "减肥指数","level": "较适宜","desc": "气温较低,在户外运动请注意增减衣物。"},{"title": "血糖指数","level": "极不易发","desc": "无需担心过敏,可放心外出,享受生活。"},{"title": "穿衣指数","level": "较冷","desc": "建议着厚外套加毛衣等服装。"},{"title": "洗车指数","level": "适宜","desc": "天气较好,适合擦洗汽车。"},{"title": "空气污染扩散指数","level": "中","desc": "易感人群应适当减少室外活动。"}],"uvIndex": "3","uvDescription": "中等"},{"day": "13日(星期四)","date": "2025-11-13","week": "星期四","wea": "晴","wea_img": "qing","wea_day": "晴","wea_day_img": "qing","wea_night": "晴","wea_night_img": "qing","tem": "6","tem1": "6","tem2": "-5","humidity": "53%","visibility": "","pressure": "","win": ["西南风","东北风"],"win_speed": "<3级","win_meter": "","sunrise": "07:17","sunset": "17:16","air": "78","air_level": "良","air_tips": "","alarm": {"alarm_type": "","alarm_level": "","alarm_content": ""},"hours": [{"hours": "08时","wea": "晴","wea_img": "qing","tem": "-5","win": "南风","win_speed": "<3级"},{"hours": "11时","wea": "晴","wea_img": "qing","tem": "3","win": "西南风","win_speed": "<3级"},{"hours": "14时","wea": "晴","wea_img": "qing","tem": "5","win": "西南风","win_speed": "<3级"},{"hours": "17时","wea": "晴","wea_img": "qing","tem": "5","win": "西南风","win_speed": "<3级"},{"hours": "20时","wea": "晴","wea_img": "qing","tem": "0","win": "东风","win_speed": "<3级"},{"hours": "23时","wea": "晴","wea_img": "qing","tem": "-1","win": "东风","win_speed": "<3级"},{"hours": "02时","wea": "晴","wea_img": "qing","tem": "-4","win": "西南风","win_speed": "<3级"},{"hours": "05时","wea": "晴","wea_img": "qing","tem": "-4","win": "东北风","win_speed": "<3级"}],"index": [{"title": "紫外线指数","level": "强","desc": "涂擦SPF大于15、PA+防晒护肤品。"},{"title": "减肥指数","level": "较不宜","desc": "天气寒冷,推荐您进行室内运动。"},{"title": "血糖指数","level": "极不易发","desc": "无需担心过敏,可放心外出,享受生活。"},{"title": "穿衣指数","level": "冷","desc": "建议着棉衣加羊毛衫等冬季服装。"},{"title": "洗车指数","level": "适宜","desc": "天气较好,适合擦洗汽车。"},{"title": "空气污染扩散指数","level": "中","desc": "易感人群应适当减少室外活动。"}],"uvIndex": "2","uvDescription": "低"},{"day": "14日(星期五)","date": "2025-11-14","week": "星期五","wea": "晴","wea_img": "qing","wea_day": "晴","wea_day_img": "qing","wea_night": "晴","wea_night_img": "qing","tem": "8","tem1": "8","tem2": "-3","humidity": "49%","visibility": "","pressure": "","win": ["西风","东北风"],"win_speed": "3-4级","win_meter": "","sunrise": "07:18","sunset": "17:15","air": "85","air_level": "良","air_tips": "","alarm": {"alarm_type": "","alarm_level": "","alarm_content": ""},"hours": [{"hours": "08时","wea": "晴","wea_img": "qing","tem": "-3","win": "东北风","win_speed": "<3级"},{"hours": "11时","wea": "晴","wea_img": "qing","tem": "4","win": "西风","win_speed": "3-4级"},{"hours": "14时","wea": "晴","wea_img": "qing","tem": "7","win": "西南风","win_speed": "3-4级"},{"hours": "17时","wea": "晴","wea_img": "qing","tem": "4","win": "西风","win_speed": "3-4级"},{"hours": "20时","wea": "晴","wea_img": "qing","tem": "0","win": "东北风","win_speed": "3-4级"},{"hours": "23时","wea": "晴","wea_img": "qing","tem": "0","win": "东风","win_speed": "3-4级"},{"hours": "02时","wea": "晴","wea_img": "qing","tem": "-2","win": "南风","win_speed": "3-4级"},{"hours": "05时","wea": "晴","wea_img": "qing","tem": "-2","win": "东南风","win_speed": "3-4级"}],"index": [{"title": "紫外线指数","level": "强","desc": "涂擦SPF大于15、PA+防晒护肤品。"},{"title": "减肥指数","level": "较适宜","desc": "风力较强且气温较低,请进行室内运动。"},{"title": "血糖指数","level": "极不易发","desc": "无需担心过敏,可放心外出,享受生活。"},{"title": "穿衣指数","level": "冷","desc": "建议着棉衣加羊毛衫等冬季服装。"},{"title": "洗车指数","level": "较不宜","desc": "风力较大,洗车后会蒙上灰尘。"},{"title": "空气污染扩散指数","level": "良","desc": "气象条件有利于空气污染物扩散。"}],"uvIndex": "2","uvDescription": "低"},{"day": "15日(星期六)","date": "2025-11-15","week": "星期六","wea": "晴","wea_img": "qing","wea_day": "晴","wea_day_img": "qing","wea_night": "晴","wea_night_img": "qing","tem": "6","tem1": "6","tem2": "-8","humidity": "41%","visibility": "","pressure": "","win": ["西风","西风"],"win_speed": "3-4级","win_meter": "","sunrise": "07:20","sunset": "17:15","air": "81","air_level": "良","air_tips": "","alarm": {"alarm_type": "","alarm_level": "","alarm_content": ""},"hours": [{"hours": "08时","wea": "晴","wea_img": "qing","tem": "-1","win": "东北风","win_speed": "3-4级"},{"hours": "11时","wea": "晴","wea_img": "qing","tem": "4","win": "西南风","win_speed": "3-4级"},{"hours": "14时","wea": "晴","wea_img": "qing","tem": "5","win": "西南风","win_speed": "3-4级"},{"hours": "17时","wea": "晴","wea_img": "qing","tem": "3","win": "西风","win_speed": "3-4级"},{"hours": "20时","wea": "晴","wea_img": "qing","tem": "0","win": "西北风","win_speed": "3-4级"},{"hours": "23时","wea": "晴","wea_img": "qing","tem": "-1","win": "西北风","win_speed": "3-4级"},{"hours": "02时","wea": "晴","wea_img": "qing","tem": "-4","win": "西北风","win_speed": "3-4级"},{"hours": "05时","wea": "晴","wea_img": "qing","tem": "-6","win": "西风","win_speed": "3-4级"}],"index": [{"title": "紫外线指数","level": "强","desc": "涂擦SPF大于15、PA+防晒护肤品。"},{"title": "减肥指数","level": "较不宜","desc": "天气寒冷,风力较强,请进行室内运动。"},{"title": "血糖指数","level": "极不易发","desc": "无需担心过敏,可放心外出,享受生活。"},{"title": "穿衣指数","level": "冷","desc": "建议着棉衣加羊毛衫等冬季服装。"},{"title": "洗车指数","level": "较不宜","desc": "风力较大,洗车后会蒙上灰尘。"},{"title": "空气污染扩散指数","level": "良","desc": "气象条件有利于空气污染物扩散。"}],"uvIndex": "2","uvDescription": "低"}],"aqi": {"update_time": "17:56","cityid": "101080101","city": "呼和浩特市","cityEn": "","country": "","countryEn": "","air": "49","air_level": "优","air_tips": "空气质量令人满意,基本无空气污染。","pp": "—","pm25": "16","pm25_desc": "优","pm10": "49","pm10_desc": "优","o3": "66","o3_desc": "","no2": "18","no2_desc": "","so2": "9","so2_desc": "","co": "0.4","co_desc": "","kouzhao": "不用佩戴口罩","yundong": "适宜运动","waichu": "适宜外出","kaichuang": "适宜开窗","jinghuaqi": "不需要打开"},"nums": 7
}

6 软件开发网络通信架构

6.1 BS架构/CS架构

在计算机网络和软件开发中,CS架构(Client-Server Architecture,客户端-服务器架构)和BS架构(Browser-Server Architecture,浏览器-服务器架构)是两种主要的应用程序架构。

CS架构(客户端-服务器架构)

CS架构是一种典型的两层结构,包括客户端和服务器两个部分。在这种架构中,客户端和服务器通过网络进行通信,每部分都有明确的职责。

  1. 客户端:
    用户界面通常在客户端呈现。
    可以是桌面应用程序、移动应用或专用软件。
    负责向服务器发送请求,接收和处理服务器响应。
  2. 服务器:
    管理数据和业务逻辑。
    处理来自客户端的请求,并发送回响应。
    通常承载在远程系统上,如数据库服务器、应用服务器等。
  3. 特点:
    需要为每种操作系统或平台单独开发客户端。
    高效的数据处理和响应能力。
    在客户端设备上占用资源(如内存和处理能力)。

BS架构(浏览器-服务器架构)

BS架构是一种基于Web的三层或多层架构,主要通过Web浏览器作为客户端访问服务器上的应用程序。

  1. 浏览器(客户端):
    使用标准Web浏览器(如Chrome、Firefox等)作为客户端。
    无需安装额外的软件,使用HTML、CSS和JavaScript显示内容。
  2. 服务器:
    和CS架构中的服务器类似,处理业务逻辑和数据存储。
    通过Web服务(如HTTP服务器)提供页面和数据。
  3. 特点:
    跨平台兼容性强,可以在任何支持Web浏览器的设备上运行。
    客户端无需安装专用软件,容易维护和更新。
    可能依赖网络性能,因为所有操作都在服务器上进行。

对比

部署和维护:BS架构易于部署和维护,而CS架构通常需要在每个客户端单独安装和更新。
性能:CS架构可以更有效地利用客户端的计算资源,适合高性能要求的应用。BS架构依赖于服务器的性能和网络延迟。
安全性:CS架构中,数据经常在客户端和服务器之间传输,可能需要更复杂的安全措施。BS架构中,敏感数据主要存储在服务器端。
用户体验:CS架构通常能提供更丰富的用户界面和交互功能。BS架构的用户体验受限于Web技术的能力。

在实际应用中,选择哪种架构取决于具体的业务需求、目标用户群、性能要求以及开发和维护的成本。

6.2 HTTP基本概念

HTTP(超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议。它是万维网
(WWW)的数据通信的基础。了解HTTP的基本概念对于理解现代网络通信至关重要。以下是HTTP的一些核心概念:

  1. 请求和响应
    HTTP是一个基于请求-响应模式的协议。客户端(通常是Web浏览器)向服务器发送一个HTTP请求,然后服务器返回一个HTTP响应。请求包含请求的资源(如网页),而响应包含请求的资源的内容。
  2. HTTP方法
    HTTP定义了一系列的方法来表明对资源的不同操作,最常用的包括:
    GET: 用于请求资源。
    POST: 用于提交数据给服务器(例如,表单数据)。
    PUT: 用于上传文件或内容。
    DELETE: 用于请求删除资源。
    HEAD: 用于获取资源的元信息,而不是资源本身。
  3. 状态码
    服务器对请求的响应中包含一个状态码,它表示请求的成功或失败,以及失败的原因。常见的状态码包括:
    200 OK: 请求成功。
    404 Not Found: 请求的资源未找到。
    500 Internal Server Error: 服务器内部错误。
    301 Moved Permanently: 请求的资源已永久移动到新位置。
  4. URL(统一资源定位符)
    URL是Web上资源的地址。它指定了资源的位置以及用于访问资源的协议(例如,http://)。
  5. HTTP头
    HTTP请求和响应包含头部信息,这些信息包括元数据,如内容类型、内容长度、服务器信息、客户端信息等。例如, Content-Type 头部指示响应中的媒体类型(如text/html,application/json)。
  6. 无状态协议
    HTTP是一个无状态协议,这意味着服务器不会保留任何请求的数据(状态)。然而,通过使用如
    Cookies这样的机制,可以在多个请求之间维持状态。
  7. 安全性(HTTPS)
    HTTPS是HTTP的安全版本,它在HTTP和TCP层之间增加了一个加密层(通常是SSL/TLS)。这提供了数据传输的加密和更好的安全性。
  8. RESTful API
    RESTful是一种使用HTTP协议的Web服务设计风格,它利用HTTP的方法来实现API的不同操作。在RESTful架构中,每个URL代表一个资源,并使用HTTP的方法(如GET, POST)来处理这些资源。
  9. Session和Cookies
    由于HTTP本身是无状态的,Cookies和会话(Session)被用来在多个请求之间存储用户数据,从而为用户提供连贯的体验。

这些概念构成了HTTP的基础,是理解和使用HTTP协议的关键。每个概念都有它的具体细节和使用场景,了解这些有助于更好地在网络应用开发中应用HTTP。

7 QT的HTTP编程

Qt中的HTTP编程主要涉及使用Qt的网络模块来进行HTTP请求和处理HTTP响应。Qt提供了一系列类来处理网络通信,其中最常用的类是 QNetworkAccessManager 、 QNetworkRequest 、 QNetworkReply 以及相关的支持类。

以下是一个基本的HTTP编程示例,展示了如何使用Qt发送一个简单的HTTP GET请求并处理响应:

步骤 1: 包含必要的头文件

#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QObject>
#include <QDebug>

步骤 2: 发送HTTP请求

创建一个 QNetworkAccessManager 对象,并使用它发送HTTP请求。 QNetworkAccessManager 对象会异步地处理请求,并返回一个 QNetworkReply 对象。

int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QNetworkAccessManager manager;QNetworkRequest request(QUrl("http://example.com"));QNetworkReply *reply = manager.get(request);QObject::connect(reply, &QNetworkReply::finished, [&]() {if (reply->error()) {qDebug() << "Error:" << reply->errorString();return;}QString response = reply->readAll();qDebug() << "Response:" << response;});return a.exec();
}

在这个例子中,我们使用 QNetworkAccessManager 的 get 方法发送了一个HTTP GET请求到"http://example.com"。然后,我们连接了 QNetworkReply 对象的 finished 信号到一个lambda函数,该函数在收到HTTP响应时被调用。

注意事项

  1. 异步处理: QNetworkAccessManager 的请求是异步的。这意味着 get 方法会立即返回,而HTTP响应将在稍后通过信号处理。
  2. 错误处理: 应该检查 QNetworkReply 对象是否有错误,并相应地处理。
  3. 内存管理: QNetworkReply 对象需要被正确地管理,以避免内存泄漏。通常情况下,使用
    QObject::deleteLater 来安排删除它是一个好方法。

8 JSON数据

8.1 概述

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它易于人阅读和编写,同时也易于机器解析和生成。JSON是基于JavaScript的一个子集,尽管它是独立于语言的,且有多种语言支持。JSON常用于网络应用程序中的数据传输,尤其是在Web应用程序中与后端服务器通信。使用JSON的原因总结如下:

在这里插入图片描述
在这里插入图片描述

BS/CS开发过程中,会使用不同的编程语言,JSON作为数据传输的标准化格式,方便程序员协议约定和数据处理,以下是不同编程语言处理JSON的方案。

在这里插入图片描述

8.2 QT生成JSON数据

在Qt中生成JSON数据并将其保存到文件的一个基本示例涉及使用 QJsonDocument 、 QJsonObject 和QJsonArray 类。以下是创建一个简单JSON对象并将其保存到文件的示例代码。

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QFile>
#include <QDebug>
void createJsonFile() {// 创建一个JSON对象 键值对QJsonObject jsonObj;jsonObj["name"] = "John Doe";jsonObj["age"] = 30;jsonObj["email"] = "john.doe@example.com";// 创建一个JSON数组QJsonArray jsonArr;jsonArr.append("C++");jsonArr.append("Python");jsonArr.append("JavaScript");jsonArr.append(123);// 将数组添加到JSON对象jsonObj["languages"] = jsonArr;// 将JSON对象转换为JSON文档QJsonDocument jsonDoc(jsonObj);// 将JSON文档转换为字符串(也可以是压缩格式)QByteArray jsonData = jsonDoc.toJson(QJsonDocument::Indented);// 将JSON数据写入文件QFile file("output.json");if (!file.open(QIODevice::WriteOnly)) {qDebug() << "Failed to open file for writing";return;}file.write(jsonData);file.close();qDebug() << "JSON data saved to output.json";
}
int main() {createJsonFile();return 0;
}

说明

  1. 创建JSON对象:使用 QJsonObject 来构建JSON对象,并使用键值对填充数据。
  2. 创建JSON数组:使用 QJsonArray 来创建一个数组,并添加元素。
  3. 组合JSON结构:将JSON数组添加到JSON对象中。
  4. 生成JSON文档:通过 QJsonDocument 来处理JSON数据,可以选择格式化(缩进)或压缩形式。
  5. 保存到文件:创建 QFile 对象,打开文件,写入JSON数据,并关闭文件。

这个例子展示了Qt中处理JSON的基础流程,包括创建、填充数据、转换为字符串,以及写入文件。您可以根据需要调整这个流程来适应更复杂的JSON结构或数据。

#include "widget.h"
#include "ui_widget.h"
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QJsonObject rootObj;rootObj["cityid"] = "1010100";rootObj["date"] = "2024-01-23";rootObj["weather"] = "雨夹雪";rootObj["tmp"] = 3;QJsonArray jsonArray;jsonArray.append("data1");jsonArray.append("data2");jsonArray.append("data3");jsonArray.append(100);rootObj["testArry"] = jsonArray;QJsonDocument jsonDoc(rootObj);QByteArray jsonArry = jsonDoc.toJson();QFile file("D:/QT/test.json");file.open(QIODevice::WriteOnly);file.write(jsonArry);file.close();
}
Widget::~Widget()
{delete ui;
}

在JSON中,数组可以包含多种类型的元素,包括对象。当您在Qt中处理JSON数组,其中的元素是对象时,您可以使用 QJsonArray 和 QJsonObject 来创建和处理这些数据结构。以下是一个示例,展示了如何创建一个包含多个对象的JSON数组,并将该数组添加到一个JSON对象中。

示例代码


#include "widget.h"
#include "ui_widget.h"
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QJsonObject rootObj;rootObj["cityid"] = "1010100";rootObj["date"] = "2024-01-23";rootObj["weather"] = "雨夹雪";rootObj["tmp"] = 3;//Json数组QJsonArray jsonArray;jsonArray.append("data1");jsonArray.append("data2");jsonArray.append("data3");jsonArray.append(100);rootObj["testArry"] = jsonArray;QJsonObject alarmObj;alarmObj["alamType"] = "雪灾";alarmObj["alamLeve"] = "黄色";alarmObj["alamTitle"] = "福州市警告老陈多穿点衣服";rootObj["alam"] = alarmObj;QJsonObject day0;day0["day"] = "星期一";day0["wea"] = "晴";day0["tem"] = 5.7;QJsonObject day1;day1["day"] = "星期二";day1["wea"] = "晴";day1["tem"] = 7;QJsonObject day2;day2["day"] = "星期三";day2["wea"] = "多云";day2["tem"] = 17;QJsonArray dayArray;dayArray.append(day0);dayArray.append(day1);dayArray.append(day2);rootObj["days"] = dayArray;//通过QJsonDocument把JSON数据转换成QByteArrayQJsonDocument jsonDoc(rootObj);QByteArray jsonArry = jsonDoc.toJson();QFile file("D:/QT/test.json");file.open(QIODevice::WriteOnly);file.write(jsonArry);file.close();
}
Widget::~Widget()
{delete ui;
}

8.3 QT解析JSON数据

在Qt中解析JSON数据通常涉及到使用 QJsonDocument 、 QJsonObject 和 QJsonArray 类。这些类提供了处理JSON数据的必要工具,使您能够从JSON字符串中提取信息、遍历JSON对象或数组,并访问具体的数据项。以下是一个基本的示例,展示了如何在Qt中解析JSON字符串。

示例:解析JSON字符串
假设您有一个JSON字符串,例如:

{"name": "John Doe","age": 30,"email": "john.doe@example.com","skills": ["C++", "Python", "JavaScript"]
}

以下是如何在Qt中解析这个JSON字符串的步骤:

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>
void parseJson() {// JSON字符串/*
R 是用于定义原始字符串字面量(Raw String Literal)的标记。
在C++中,原始字符串字面量是一种方便的语法,
用于创建包含多行文本和特殊字符的字符串,而无需转义。
R"("chenlichen")"
*/QString testStr = "chenli\"c";QString jsonString = R"({"name": "John Doe","age": 30,"email": "john.doe@example.com","skills": ["C++", "Python", "JavaScript"]})";/*jsonString = "{\n"
" \"name\": \"John Doe\",\n"
" \"age\": 30\n"
"}";
*/// 将JSON字符串转换为QJsonDocumentQJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8());// 检查JSON文档是否包含一个对象if (!jsonDoc.isNull() && jsonDoc.isObject()) {// 获取JSON对象QJsonObject jsonObj = jsonDoc.object();// 访问对象的键值QString name = jsonObj["name"].toString();int age = jsonObj["age"].toInt();QString email = jsonObj["email"].toString();qDebug() << "Name:" << name;qDebug() << "Age:" << age;qDebug() << "Email:" << email;// 处理JSON数组if (jsonObj.contains("skills") && jsonObj["skills"].isArray()) {QJsonArray skillsArray = jsonObj["skills"].toArray();for (const QJsonValue &value : skillsArray) {qDebug() << "Skill:" << value.toString();}}} else {qDebug() << "Invalid JSON...";}
}
int main() {parseJson();return 0;
}

说明

  1. 字符串转换为 QJsonDocument :使用 QJsonDocument::fromJson 方法将JSON字符串转换为
    QJsonDocument 对象。
  2. 提取 QJsonObject :如果 QJsonDocument 包含一个JSON对象,使用 object() 方法获取它。
  3. 访问对象数据:使用键(如 “name” 、 “age” )访问 QJsonObject 中的数据。
  4. 处理数组:如果对象包含一个数组,使用 QJsonArray 来遍历数组中的元素。
    这个示例提供了一个基础框架,用于在Qt中解析和处理JSON数据。您可以根据实际需要调整这个过程,以适应不同的JSON结构和数据类型。
    在Qt中,如果你想要将JSON数据解析到一个 QMap 中,你可以遍历JSON对象的所有键值对,并将它们添加到 QMap 里。这个方法特别适合于当你的JSON对象是一个简单的键值对集合时。以下是一个如何实现这一点的示例。

示例:将JSON数据解析到QMap中

假设你有以下JSON数据:

json
{"name": "John Doe","age": "30","email": "john.doe@example.com"
}

以下是如何将这些数据解析到 QMap<QString, QString> 中的步骤:

#include <QJsonDocument>
#include <QJsonObject>
#include <QMap>
#include <QDebug>
void parseJsonToMap() {// JSON字符串QString jsonString = R"({"name": "John Doe","age": "30","email": "john.doe@example.com"})";// 将JSON字符串转换为QJsonDocumentQJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8());// 准备一个QMap来存储解析的数据QMap<QString, QString> dataMap;// 解析JSON对象并填充QMapif (!jsonDoc.isNull() && jsonDoc.isObject()) {QJsonObject jsonObj = jsonDoc.object();for (auto key : jsonObj.keys()) {dataMap[key] = jsonObj.value(key).toString();}} else {qDebug() << "Invalid JSON...";}// 打印QMap内容for (auto key : dataMap.keys()) {qDebug() << key << ":" << dataMap[key];}
}
int main() {parseJsonToMap();return 0;
}

说明

  1. 从JSON字符串创建 QJsonDocument :使用 QJsonDocument::fromJson 来解析JSON字符串。
  2. 创建 QMap :定义一个 QMap<QString, QString> 来存储键值对。
  3. 遍历JSON对象:使用 keys() 方法获取所有键,然后遍历这些键,将对应的值添加到 QMap 中。
  4. 打印 QMap 内容:遍历 QMap 并打印键值对。

这个示例展示了如何将JSON对象的键值对解析到 QMap 中。这种方法适用于键值对类型的简单JSON对象。对于更复杂的JSON结构,可能需要更详细的解析逻辑。

解析如下JSON

在这里插入图片描述

#include "widget.h"
#include "ui_widget.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDebug>
#include <QJsonArray>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//第一步:读取JSON文件保存到QByteArray中QFile file("D:/QT/test.json");file.open(QIODevice::ReadOnly);QByteArray rawData = file.readAll();file.close();//第二步:把QByteArray转成JSONDocQJsonDocument jsonDoc = QJsonDocument::fromJson(rawData);if( !jsonDoc.isNull() && jsonDoc.isObject()){//第三步:把JsonDoc转成JsonObjQJsonObject jsonRoot = jsonDoc.object();//第四步:如果解析普通键值对,通过“下表键”来获取值QString strW = jsonRoot["weather"].toString();QString strCityId = jsonRoot["cityid"].toString();int tempretrue = jsonRoot["tmp"].toInt();qDebug() << strW;qDebug() << strCityId;qDebug() << QString::number(tempretrue);//第五步:判读是否是一个数组if(jsonRoot.contains("testArry") && jsonRoot["testArry"].isArray()){qDebug() << "array";//如果是数组,转换成JSON数组QJsonArray testArray = jsonRoot["testArry"].toArray();//遍历数组,访问每一项for(QJsonValue val : testArray){//QJsonValue的type函数返回数据类型,根据不同的数据类型处理数据// QJsonValue::Type t = val.type();switch (val.type()) {case QJsonValue::Double:qDebug() << QString::number(val.toDouble());break;case QJsonValue::String:qDebug() << val.toString();break;case QJsonValue::Object:break;}}}//第六步:判断某个键对应的值,是否是一个json对象if(jsonRoot.contains("alam") && jsonRoot["alam"].isObject()){//转成Json对象后处理QJsonObject alamObj = jsonRoot["alam"].toObject();qDebug() << alamObj["alamLeve"].toString();qDebug() << alamObj["alamTitle"].toString();qDebug() << alamObj["alamType"].toString();}if(jsonRoot.contains("days") && jsonRoot["days"].isArray()){QJsonArray dayArray = jsonRoot["days"].toArray();for(QJsonValue val : dayArray){//if(val.type() ==QJsonValue::Object ){if(val.isObject()){QJsonObject obj = val.toObject();qDebug() << obj["day"].toString();qDebug() << QString::number(obj["tem"].toDouble());qDebug() << obj["wea"].toString();}}}}
}
Widget::~Widget()
{delete ui;
}

天气类型和图标

//根据keys,设置icon的路径
mTypeMap.insert("暴雪",":/res/type/BaoXue.png");
mTypeMap.insert("暴雨",":/res/type/BaoYu. png");
mTypeMap.insert("暴雨到大暴雨",":/res/type/BaoYuDaoDaBaoYu.png");
mTypeMap.insert("大暴雨",":/res/type/DaBaoYu.png");
mTypeMap.insert("大暴雨到特大暴雨",":/res/type/DaBaoYuDaoTeDaBaoYu.png");
mTypeMap.insert("大到暴雪",":/res/type/DaDaoBaoXue.png");
mTypeMap.insert("大雪",":/res/type/DaXue.png");
mTypeMap.insert("大雨",":/res/type/DaYu.png");
mTypeMap.insert("冻雨",":/res/type/DongYu.png");
mTypeMap.insert("多云",":/res/type/DuoYun.png");
mTypeMap.insert("浮沉",":/res/type/FuChen.png");
mTypeMap.insert("雷阵雨",":/res/type/LeiZhenYu.png");
mTypeMap.insert("雷阵雨伴有冰雹",":/res/type/LeiZhenYuBanYouBingBao.png");
mTypeMap.insert("霾",":/res/type/Mai.png");
mTypeMap.insert("强沙尘暴",":/res/type/QiangShaChenBao.png");
mTypeMap.insert("晴",":/res/type/Qing.png");
mTypeMap.insert("沙尘暴",":/res/type/ShaChenBao.png");
mTypeMap.insert("特大暴雨",":/res/type/TeDaBaoYu.png");
mTypeMap.insert("undefined",":/res/type/undefined.png");
mTypeMap.insert("雾",":/res/type/Wu.png");
mTypeMap.insert("小到中雪",":/res/type/XiaoDaoZhongXue.png");
mTypeMap.insert("小到中雨",":/res/type/XiaoDaoZhongYu.png");
mTypeMap.insert("小雪",":/res/type/XiaoXue.png");
mTypeMap.insert("小雨",":/res/type/XiaoYu.png");
mTypeMap.insert("雪",":/res/type/Xue.png");
mTypeMap.insert("扬沙",":/res/type/YangSha.png");
mTypeMap.insert("阴",":/res/type/Yin.png");
mTypeMap.insert("雨",":/res/type/Yu.png");
mTypeMap.insert("雨夹雪",":/res/type/YuJiaXue.png");
mTypeMap.insert("阵雪",":/res/type/ZhenXue.png");
mTypeMap.insert("阵雨",":/res/type/ZhenYu.png");
mTypeMap.insert("中到大雪",":/res/type/ZhongDaoDaXue.png");
mTypeMap.insert("中到大雨",":/res/type/ZhongDaoDaYu.png");
mTypeMap.insert("中雪",":/res/type/ZhongXue.png");
mTypeMap.insert("中雨",":/res/type/ZhongYu.png");

9 项目全部代码

widget.ui

在这里插入图片描述

main.cpp

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

widget.cpp

#include "widget.h"
#include "ui_widget.h"#include <QMouseEvent>
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetWorkRequest>
#include <QNetworkReply>
#include <QMessageBox>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QPainter>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置组件大小随窗口大小变化this->setLayout(ui->gridLayout);//设置窗口固定大小//setFixedSize(500, 800);//实例化一个menu控件menuQuit = new QMenu(this);//设置菜单项文字颜色menuQuit->setStyleSheet("QMenu::item{ color:white }");//定义一个动作QAction *closeAct = new QAction(QIcon(":/res/close.png"), tr("退出"), this);//往menu中添加动作menuQuit->addAction(closeAct);//为action绑定信号与槽connect(menuQuit,&QMenu::triggered,this,[=](){this->close();});//由QNetworkAccessManager发起get请求manager = new QNetworkAccessManager(this);//QUrl urlItBoy("http://t.weather.itboy.net/api/weather/city/101010100");QUrl urlItBoy("http://t.weather.itboy.net");//strUrl = "http://gfeljm.tianqiapi.com/api?unescape=1&version=v61&appid=21554592&appsecret=h45CVZpY";strUrl = "http://gfeljm.tianqiapi.com/api?unescape=1&version=v9&appid=21554592&appsecret=h45CVZpY";QUrl urlTianQi(strUrl);//指定请求url的地址QNetworkRequest res(urlTianQi);//发送get请求reply = manager->get(res);//绑定http回复槽函数connect(manager,&QNetworkAccessManager::finished,this,&Widget::readHttpReply);//所有七天天气组件加入对应QListmWeekList << ui->labelDay0 << ui->labelDay1<< ui->labelDay2 << ui->labelDay3<< ui->labelDay4 << ui->labelDay5;mDateList << ui->labelDate0 << ui->labelDate1<< ui->labelDate2 << ui->labelDate3<< ui->labelDate4 << ui->labelDate5;mIconList << ui->labelWeathIcon0 << ui->labelWeathIcon1<< ui->labelWeathIcon2 << ui->labelWeathIcon3<< ui->labelWeathIcon4 << ui->labelWeathIcon5;mWeaTypeList << ui->labelWeath0 << ui->labelWeath1<< ui->labelWeath2 << ui->labelWeath3<< ui->labelWeath4 << ui->labelWeath5;mAirqList << ui->labelAirQ0 << ui->labelAirQ1<< ui->labelAirQ2 << ui->labelAirQ3<< ui->labelAirQ4 << ui->labelAirQ5;mFxList << ui->labelWindDir0 << ui->labelWindDir1<< ui->labelWindDir2 << ui->labelWindDir3<< ui->labelWindDir4 << ui->labelWindDir5;mFlList << ui->labelWindSpe0 << ui->labelWindSpe1<< ui->labelWindSpe2 << ui->labelWindSpe3<< ui->labelWindSpe4 << ui->labelWindSpe5;//根据keys,设置icon的路径mTypeMap.insert("暴雪",":/res/type/BaoXue.png");mTypeMap.insert("暴雨",":/res/type/BaoYu. png");mTypeMap.insert("暴雨到大暴雨",":/res/type/BaoYuDaoDaBaoYu.png");mTypeMap.insert("大暴雨",":/res/type/DaBaoYu.png");mTypeMap.insert("大暴雨到特大暴雨",":/res/type/DaBaoYuDaoTeDaBaoYu.png");mTypeMap.insert("大到暴雪",":/res/type/DaDaoBaoXue.png");mTypeMap.insert("大雪",":/res/type/DaXue.png");mTypeMap.insert("大雨",":/res/type/DaYu.png");mTypeMap.insert("冻雨",":/res/type/DongYu.png");mTypeMap.insert("多云",":/res/type/DuoYun.png");mTypeMap.insert("浮沉",":/res/type/FuChen.png");mTypeMap.insert("雷阵雨",":/res/type/LeiZhenYu.png");mTypeMap.insert("雷阵雨伴有冰雹",":/res/type/LeiZhenYuBanYouBingBao.png");mTypeMap.insert("霾",":/res/type/Mai.png");mTypeMap.insert("强沙尘暴",":/res/type/QiangShaChenBao.png");mTypeMap.insert("晴",":/res/type/Qing.png");mTypeMap.insert("沙尘暴",":/res/type/ShaChenBao.png");mTypeMap.insert("特大暴雨",":/res/type/TeDaBaoYu.png");mTypeMap.insert("undefined",":/res/type/undefined.png");mTypeMap.insert("雾",":/res/type/Wu.png");mTypeMap.insert("小到中雪",":/res/type/XiaoDaoZhongXue.png");mTypeMap.insert("小到中雨",":/res/type/XiaoDaoZhongYu.png");mTypeMap.insert("小雪",":/res/type/XiaoXue.png");mTypeMap.insert("小雨",":/res/type/XiaoYu.png");mTypeMap.insert("雪",":/res/type/Xue.png");mTypeMap.insert("扬沙",":/res/type/YangSha.png");mTypeMap.insert("阴",":/res/type/Yin.png");mTypeMap.insert("雨",":/res/type/Yu.png");mTypeMap.insert("雨夹雪",":/res/type/YuJiaXue.png");mTypeMap.insert("阵雪",":/res/type/ZhenXue.png");mTypeMap.insert("阵雨",":/res/type/ZhenYu.png");mTypeMap.insert("中到大雪",":/res/type/ZhongDaoDaXue.png");mTypeMap.insert("中到大雨",":/res/type/ZhongDaoDaYu.png");mTypeMap.insert("中雪",":/res/type/ZhongXue.png");mTypeMap.insert("中雨",":/res/type/ZhongYu.png");//为widget0404,0405安装绘图事件过滤器ui->widget0404->installEventFilter(this);ui->widget0405->installEventFilter(this);
}Widget::~Widget()
{delete ui;
}/*
QMenu menu;
QAction *at = actions[0]; // Assumes actions is not empty
foreach (QAction *a, actions)menu.addAction(a);
menu.exec(pos, at);
*/
//鼠标点击事件
void Widget::mousePressEvent(QMouseEvent *event)
{//鼠标右键按下if(event->button() == Qt::RightButton){qDebug() << "right button pressed";//执行menuQuitmenuQuit->exec(QCursor::pos());}//鼠标左键按下if(event->button() == Qt::LeftButton){//qDebug() << "left button pressed";//qDebug() << event->globalPos();//计算偏移值mOffset = event->globalPos() - this->pos();}
}
//鼠标移动事件
void Widget::mouseMoveEvent(QMouseEvent *event)
{this->move(event->globalPos() - mOffset);
}
//事件过滤器函数
bool Widget::eventFilter(QObject *watched, QEvent *event)
{if(watched == ui->widget0404 && event->type() == QEvent::Paint){drawTempLineHigh();return true;}if(watched == ui->widget0405 && event->type() == QEvent::Paint){drawTempLineLow();return true;}return QWidget::eventFilter(watched, event);
}/*
//天气JSON信息解析函数
void Widget::parseWeatherJsonData(QByteArray rawData)
{QJsonDocument jsonObj = QJsonDocument::fromJson(rawData);if(!jsonObj.isNull() && jsonObj.isObject()){QJsonObject objRoot = jsonObj.object();//解析日期QString date = objRoot["date"].toString();QString week = objRoot["week"].toString();ui->labelDate->setText(date + " " + week);//解析当前温度QString cityName = objRoot["city"].toString();ui->labelCity->setText(cityName + "市");//解析当前温度QString currentTemp = objRoot["tem"].toString();ui->labelTemp->setText(currentTemp + "℃");//解析温度范围QString Temp1 = objRoot["tem1"].toString();QString Temp2 = objRoot["tem2"].toString();ui->labelWeatherRange->setText(Temp2 + "℃-" + Temp1 + "℃");//解析天气类型ui->labelWeather->setText(objRoot["wea"].toString());ui->labelWeatherIcon->setPixmap(mTypeMap[objRoot["wea"].toString()]);//解析感冒指数ui->labelGanMao->setText(objRoot["air_tips"].toString());//自动换行ui->labelGanMao->setWordWrap(true);//解析风向ui->labelFXType->setText(objRoot["win"].toString());//解析风力ui->labelFXType_2->setText(objRoot["win_speed"].toString());//解析PM2.5ui->labelPM25Data->setText(objRoot["air_pm25"].toString());//解析湿度ui->labelHumData->setText(objRoot["humidity"].toString());//空气质量ui->labelAirQuantData->setText(objRoot["air_level"].toString());}
}
*///读http收到的内容槽函数
void Widget::readHttpReply(QNetworkReply *reply)
{//定义状态码int resCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();qDebug() << resCode;//状态码判断if(reply->error() == QNetworkReply::NoError && resCode == 200){QByteArray data = reply->readAll();//大多数服务器返回的字符编码是utf-8parseWeatherJsonDataNew(data);//打印测试返回天气数据//qDebug() << QString::fromUtf8(data);}else{//打印状态信息qDebug() << "请求失败:" << reply->errorString();//弹窗提示QMessageBox mes;mes.setWindowTitle("错误");mes.setText("网络请求失败");mes.setStyleSheet("QPushButton {color:red}");mes.setStandardButtons(QMessageBox::Ok);mes.exec();}
}
//搜索按钮槽函数实现
void Widget::on_pushButtonSearch_clicked()
{QString cityNameFromUser = ui->lineEditSearch->text();QString cityCode = cityCodeUtils.getCityCodeFromName(cityNameFromUser);if(cityCode != NULL){//URL拼接strUrl += "&cityid=" + cityCode;manager->get(QNetworkRequest(QUrl(strUrl)));}else{//弹窗提示QMessageBox mes;mes.setWindowTitle("错误");mes.setText("请输入正确的城市名称");mes.setStyleSheet("QPushButton {color:red}");mes.setStandardButtons(QMessageBox::Ok);mes.exec();}
}
//天气JSON信息解析函数
void Widget::parseWeatherJsonDataNew(QByteArray rawData)
{QJsonDocument jsonDoc = QJsonDocument::fromJson(rawData);if(!jsonDoc.isNull() && jsonDoc.isObject()){QJsonObject jsonRoot = jsonDoc.object();days[0].mCity = jsonRoot["city"].toString();days[0].mPm25 = jsonRoot["aqi"].toObject()["pm25"].toString();if(jsonRoot.contains("data") && jsonRoot["data"].isArray()){QJsonArray weaArray = jsonRoot["data"].toArray();for(int i = 0;i < weaArray.size();i++){QJsonObject obj = weaArray[i].toObject();days[i].mWeek = obj["week"].toString();days[i].mDate = obj["date"].toString();days[i].mWeatherType = obj["wea"].toString();days[i].mTemp = obj["tem"].toString();days[i].mTempLow = obj["tem2"].toString();days[i].mTempHigh = obj["tem1"].toString();days[i].mFx = obj["win"].toArray()[0].toString();days[i].mFl = obj["win_speed"].toString();days[i].mAirq = obj["air_level"].toString();days[i].mTips = obj["air_tips"].toString();days[i].mHu = obj["humidity"].toString();}}}upDateUI();
}void Widget::upDateUI()
{QPixmap pixmap;//解析日期ui->labelDate->setText(days[0].mDate + " " + days[0].mWeek);//解析当前城市ui->labelCity->setText(days[0].mCity + "市");//解析当前温度ui->labelTemp->setText(days[0].mTemp + "℃");//解析温度范围ui->labelWeatherRange->setText(days[0].mTempLow + "℃-" + days[0].mTempHigh + "℃");//解析天气类型ui->labelWeather->setText(days[0].mWeatherType);ui->labelWeatherIcon->setPixmap(mTypeMap[days[0].mWeatherType]);//解析感冒指数ui->labelGanMao->setText(days[0].mTips);//自动换行ui->labelGanMao->setWordWrap(true);//解析风向ui->labelFXType->setText(days[0].mFx);//解析风力ui->labelFL->setText(days[0].mFl);//解析PM2.5ui->labelPM25Data->setText(days[0].mPm25);//解析湿度ui->labelHumData->setText(days[0].mHu);//空气质量ui->labelAirQuantData->setText(days[0].mAirq);ui->labelWeath3->setText(days[3].mWeatherType);ui->labelWeath0->setText(days[0].mWeatherType);//循环刷新七天天气控件for(int i = 0;i < 6;i++){QStringList dayList =days[i].mDate.split("-");mDateList[i]->setText(dayList.at(1) + "-" + dayList.at(2));mWeekList[0]->setText("今天");mWeekList[1]->setText("明天");mWeekList[2]->setText("后天");mWeekList[i]->setText(days[i].mWeek);//晴转多云变成晴,多云转晴变成多云...int index = days[i].mWeatherType.indexOf("转");if(index != -1){pixmap = mTypeMap[days[i].mWeatherType.left(index)];}else{pixmap = mTypeMap[days[i].mWeatherType];}//缩放图片大小和label大小能匹配pixmap = pixmap.scaled(mIconList[i]->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);mIconList[i]->setPixmap(pixmap);mWeaTypeList[i]->setText(days[i].mWeatherType);//去掉"污染"QString airQ = days[i].mAirq;index = airQ.indexOf("污");if(index != -1){mAirqList[i]->setText(airQ.left(index));}else{mAirqList[i]->setText(airQ);}//处理空气质量背景颜色if(airQ == "优"){mAirqList[i]->setStyleSheet("background-color: rgb(85, 170, 0);border-radius: 7px");}if(airQ == "良"){mAirqList[i]->setStyleSheet("background-color: rgb(208,107,39); border-radius: 7px");}if(airQ == "轻度污染"){mAirqList[i]->setStyleSheet("background-color: rgb(255,100,100); border-radius: 7px");}if(airQ == "中度污染"){mAirqList[i]->setStyleSheet("background-color: rgb(255,50,50); border-radius: 7px");}if(airQ == "重度污染"){mAirqList[i]->setStyleSheet("background-color: rgb(255,0,0); border-radius: 7px");}mFxList[i]->setText(days[i].mFx);//去掉"转"index = days[i].mFl.indexOf("转");if(index != -1){mFlList[i]->setText(days[i].mFl.left(index));}else{mFlList[i]->setText(days[i].mFl);}}update();
}
//画最高温度折线
void Widget::drawTempLineHigh()
{QPainter painter(ui->widget0404);painter.setRenderHint(QPainter::Antialiasing,true);painter.setBrush(Qt::yellow);painter.setPen(Qt::yellow);//最高气温平均值int ave = 0;//最高气温总和int sum = 0;//气温偏移值int offset = 0;//组件中心纵坐标int middle = ui->widget0404->height()/2;for(int i = 0;i < 6;i++){sum += days[i].mTempHigh.toInt();}ave = sum / 6;//定义出6个点QPoint points[6];//画6个点for(int i = 0;i < 6;i++){//确定点横纵坐标points[i].setX(mAirqList[i]->x() + mAirqList[i]->width()/2);offset = (days[i].mTempHigh.toInt() - ave)*3;points[i].setY(middle - offset);//画出6个点painter.drawEllipse(points[i],3,3);//画出当天温度painter.drawText(points[i].x() - 5,points[i].y() - 10,days[i].mTempHigh + "°");}//画折线for(int i = 0;i < 5;i++){painter.drawLine(points[i],points[i+1]);}
}
//画最低温度折线
void Widget::drawTempLineLow()
{QPainter painter(ui->widget0405);painter.setRenderHint(QPainter::Antialiasing,true);painter.setBrush(QColor(65, 178, 248));painter.setPen(QColor(65, 178, 248));//最高气温平均值int ave = 0;//最高气温总和int sum = 0;//气温偏移值int offset = 0;//组件中心纵坐标int middle = ui->widget0405->height()/2;for(int i = 0;i < 6;i++){sum += days[i].mTempLow.toInt();}ave = sum / 6;//定义出6个点QPoint points[6];//画6个点for(int i = 0;i < 6;i++){//确定点横纵坐标points[i].setX(mAirqList[i]->x() + mAirqList[i]->width()/2);offset = (days[i].mTempLow.toInt() - ave)*3;points[i].setY(middle - offset);//画出6个点painter.drawEllipse(points[i],3,3);//画出当天温度painter.drawText(points[i].x() - 5,points[i].y() - 10,days[i].mTempLow + "°");}//画折线for(int i = 0;i < 5;i++){painter.drawLine(points[i],points[i+1]);}
}
//回车搜索槽函数实现
void Widget::on_lineEditSearch_returnPressed()
{on_pushButtonSearch_clicked();
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QLabel>
#include <QMenu>
#include <QNetworkReply>
#include <QWidget>
#include "citycodeutils.h"
#include "day.h"QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();
protected://鼠标点击事件void mousePressEvent(QMouseEvent *event);//鼠标移动事件void mouseMoveEvent(QMouseEvent *event);//画图事件过滤器bool eventFilter(QObject *watched, QEvent *event);
public slots://http回复槽函数void readHttpReply(QNetworkReply *reply);
private slots://搜索按钮槽函数实现void on_pushButtonSearch_clicked();//回车搜索槽函数实现void on_lineEditSearch_returnPressed();private:Ui::Widget *ui;//定义menu小控件QMenu *menuQuit;//定义鼠标相对于窗口的偏移值QPoint mOffset;//实例化http回复对象QNetworkReply *reply;//定义URLQString strUrl;//定义网络访问管理员QNetworkAccessManager *manager;//定义城市代码获取对象CityCodeUtils cityCodeUtils;//定义天气和天气图片mapQMap<QString, QString> mTypeMap;//定义七天天气对象数组Day days[7];//定义七天天气组件QListQList<QLabel *> mWeekList;QList<QLabel *> mDateList;QList<QLabel *> mIconList;QList<QLabel *> mWeaTypeList;QList<QLabel *> mAirqList;QList<QLabel *> mFxList;QList<QLabel *> mFlList;//天气JSON信息解析函数//void parseWeatherJsonData(QByteArray rawData);void parseWeatherJsonDataNew(QByteArray rawData);//更新UIvoid upDateUI();//画最高温度折线void drawTempLineHigh();//画最低温度折线void drawTempLineLow();
};
#endif // WIDGET_H

citycodeutils.cpp

#include "citycodeutils.h"#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>CityCodeUtils::CityCodeUtils()
{}
//从cityMap中获取CityCode
QString CityCodeUtils::getCityCodeFromName(QString cityName)
{if(cityMap.isEmpty()){initCityMap();}QMap<QString, QString>::iterator it = cityMap.find(cityName);if(it == cityMap.end()){it = cityMap.find(cityName + "市");if(it == cityMap.end()){it = cityMap.find(cityName + "县");}if(it == cityMap.end()){it = cityMap.find(cityName + "区");}if(it == cityMap.end()){return "";}}return it.value();
}
//初始化CityMap
void CityCodeUtils::initCityMap()
{//打开城市json文件并且读取QFile file(":/citycode.json");file.open(QIODevice::ReadOnly);QByteArray rawData = file.readAll();file.close();//将citycode.json中的json插入到cityMap中QJsonDocument jsonDoc = QJsonDocument::fromJson(rawData);if(jsonDoc.isArray()){QJsonArray cities = jsonDoc.array();for(QJsonValue value : cities){if(value.isObject()){QString cityName = value["city_name"].toString();QString cityCode = value["city_code"].toString();cityMap.insert(cityName,cityCode);}}}
}

citycodeutils.h

#ifndef CITYCODEUTILS_H
#define CITYCODEUTILS_H#include <QMap>class CityCodeUtils
{
public:CityCodeUtils();//定义城市名称代码MapQMap<QString,QString> cityMap = {};//城市代码获取函数QString getCityCodeFromName(QString cityName);//cityMap初始化函数void initCityMap();
};#endif // CITYCODEUTILS_H

day.cpp

#include "day.h"Day::Day()
{}

day.h

#ifndef DAY_H
#define DAY_H#include <QString>class Day
{
public:Day();QString mDate;QString mWeek;QString mCity;QString mTemp;QString mWeatherType;QString mTempLow;QString mTempHigh;QString mTips;QString mFx;QString mFl;QString mPm25;QString mHu;QString mAirq;
};
#endif // DAY_H

citycode.json

//文件太大,自行查找获取,类似以下内容

在这里插入图片描述

项目结构(图标可自行百度阿里矢量图库下载获取)

在这里插入图片描述

http://www.dtcms.com/a/590376.html

相关文章:

  • Vue嵌套(多级)路由
  • 精品网站建设公司互联网产品推广是做什么的
  • 东莞360推广的网站是谁做的云南楚雄医药高等专科学校
  • 学做网站的视频建设银行电商网站
  • 目前网站类型主要包括哪几种江苏营销型网站建设公司
  • 临沂网站开发多少钱wordpress无法发送
  • 信用网站标准化建设模块都有哪些东道设计招聘要求
  • YOLO项目笔记
  • 网站制作合同模板汽车网站flash模板
  • 凡科网做网站能达到什么效果济南网站建设(力推聚搜网络)
  • 网站备案表格样本一个人做的网站做什么好
  • 做个网站好还是做淘宝好品牌推广网站策划设计
  • 启迪网站建设招聘成都景观设计公司有哪些
  • 12306网站建设费用怎么做app下载网站
  • 外设模块学习(18)——5针双轴按键摇杆模块(STM32)
  • 怎么做网站充值网站注册公司需要几个人员
  • 网站掉权重是怎么回事软件开发者模式怎么打开
  • ArrayList底层实现及源码分析
  • 河北建设集团有限公司网站企业公司有哪些
  • HarmonyOS黑马云音乐项目:全场景在线音乐播放的实现与优化
  • 804.唯一的摩尔斯密码词(uthash)
  • 公司做网站域名归谁大学生做兼职上什么网站好
  • 网站分类代码网站建设经营服务合同范本
  • 手机网站设计案例电子商务网站建设个人总结
  • 【算法】--位运算
  • 门户网站的案例分析开发游戏用什么软件
  • 网站建设目标个人博客dwzh-cn 安装wordpress
  • 长沙网站优化步骤哈尔滨网站建设渠道
  • 浏览器打开网站wordpress表情不显示
  • 网站图片都是站外连接对seo小公司做网站推广好不好