• pyqt5 嵌入WEB 并实现qt向web的通信


    最终实现效果:(左边是一个web界面,右边是qt的doubleSpinBox和pushButton)

     

    我的思路是这样的:

            首先建立一个flask Sever 用来接收qt提交的数据并保存在服务器中

            然后web前端轮询的获取储存在服务器中的数据

            (虽然知道轮询方式缺点巨大,但还没有想到好的办法,还请路过的大佬指点)

    项目文件夹:

     

    flask:

    1. from flask import Flask,render_template,url_for,request,jsonify
    2. # template_folder:模板的位置,
    3. # static_folder:静态文件放的位置(图片/css..),默认叫static
    4. # static_url_path:前端寻找静态文件的前缀, 默认叫/static g跟静态文件夹存放的位置名称,不一样
    5. app = Flask(__name__ ,template_folder = 'templates', static_folder='static', static_url_path='/static')
    6. @app.route("/index",methods=['GET']) # 设置路由,允许GET请求
    7. def showIndexHtml():
    8. return render_template("test.html")
    9. @app.route("/postData",methods=['POST'])
    10. def postDataformUI():
    11. global data
    12. data = request.get_json()
    13. return jsonify(msg="ok")
    14. @app.route("/getData",methods=['GET'])
    15. def getDataformFlask():
    16. doubleSpinBoxValue = data["doubleSpinBoxValue"]
    17. return jsonify(doubleSpinBoxValue=doubleSpinBoxValue)
    18. app.run(host="0.0.0.0")

    前端:

    1. HTML>
    2. <html>
    3. <head>
    4. <meta charset="utf-8">
    5. <title>websocket通信客户端title>
    6. <script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js">script>
    7. <script src="https://code.jquery.com/jquery-3.6.0.min.js">script>
    8. head>
    9. <body>
    10. <div id="main" style="width: 100%; height:100%; position: absolute;">div>
    11. <script>
    12. function getNum(url,callback) {
    13. var xmlhttp=new XMLHttpRequest();
    14. // var url="http://127.0.0.1:5000/getData";
    15. var type="GET";//方法
    16. var doubleSpinBoxValue = 0;
    17. xmlhttp.open(type,url,true);//方法,接口,异步
    18. xmlhttp.send();//发送请求
    19. xmlhttp.onreadystatechange=function(){
    20. if(xmlhttp.status==200&&xmlhttp.readyState==4){
    21. var result=JSON.parse(xmlhttp.response);
    22. doubleSpinBoxValue = result.doubleSpinBoxValue;
    23. callback(doubleSpinBoxValue);
    24. console.log(doubleSpinBoxValue, typeof doubleSpinBoxValue)//result即为接口返回给我们的数据具体进行处理可以封装一个方法
    25. }
    26. };
    27. }
    28. function html(){
    29. //在此希望调用获取年龄方法得到小明的年龄
    30. let num=getNum("http://127.0.0.1:5000/getData", function(doubleSpinBoxValue){
    31. var myChart = echarts.init(document.getElementById('main'));
    32. let angle = 0; //角度,用来做简单的动画效果的
    33. let value = doubleSpinBoxValue;
    34. console.log(doubleSpinBoxValue, typeof doubleSpinBoxValue);
    35. option = {
    36. backgroundColor: "#061740",
    37. title: {
    38. text: "{a|" + value + "}{c|%}",
    39. x: "center",
    40. y: "center",
    41. textStyle: {
    42. rich: {
    43. a: {
    44. fontSize: 48,
    45. color: "#29EEF3",
    46. },
    47. c: {
    48. fontSize: 20,
    49. color: "#ffffff",
    50. // padding: [5,0]
    51. },
    52. },
    53. },
    54. },
    55. legend: {
    56. type: "plain",
    57. orient: "vertical",
    58. right: 0,
    59. top: "10%",
    60. align: "auto",
    61. data: [
    62. {
    63. name: "涨价后没吃过",
    64. icon: "circle",
    65. },
    66. {
    67. name: "天天吃",
    68. icon: "circle",
    69. },
    70. {
    71. name: "三五天吃一次",
    72. icon: "circle",
    73. },
    74. {
    75. name: "半个月吃一次",
    76. icon: "circle",
    77. },
    78. ],
    79. textStyle: {
    80. color: "white",
    81. fontSize: 16,
    82. padding: [10, 1, 10, 0],
    83. },
    84. selectedMode: false,
    85. },
    86. series: [
    87. {
    88. name: "ring5",
    89. type: "custom",
    90. coordinateSystem: "none",
    91. renderItem: function (params, api) {
    92. return {
    93. type: "arc",
    94. shape: {
    95. cx: api.getWidth() / 2,
    96. cy: api.getHeight() / 2,
    97. r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.6,
    98. startAngle: ((0 + angle) * Math.PI) / 180,
    99. endAngle: ((90 + angle) * Math.PI) / 180,
    100. },
    101. style: {
    102. stroke: "#0CD3DB",
    103. fill: "transparent",
    104. lineWidth: 1.5,
    105. },
    106. silent: true,
    107. };
    108. },
    109. data: [0],
    110. },
    111. {
    112. name: "ring5",
    113. type: "custom",
    114. coordinateSystem: "none",
    115. renderItem: function (params, api) {
    116. return {
    117. type: "arc",
    118. shape: {
    119. cx: api.getWidth() / 2,
    120. cy: api.getHeight() / 2,
    121. r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.6,
    122. startAngle: ((180 + angle) * Math.PI) / 180,
    123. endAngle: ((270 + angle) * Math.PI) / 180,
    124. },
    125. style: {
    126. stroke: "#0CD3DB",
    127. fill: "transparent",
    128. lineWidth: 1.5,
    129. },
    130. silent: true,
    131. };
    132. },
    133. data: [0],
    134. },
    135. {
    136. name: "ring5",
    137. type: "custom",
    138. coordinateSystem: "none",
    139. renderItem: function (params, api) {
    140. return {
    141. type: "arc",
    142. shape: {
    143. cx: api.getWidth() / 2,
    144. cy: api.getHeight() / 2,
    145. r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.65,
    146. startAngle: ((270 + -angle) * Math.PI) / 180,
    147. endAngle: ((40 + -angle) * Math.PI) / 180,
    148. },
    149. style: {
    150. stroke: "#0CD3DB",
    151. fill: "transparent",
    152. lineWidth: 1.5,
    153. },
    154. silent: true,
    155. };
    156. },
    157. data: [0],
    158. },
    159. {
    160. name: "ring5",
    161. type: "custom",
    162. coordinateSystem: "none",
    163. renderItem: function (params, api) {
    164. return {
    165. type: "arc",
    166. shape: {
    167. cx: api.getWidth() / 2,
    168. cy: api.getHeight() / 2,
    169. r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.65,
    170. startAngle: ((90 + -angle) * Math.PI) / 180,
    171. endAngle: ((220 + -angle) * Math.PI) / 180,
    172. },
    173. style: {
    174. stroke: "#0CD3DB",
    175. fill: "transparent",
    176. lineWidth: 1.5,
    177. },
    178. silent: true,
    179. };
    180. },
    181. data: [0],
    182. },
    183. {
    184. name: "ring5",
    185. type: "custom",
    186. coordinateSystem: "none",
    187. renderItem: function (params, api) {
    188. let x0 = api.getWidth() / 2;
    189. let y0 = api.getHeight() / 2;
    190. let r = (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.65;
    191. let point = getCirlPoint(x0, y0, r, 90 + -angle);
    192. return {
    193. type: "circle",
    194. shape: {
    195. cx: point.x,
    196. cy: point.y,
    197. r: 4,
    198. },
    199. style: {
    200. stroke: "#0CD3DB", //粉
    201. fill: "#0CD3DB",
    202. },
    203. silent: true,
    204. };
    205. },
    206. data: [0],
    207. },
    208. {
    209. name: "ring5", //绿点
    210. type: "custom",
    211. coordinateSystem: "none",
    212. renderItem: function (params, api) {
    213. let x0 = api.getWidth() / 2;
    214. let y0 = api.getHeight() / 2;
    215. let r = (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.65;
    216. let point = getCirlPoint(x0, y0, r, 270 + -angle);
    217. return {
    218. type: "circle",
    219. shape: {
    220. cx: point.x,
    221. cy: point.y,
    222. r: 4,
    223. },
    224. style: {
    225. stroke: "#0CD3DB", //绿
    226. fill: "#0CD3DB",
    227. },
    228. silent: true,
    229. };
    230. },
    231. data: [0],
    232. },
    233. {
    234. name: "吃猪肉频率",
    235. type: "pie",
    236. radius: ["58%", "45%"],
    237. silent: true,
    238. clockwise: true,
    239. startAngle: 90,
    240. z: 0,
    241. zlevel: 0,
    242. label: {
    243. normal: {
    244. position: "center",
    245. },
    246. },
    247. data: [
    248. {
    249. value: value,
    250. name: "",
    251. itemStyle: {
    252. normal: {
    253. color: {
    254. // 完成的圆环的颜色
    255. colorStops: [
    256. {
    257. offset: 0,
    258. color: "#4FADFD", // 0% 处的颜色
    259. },
    260. {
    261. offset: 1,
    262. color: "#28E8FA", // 100% 处的颜色
    263. },
    264. ],
    265. },
    266. },
    267. },
    268. },
    269. {
    270. value: 100 - value,
    271. name: "",
    272. label: {
    273. normal: {
    274. show: false,
    275. },
    276. },
    277. itemStyle: {
    278. normal: {
    279. color: "#173164",
    280. },
    281. },
    282. },
    283. ],
    284. },
    285. {
    286. name: "",
    287. type: "gauge",
    288. radius: "58%",
    289. center: ["50%", "50%"],
    290. startAngle: 0,
    291. endAngle: 359.9,
    292. splitNumber: 8,
    293. hoverAnimation: true,
    294. axisTick: {
    295. show: false,
    296. },
    297. splitLine: {
    298. length: 60,
    299. lineStyle: {
    300. width: 5,
    301. color: "#061740",
    302. },
    303. },
    304. axisLabel: {
    305. show: false,
    306. },
    307. pointer: {
    308. show: false,
    309. },
    310. axisLine: {
    311. lineStyle: {
    312. opacity: 0,
    313. },
    314. },
    315. detail: {
    316. show: false,
    317. },
    318. data: [
    319. {
    320. value: 0,
    321. name: "",
    322. },
    323. ],
    324. },
    325. ],
    326. };
    327. myChart.setOption(option);
    328. //获取圆上面某点的坐标(x0,y0表示坐标,r半径,angle角度)
    329. function getCirlPoint(x0, y0, r, angle) {
    330. let x1 = x0 + r * Math.cos((angle * Math.PI) / 180);
    331. let y1 = y0 + r * Math.sin((angle * Math.PI) / 180);
    332. return {
    333. x: x1,
    334. y: y1,
    335. };
    336. }
    337. function draw() {
    338. angle = angle + 3;
    339. myChart.setOption(option, true);
    340. //window.requestAnimationFrame(draw);
    341. }
    342. setInterval(function () {
    343. //用setInterval做动画感觉有问题
    344. draw();
    345. }, 100);
    346. });
    347. }
    348. function funcTest(){
    349. //每隔3秒执行一次timelyFun方法
    350. window.setInterval("html()",3000);
    351. }
    352. window.onload = funcTest;
    353. script>
    354. body>
    355. html>

    pyqt

    1. from PyQt5.Qt import *
    2. from resource.home import Ui_MainWindow
    3. from PyQt5.QtCore import Qt
    4. from PyQt5 import QtCore,QtGui
    5. from PyQt5.QtWidgets import QApplication
    6. from PyQt5.QtWebEngineWidgets import *
    7. import sys,threading,requests,json
    8. class homePane(QMainWindow, Ui_MainWindow):
    9. def __init__(self, parent=None, *args, **kwargs):
    10. self.app = QApplication(sys.argv)
    11. super().__init__(parent, *args, **kwargs)
    12. self.setAttribute(Qt.WA_StyledBackground, True)
    13. self.setupUi(self)
    14. self.setWindowTitle("WEBTest")
    15. icon = QtGui.QIcon()
    16. icon.addPixmap(QtGui.QPixmap("resource/images/webIcon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
    17. self.setWindowIcon(icon)
    18. self.setIconSize(QtCore.QSize(40, 40))
    19. # 设置按钮图标
    20. icon1 = QtGui.QIcon()
    21. icon1.addPixmap(QtGui.QPixmap("resource/images/保存.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
    22. self.pushButton.setIcon(icon1)
    23. self.pushButton.setIconSize(QtCore.QSize(30, 30))
    24. self.doubleSpinBox.setStyleSheet(
    25. "QAbstractSpinBox{background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(0, 38, 200, 255), stop:1 rgba(255, 255, 255, 255));color: rgb(255, 255, 255);font: 16pt 'Arial';border-radius:8px;}"
    26. "QAbstractSpinBox::up-button{subcontrol-origin: padding;subcontrol-position: center right; border-image: url('resource/images/向右.png');width:40px;height:40px;}"
    27. "QAbstractSpinBox::down-button{subcontrol-origin: padding;subcontrol-position: center left;border-image: url('resource/images/向左.png');width:40px;height:40px;}"
    28. "QAbstractSpinBox::up-button:pressed{subcontrol-origin: padding;subcontrol-position: center right;background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(0, 81, 200, 255), stop:1 rgba(255, 255, 255, 255));}"
    29. "QAbstractSpinBox::down-button:pressed{subcontrol-origin: padding;subcontrol-position: center left;background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(0, 81, 200, 255), stop:1 rgba(255, 255, 255, 255));}"
    30. )
    31. self.browser = QWebEngineView()
    32. # 加载外部的web界面
    33. self.browser.load(QUrl('http://127.0.0.1:5000/index'))
    34. self.scrollArea.setWidget(self.browser)
    35. def saveNum(self):
    36. doubleSpinBoxValue = self.doubleSpinBox.value() # 获取doubleSpinBox的值
    37. postData = json.dumps({'doubleSpinBoxValue': doubleSpinBoxValue})
    38. headers = {"Content-type": "application/json", "Accept": "*/*"}
    39. r = requests.post("http://127.0.0.1:5000/postData", data=postData, headers=headers)
    40. print(r.text)
    41. if __name__ == '__main__':
    42. app = QApplication(sys.argv)
    43. window = homePane()
    44. window.show()
    45. sys.exit(app.exec())

    UI(home.py)

    1. # -*- coding: utf-8 -*-
    2. # Form implementation generated from reading ui file 'home.ui'
    3. #
    4. # Created by: PyQt5 UI code generator 5.15.6
    5. #
    6. # WARNING: Any manual changes made to this file will be lost when pyuic5 is
    7. # run again. Do not edit this file unless you know what you are doing.
    8. from PyQt5 import QtCore, QtGui, QtWidgets
    9. class Ui_MainWindow(object):
    10. def setupUi(self, MainWindow):
    11. MainWindow.setObjectName("MainWindow")
    12. MainWindow.resize(818, 622)
    13. self.centralwidget = QtWidgets.QWidget(MainWindow)
    14. self.centralwidget.setObjectName("centralwidget")
    15. self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
    16. self.horizontalLayout.setObjectName("horizontalLayout")
    17. self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)
    18. self.scrollArea.setStyleSheet("border:3px solid rgb(0, 0, 0);\n"
    19. "border-radius:8px;")
    20. self.scrollArea.setWidgetResizable(True)
    21. self.scrollArea.setObjectName("scrollArea")
    22. self.scrollAreaWidgetContents = QtWidgets.QWidget()
    23. self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 590, 553))
    24. self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
    25. self.scrollArea.setWidget(self.scrollAreaWidgetContents)
    26. self.horizontalLayout.addWidget(self.scrollArea)
    27. self.widget_2 = QtWidgets.QWidget(self.centralwidget)
    28. self.widget_2.setObjectName("widget_2")
    29. self.verticalLayout = QtWidgets.QVBoxLayout(self.widget_2)
    30. self.verticalLayout.setObjectName("verticalLayout")
    31. self.doubleSpinBox = QtWidgets.QDoubleSpinBox(self.widget_2)
    32. self.doubleSpinBox.setMinimumSize(QtCore.QSize(100, 40))
    33. self.doubleSpinBox.setStyleSheet("QAbstractSpinBox{\n"
    34. " background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(0, 38, 200, 255), stop:1 rgba(255, 255, 255, 255));\n"
    35. " color: rgb(255, 255, 255);\n"
    36. " font: 16pt \"Arial\";\n"
    37. "border-radius:8px;\n"
    38. "}\n"
    39. "QAbstractSpinBox::up-button{\n"
    40. " subcontrol-origin: padding;\n"
    41. " subcontrol-position: center right;\n"
    42. " border-image: url(:/police_classifcation/images/向右.png);\n"
    43. "width:40px;\n"
    44. "height:40px;\n"
    45. "}\n"
    46. "QAbstractSpinBox::down-button{\n"
    47. " image: url(:/new/prefix1/picture/sl1.png);\n"
    48. " subcontrol-origin: padding;\n"
    49. " subcontrol-position: center left;\n"
    50. " border-image: url(:/police_classifcation/images/向左.png);\n"
    51. "width:40px;\n"
    52. "height:40px;\n"
    53. "}\n"
    54. "QAbstractSpinBox::up-button:pressed{\n"
    55. " subcontrol-origin: padding;\n"
    56. " subcontrol-position: center right;\n"
    57. " background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(0, 81, 200, 255), stop:1 rgba(255, 255, 255, 255));\n"
    58. "}\n"
    59. "QAbstractSpinBox::down-button:pressed{\n"
    60. " subcontrol-origin: padding;\n"
    61. " subcontrol-position: center left;\n"
    62. " background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(0, 81, 200, 255), stop:1 rgba(255, 255, 255, 255));\n"
    63. "}")
    64. self.doubleSpinBox.setMaximum(100.0)
    65. self.doubleSpinBox.setProperty("value", 90.0)
    66. self.doubleSpinBox.setObjectName("doubleSpinBox")
    67. self.verticalLayout.addWidget(self.doubleSpinBox)
    68. self.pushButton = QtWidgets.QPushButton(self.widget_2)
    69. self.pushButton.setMinimumSize(QtCore.QSize(100, 40))
    70. self.pushButton.setStyleSheet("QPushButton {\n"
    71. "background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(0, 38, 200, 255), stop:1 rgba(255, 255, 255, 255));\n"
    72. "border-radius:8px;\n"
    73. "color:white;\n"
    74. "spacing:20px;\n"
    75. " font: 14pt \"楷体\";\n"
    76. "}\n"
    77. "QPushButton:hover {\n"
    78. " background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(147, 33, 250, 255), stop:1 rgba(255, 255, 255, 255));\n"
    79. "}\n"
    80. "QPushButton:pressed {\n"
    81. "background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(250, 33, 80, 255), stop:1 rgba(255, 255, 255, 255));\n"
    82. "}\n"
    83. "QPushButton:disabled{\n"
    84. " background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255));\n"
    85. "}")
    86. self.pushButton.setText("")
    87. self.pushButton.setObjectName("pushButton")
    88. self.verticalLayout.addWidget(self.pushButton)
    89. self.horizontalLayout.addWidget(self.widget_2)
    90. self.horizontalLayout.setStretch(0, 3)
    91. self.horizontalLayout.setStretch(1, 1)
    92. MainWindow.setCentralWidget(self.centralwidget)
    93. self.menubar = QtWidgets.QMenuBar(MainWindow)
    94. self.menubar.setGeometry(QtCore.QRect(0, 0, 818, 23))
    95. self.menubar.setObjectName("menubar")
    96. MainWindow.setMenuBar(self.menubar)
    97. self.statusbar = QtWidgets.QStatusBar(MainWindow)
    98. self.statusbar.setObjectName("statusbar")
    99. MainWindow.setStatusBar(self.statusbar)
    100. self.retranslateUi(MainWindow)
    101. self.pushButton.clicked.connect(MainWindow.saveNum) # type: ignore
    102. QtCore.QMetaObject.connectSlotsByName(MainWindow)
    103. def retranslateUi(self, MainWindow):
    104. _translate = QtCore.QCoreApplication.translate
    105. MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

  • 相关阅读:
    从零开始Blazor Server(11)--编辑用户
    linux下的gdb调试器
    magento1.x多域名部署可行性方案
    HTML页面在iPhone中电话号码自动检测带来的布局问题
    【工具】idea 设置自动渲染注释
    Innodb底层原理与Mysql日志机制
    Java float和double精度范围大小(二进制存储角度剖析)
    树莓派4b编译FFmpeg支持硬件编解码
    使C#语言编程更加高效的伎俩
    dubbo-admin 无法显示元数据
  • 原文地址:https://blog.csdn.net/ChaoChao66666/article/details/126907693