From 409404e11240c46193b8b6f24e123c1defca3afa Mon Sep 17 00:00:00 2001 From: "ZHANGXUXU\\95193" <951937200@qq.com> Date: Wed, 29 May 2024 16:08:00 +0800 Subject: [PATCH] =?UTF-8?q?0529=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Static/Main.qss | 6 +- Static/PA块信息表.xlsx | Bin 0 -> 25312 bytes Static/modbus映射表.xlsx | Bin 0 -> 39461 bytes UI/AreaTabWidget.py | 8 +- UI/BlockParameterManageWidget.py | 112 ++++++++++++ UI/BlockParameterModel.py | 210 ++++++++++++++++++++++ UI/BlockParameterView.py | 112 ++++++++++++ UI/DeviceDialogWidget.py | 2 +- UI/DeviceWidget.py | 2 +- UI/MainWindow.py | 46 ++++- UI/RightAreaWidget.py | 5 +- UI/SearchAddressWidget.py | 80 +++++++++ bin.py | 8 +- model/ClientModel/Client.py | 3 +- protocol/BatterySerial/BatteryProtocol.py | 3 +- utils/DBModels/DeviceModels.py | 2 - utils/DBModels/DeviceParModels.py | 89 +++++++++ utils/DBModels/InitParameterDB.py | 19 ++ 18 files changed, 679 insertions(+), 28 deletions(-) create mode 100644 Static/PA块信息表.xlsx create mode 100644 Static/modbus映射表.xlsx create mode 100644 UI/BlockParameterManageWidget.py create mode 100644 UI/BlockParameterModel.py create mode 100644 UI/BlockParameterView.py create mode 100644 UI/SearchAddressWidget.py create mode 100644 utils/DBModels/DeviceParModels.py create mode 100644 utils/DBModels/InitParameterDB.py diff --git a/Static/Main.qss b/Static/Main.qss index b9c0488..961cdea 100644 --- a/Static/Main.qss +++ b/Static/Main.qss @@ -101,7 +101,7 @@ QDockWidget::title{ } -QPushButton#startProtocolBtn, QPushButton#switchBtn, QPushButton#switchTouchBtn{ +QPushButton#startProtocolBtn, QPushButton#switchBtn, QPushButton#switchTouchBtn, QPushButton#deviceParameterManageBtn{ font-size: 25px; @@ -111,7 +111,7 @@ QPushButton#startProtocolBtn, QPushButton#switchBtn, QPushButton#switchTouchBtn{ } -QPushButton#startProtocolBtn:hover, QPushButton#switchBtn:hover, QPushButton#switchTouchBtn::hover{ +QPushButton#startProtocolBtn:hover, QPushButton#switchBtn:hover, QPushButton#switchTouchBtn:hover, QPushButton#deviceParameterManageBtn:hover{ font-size: 25px; @@ -125,7 +125,7 @@ QPushButton#startProtocolBtn:hover, QPushButton#switchBtn:hover, QPushButton#swi } -QPushButton#startProtocolBtn:checked, QPushButton#switchBtn:checked, QPushButton#switchTouchBtn:checked{ +QPushButton#startProtocolBtn:checked, QPushButton#switchBtn:checked, QPushButton#switchTouchBtn:checked, QPushButton#deviceParameterManageBtn:checked{ font-size: 25px; diff --git a/Static/PA块信息表.xlsx b/Static/PA块信息表.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..942cfd1e0372a4382a702889a54b7bc0014bb755 GIT binary patch literal 25312 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 self.columnCount(): + print("列索引超出范围") + return + for row in range(self.rowCount()): + self.datas[row][column] = value + self.table.proxy.invalidate() + # self.layoutChanged.emit() # 通知视图数据已更改 + # self.dataChanged.emit() + + def remove_row(self, row): + self.datas.pop(row) + self.checkList = ['UnChecked'] * len(self.datas) + self.table.proxy.invalidate() + + def rowCount(self, parent: QModelIndex = ...) -> int: + if len(self.datas) > 0: + return len(self.datas) + return 0 + + def columnCount(self, parent: QModelIndex = ...) -> int: + return len(self.header) + + def data(self, QModelIndex, role=None): + # print(Qt.__dict__.items()) + if role == Qt.TextAlignmentRole: + return Qt.AlignCenter + if not QModelIndex.isValid(): + print("行或者列有问题") + return QVariant() + + if role == Qt.TextColorRole: + return QtGui.QColor('#1A1A1A') + + if role == Qt.DisplayRole or role == Qt.EditRole: + if QModelIndex.row() in self.editableList or 'w' in self.datas[QModelIndex.row()][4]: + return self.datas[QModelIndex.row()][QModelIndex.column()] + if role != Qt.DisplayRole: + return QVariant() + + + return self.datas[QModelIndex.row()][QModelIndex.column()] + + def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> typing.Any: # 表头 + if role != Qt.DisplayRole: + return None + + if role == Qt.SizeHintRole: + # print(self.datas[QModelIndex.row()][QModelIndex.column()].find('\r\n')) + return QSize(500, 500) + + if orientation == Qt.Horizontal: + return self.header[section] + + # if orientation == Qt.Vertical: + # return str(section + 1) + + def setData(self, index, value, role): + row = index.row() + col = index.column() + if role == Qt.EditRole: + self.datas[row][col] = value + return True + return True + + def flags(self, index): + # if index.column() == 0: + # return Qt.ItemIsEnabled | Qt.ItemIsUserCheckable + if index.row() in self.editableList and index.column() or index.column() == 6: + return Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsEditable + + + if 'w' in self.datas[index.row()][4] and index.column() == 5: + return Qt.ItemIsEnabled | Qt.ItemIsEditable + + return Qt.ItemIsEnabled + + def dragMoveEvent(self, event): + event.setDropAction(QtCore.Qt.MoveAction) + event.accept() + + def moveRow(self, sourceParent: QModelIndex, sourceRow: int, destinationParent: QModelIndex, + destinationChild: int) -> bool: + if self.datas[destinationChild] == self.datas[sourceRow]: + return + self.datas[sourceRow], self.datas[destinationChild] = self.datas[destinationChild], self.datas[sourceRow] + self.table.proxy.invalidate() + + +class VarButtonDelegate(QItemDelegate): + """该类用于向单元格中添加按钮 任务表格""" + def __init__(self, parent=None): + super(VarButtonDelegate, self).__init__(parent) + + def paint(self, painter, option, index): + if not self.parent().indexWidget(index): + button1 = QPushButton( + qtawesome.icon('fa.play', color='#1fbb6f'), + "", + self.parent() + ) + + if 'w' not in self.parent().model.datas[index.row()][4]: + return + + + button1.index = [index.row(), index.column()] + + parameEditline = QLineEdit() + + boxLayout = QHBoxLayout() + boxLayout.addWidget(parameEditline) + boxLayout.addWidget(button1) + + button1.clicked.connect(lambda: self.startAction(parameEditline)) + + boxLayout.setContentsMargins(2, 0, 0, 2) + boxLayout.setAlignment(Qt.AlignCenter) + widget = QWidget() + widget.setLayout(boxLayout) + self.parent().setIndexWidget( + index, + widget + ) + + + def startAction(self, parameEditline): + sender = self.sender() + model = self.parent().model + # value = model.datas[sender.index[0]][sender.index[1]] + value = parameEditline.text() + pattern = re.compile(r'[^0-9\.-]+') + if not value or re.findall(pattern, str(value)): + reply = QMessageBox.question(self.parent(), + '警告', + "请输入强制值或数字", + QMessageBox.Yes) + return + + +class ComboBoxDelegate(QStyledItemDelegate): + def __init__(self, parent=None): + super(ComboBoxDelegate, self).__init__(parent) + + def createEditor(self, parent, option, index): + # 仅在第二列第二行创建编辑器 + if index.row() == 5 and index.column() == 5: + comboBox = QComboBox(parent) + comboBox.addItems(["非服务", "手动初始化", "本地超驰", '手动', '自动', '级联', '远程级联', '远程输出']) + return comboBox + else: + return super().createEditor(parent, option, index) + + def setEditorData(self, editor, index): + if index.row() == 5 and index.column() == 5: + # value = index.model().data(index, Qt.EditRole) + value = "非服务" + if value: + editor.setCurrentText(value) + else: + super().setEditorData(editor, index) + + def setModelData(self, editor, model, index): + if index.row() == 5 and index.column() == 5: + model.setData(index, editor.currentText(), Qt.EditRole) + else: + super().setModelData(editor, model, index) + + def updateEditorGeometry(self, editor, option, index): + editor.setGeometry(option.rect) diff --git a/UI/BlockParameterView.py b/UI/BlockParameterView.py new file mode 100644 index 0000000..14e45ee --- /dev/null +++ b/UI/BlockParameterView.py @@ -0,0 +1,112 @@ +from PyQt5 import QtCore +from PyQt5.QtGui import QTextDocument +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import QHeaderView, QAbstractItemView, QTableView, QWidget, QDesktopWidget +from UI.BlockParameterModel import VarTableModel, VarButtonDelegate, ComboBoxDelegate + +from utils.DBModels.DeviceParModels import * + +class ParamsVHeader(QHeaderView): + def __init__(self, parent, datas): + super().__init__(Qt.Vertical, parent) + self.datas = datas + + def resizeEvent(self, event): + """Resize table as a whole, need this to enable resizing""" + super(QHeaderView, self).resizeEvent(event) + + for index, content in enumerate(self.datas): + self.setSectionResizeMode(index, QHeaderView.Fixed) + self.resizeSection(index, 50 * (content[2].count('\r\n') + 1)) + + return + + +class VarTableView(QTableView): + def __init__(self, parent=None): + super(VarTableView, self).__init__(parent) + self.parent = parent + self.setHeader() + self.setupUi() + + def setHeader(self): + self.setItemDelegateForColumn(6, VarButtonDelegate(self)) + self.setItemDelegateForColumn(5, ComboBoxDelegate(self)) + + self.model = VarTableModel(['相对索引', '参数名', '描述', '数据类型', '访问', '当前值', '输入值'], [], table = self) + + def setupUi(self): + self.setShowGrid(True) + self.setAlternatingRowColors(True) + self.setSelectionBehavior(QAbstractItemView.SelectRows) + + + #设置单元格宽度比例 + self.header = self.horizontalHeader() + self.header.setSectionResizeMode(QHeaderView.Interactive) + self.header.setStretchLastSection(True) + + self.proxy = QtCore.QSortFilterProxyModel(self) + # # self.parameTableView.proxy = self.proxy + self.proxy.setSourceModel(self.model) + + self.setModel(self.proxy) + self.setCustomColumnWidths([1, 3, 9, 2, 2, 2, 2]) + + + # self.header.checkClicked.connect(self.model.headerClick) + # self.setHorizontalHeader(self.header) + # self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + + # self.header.setSectionResizeMode(0, QHeaderView.Fixed) + # self.header.resizeSection(0, 70) + def setCustomColumnWidths(self, ratios): + # 计算总比例 + totalRatio = sum(ratios) + # 获取窗口宽度 + screen = QDesktopWidget().screenGeometry() + width = screen.width() - 80 + + # 根据比例设置每列的宽度 + for i, ratio in enumerate(ratios): + columnWidth = int(width * (ratio / totalRatio)) + self.setColumnWidth(i, columnWidth) + + + + +class PressureTBlockView(VarTableView): + def __init__(self, datas = None): + super().__init__() + self.datas = datas + self.initUI() + + + def initUI(self): + if not self.datas: + self.datas = PressureTranslationBlock.getallParame() + for index, data in enumerate(self.datas): + desc = data[2].replace('\r\n', '').replace('\n', '') + lines = [desc[i:i+50] + "\r\n" for i in range(0, len(desc), 50)] + # 合并列表为一个字符串,移除最后一个换行符 + result = "".join(lines).rstrip("\r\n") + data[2] = result + data = data + ['', '', ''] + self.model.append_data(data) + self.setVerticalHeader(ParamsVHeader(self, self.model.datas)) + +class AIFunctionBlockView(PressureTBlockView): + def __init__(self): + self.datas = AIFunctionBlock.getallParame() + super().__init__(self.datas) + + + + +class PhysicalBlockView(PressureTBlockView): + def __init__(self): + self.datas = PhysicalBlock.getallParame() + super().__init__(self.datas) + + + \ No newline at end of file diff --git a/UI/DeviceDialogWidget.py b/UI/DeviceDialogWidget.py index 6f64af5..26bfe7b 100644 --- a/UI/DeviceDialogWidget.py +++ b/UI/DeviceDialogWidget.py @@ -27,7 +27,7 @@ from utils.DBModels.DeviceModels import DeviceDB class DeviceDialog(QDialog): BORDER_WIDTH = 5 #设圆角 - def __init__(self,dataTypeAndModel,parent=None): + def __init__(self,dataTypeAndModel = None, parent=None): super().__init__(parent) self.dataTypeAndModel = dataTypeAndModel self.initUI() diff --git a/UI/DeviceWidget.py b/UI/DeviceWidget.py index 34fdf9c..b808487 100644 --- a/UI/DeviceWidget.py +++ b/UI/DeviceWidget.py @@ -12,7 +12,7 @@ from utils.DBModels.BaseModel import * from UI.AreaTabWidget import AreaTabWidget from utils.DBModels.DeviceModels import DeviceDB from model.ProjectModel.DeviceManage import DevicesManange -from UI.DeviceDialogWidget import DeviceDialog + from PyQt5.QtWidgets import QApplication, QStyleOptionTab, QTabBar, QWidget from PyQt5.QtGui import QPainter, QPen, QColor, QPainterPath, QPolygonF, QFontMetrics, QTextOption, QFont diff --git a/UI/MainWindow.py b/UI/MainWindow.py index 86495e6..5c91515 100644 --- a/UI/MainWindow.py +++ b/UI/MainWindow.py @@ -1,4 +1,4 @@ -import os + import sys import time import win32con @@ -7,7 +7,7 @@ import win32process import subprocess import qtawesome -from PyQt5.QtWidgets import QApplication, QPushButton, QMainWindow, QDockWidget, QToolBar, QAction, QTabWidget, QGridLayout, QWidget, QHBoxLayout, QStackedWidget\ +from PyQt5.QtWidgets import QApplication, QPushButton, QMainWindow, QDockWidget, QWidget, QHBoxLayout, QStackedWidget\ ,QVBoxLayout, QProgressBar, QLabel from PyQt5.QtCore import Qt, QTimer, QSize from PyQt5.QtGui import QIcon, QWindow, QPixmap @@ -15,17 +15,20 @@ from utils.DBModels.BaseModel import * from model.ClientModel.Client import Client from UI.DeviceWidget import DeviceTab from model.ProjectModel.DeviceManage import DevicesManange +from utils.DBModels.InitParameterDB import InitParameterDB from protocol.BatterySerial.BatteryProtocol import BatteryManange +from UI.BlockParameterManageWidget import BlockParameterManageWidget import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QProgressBar, QVBoxLayout, QWidget -from PyQt5.QtCore import Qt, QRect, QSize -from PyQt5.QtGui import QPainter, QFont, QColor - +from PyQt5.QtCore import Qt, QSize +from PyQt5.QtGui import QPainter, QFont from utils import Globals + + class CustomProgressBar(QProgressBar): def __init__(self, parent=None): super().__init__(parent) @@ -68,9 +71,11 @@ def getHwndByPid(pid): class MainWindow(QWidget): def __init__(self): super().__init__() + InitParameterDB() self.setObjectName("MainWindow") self.devicesManange = DevicesManange() self.batteryManange = BatteryManange() + self.blockParameterManageWidget = BlockParameterManageWidget() self.process = None self.initUI() @@ -103,6 +108,13 @@ class MainWindow(QWidget): self.switchBtn.setCheckable(True) self.switchBtn.clicked.connect(self.switchWidget) + self.deviceParameterManageBtn = QPushButton('设备参数管理') + self.deviceParameterManageBtn.setObjectName('deviceParameterManageBtn') + self.deviceParameterManageBtn.setIcon(qtawesome.icon('fa.gears', color='#1fbb6f')) + self.deviceParameterManageBtn.setIconSize(QSize(25, 25)) + self.deviceParameterManageBtn.setCheckable(True) + self.deviceParameterManageBtn.clicked.connect(self.switchDeviceParManageWidget) + self.batteryProBar = CustomProgressBar() self.batteryProBar.setRange(0, 100) @@ -112,7 +124,7 @@ class MainWindow(QWidget): self.switchTouchBtn = QPushButton("触控模式") self.switchTouchBtn.setIconSize(QSize(25, 25)) self.switchTouchBtn.setObjectName('switchTouchBtn') - self.switchTouchBtn.setIcon(qtawesome.icon('fa.keyboard-o', color='#1fbb6f')) + self.switchTouchBtn.setIcon(qtawesome.icon('fa.hand-pointer-o', color='#1fbb6f')) self.switchTouchBtn.clicked.connect(self.switchTouchMode) self.switchTouchBtn.setCheckable(True) @@ -140,6 +152,7 @@ class MainWindow(QWidget): toolbarLayout.addWidget(self.startProtocolBtn, 1) toolbarLayout.addWidget(self.switchBtn, 1) toolbarLayout.addWidget(self.switchTouchBtn, 1) + toolbarLayout.addWidget(self.deviceParameterManageBtn, 1) toolbarLayout.addWidget(QWidget(), 20) # toolbarLayout.addWidget(QLabel('电量:'), 1) toolbarLayout.addWidget(self.batteryProBar, 1) @@ -177,6 +190,7 @@ class MainWindow(QWidget): self.stackWidget.addWidget(self.upperWidget) self.stackWidget.addWidget(QWidget()) + self.stackWidget.addWidget(self.blockParameterManageWidget) self.mainLayout = QVBoxLayout(self) self.mainLayout.addLayout(toolbarLayout, 1) @@ -250,9 +264,10 @@ class MainWindow(QWidget): # self.capacity = capacity # mAH # self.cappercent = cappercent # 百分比% # self.state = state # 充放电状态 - result = self.batteryManange.readBatteryInfo() - self.batteryProBar.setValue(result.cappercent) - self.batteryStateLabel.setText(result.chargingStatus) + pass + # result = self.batteryManange.readBatteryInfo() + # self.batteryProBar.setValue(result.cappercent) + # self.batteryStateLabel.setText(result.chargingStatus) @@ -277,6 +292,17 @@ class MainWindow(QWidget): self.switchBtn.setText('通讯组态') # self.switchBtn.setIcon(QIcon(':/static/newH.png')) + + def switchDeviceParManageWidget(self): + if self.deviceParameterManageBtn.isChecked(): + self.stackWidget.setCurrentIndex(2) + self.deviceParameterManageBtn.setText('变量读写') + self.deviceParameterManageBtn.setIcon(qtawesome.icon('fa.pencil-square-o', color='#1fbb6f')) + + else: + self.stackWidget.setCurrentIndex(0) + self.deviceParameterManageBtn.setText('设备参数管理') + self.deviceParameterManageBtn.setIcon(qtawesome.icon('fa.gears', color='#1fbb6f')) def showLowerWidget(self, process): @@ -310,9 +336,11 @@ class MainWindow(QWidget): def switchTouchMode(self): if self.switchTouchBtn.isChecked(): Globals.setValue('_touchMode', 1) + self.switchTouchBtn.setIcon(qtawesome.icon('fa.keyboard-o', color='#1fbb6f')) self.switchTouchBtn.setText('键盘模式') else: Globals.setValue('_touchMode', 0) + self.switchTouchBtn.setIcon(qtawesome.icon('fa.hand-pointer-o', color='#1fbb6f')) self.switchTouchBtn.setText('触控模式') def toggleMaximize(self): diff --git a/UI/RightAreaWidget.py b/UI/RightAreaWidget.py index 0504cc3..628900e 100644 --- a/UI/RightAreaWidget.py +++ b/UI/RightAreaWidget.py @@ -1,8 +1,7 @@ import re -from PyQt5.QtWidgets import QApplication, QMainWindow, QTabWidget, QWidget, QVBoxLayout, QLabel, QPushButton, QLayout, \ - QHBoxLayout, QComboBox, QLineEdit, QSpacerItem, QSizePolicy, QGridLayout, QMessageBox, QSplitter, QFrame, QRadioButton -from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton, \ + QHBoxLayout, QMessageBox, QSplitter, QRadioButton from UI.SoftKeyBoardEdit import SoftKeyBoardEdit diff --git a/UI/SearchAddressWidget.py b/UI/SearchAddressWidget.py new file mode 100644 index 0000000..511608a --- /dev/null +++ b/UI/SearchAddressWidget.py @@ -0,0 +1,80 @@ +from UI.DeviceDialogWidget import DeviceDialog +import sys +import re +import random +from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5.QtCore import Qt, QTimer +from PyQt5.Qt import * + +from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, \ + QApplication, QLineEdit, QWidget, QTableWidget, QSplitter,QVBoxLayout,QPushButton, QProgressBar, QTableWidgetItem, QMessageBox +from PyQt5.QtWidgets import QDialog + +class SearchAddressWidget(QWidget): + def __init__(self, deviceAddressEdit): + super().__init__() + self.selected_value = None + self.deviceAddressEdit = deviceAddressEdit + self.initUI() + + def initUI(self): + self.resize(800, 500) + self.setObjectName('deviceDialog') + self.addressTabWidget = QTableWidget() + self.addressTabWidget.setRowCount(10) + self.addressTabWidget.setColumnCount(1) + + self.addressTabWidget.setShowGrid(False) #隐藏网格线 + self.addressTabWidget.horizontalHeader().setVisible(False) # 隐藏水平表头 + self.addressTabWidget.verticalHeader().setVisible(False) # 隐藏垂直表头 + self.header = self.addressTabWidget.horizontalHeader() + self.header.setStretchLastSection(True) #设置最后一列顶格 + self.addressTabWidget.setFocusPolicy(Qt.NoFocus) #取消选中焦点,去掉虚线框 + self.addressTabWidget.setEditTriggers(QTableWidget.NoEditTriggers) + self.addressTabWidget.cellClicked.connect(self.onCellClicked) + self.addressTabWidget.cellDoubleClicked.connect(lambda row, column: self.onCellClicked(row, column, True)) + + self.item = QTableWidgetItem('16') + self.addressTabWidget.setItem(0, 0, self.item) + + self.mainlayout = QVBoxLayout() + self.progressBar = QProgressBar(self) + self.bottomLayout = QHBoxLayout() + + self.confirmBtn = QPushButton('确定') + self.confirmBtn.clicked.connect(self.onConfirm) + + self.cancelBtn = QPushButton('取消') + + self.bottomLayout.addWidget(self.confirmBtn) + self.bottomLayout.addWidget(QSplitter()) + self.bottomLayout.addWidget(self.cancelBtn) + + self.mainlayout.addWidget(self.progressBar) + self.mainlayout.addWidget(self.addressTabWidget) + self.mainlayout.addLayout(self.bottomLayout) + + self.setLayout(self.mainlayout) + self.setWindowTitle('从站地址查找') + + self.timer = QTimer() + self.timer.timeout.connect(self.updateProgress) + self.timer.start(500) + + def updateProgress(self): + # 模拟一个任务,逐步更新进度条 + self.progressBar.setValue(int(125 * (100/125))) + # QApplication.processEvents() # 确保UI及时更新 + # QTimer.singleShot(100, lambda: None) # 暂停一小段时间,模拟任务执行时间 + + def onCellClicked(self, row, column, double = False): + item = self.addressTabWidget.item(row, column) + if item: + self.address = item.text() + if double: + self.onConfirm() + + def onConfirm(self): + self.deviceAddressEdit.setText(self.address) + self.close() + diff --git a/bin.py b/bin.py index 13da3ba..d2a692a 100644 --- a/bin.py +++ b/bin.py @@ -5,6 +5,7 @@ from model.ClientModel.Client import Client from utils import Globals + import time import sys @@ -30,9 +31,10 @@ if __name__ == '__main__': app.setStyle(QStyleFactory.create('windowsvisio')) from Static.Png import qInitResources qInitResources() - from Static.QSS import qInitResources - qInitResources() - app.setStyleSheet(CommonHelper.readQrcQss('static/Main.qss') + CommonHelper.readQrcQss('static/Area.qss')) + # from Static.QSS import qInitResources + # qInitResources() + # app.setStyleSheet(CommonHelper.readQrcQss('static/Main.qss') + CommonHelper.readQrcQss('static/Area.qss')) + app.setStyleSheet(CommonHelper.readLocalQss('Static/Main.qss') + CommonHelper.readLocalQss('Static/Area.qss')) Globals._init() Client.initDB() window = MainWindow() diff --git a/model/ClientModel/Client.py b/model/ClientModel/Client.py index 44c662a..f18e294 100644 --- a/model/ClientModel/Client.py +++ b/model/ClientModel/Client.py @@ -3,6 +3,7 @@ import sys from peewee import * from utils.DBModels.BaseModel import * from utils.DBModels.DeviceModels import * +from utils.DBModels.DeviceParModels import * class Client(object): def __init__(self): super(Client, self).__init__() @@ -17,6 +18,6 @@ class Client(object): else: self.deviceDB = SqliteDatabase(dbPath) client_proxy.initialize(self.deviceDB) - modelsArr = [DeviceDB] + modelsArr = [DeviceDB, PressureTranslationBlock, PhysicalBlock, AIFunctionBlock] self.deviceDB.connect() self.deviceDB.create_tables(modelsArr, safe = True) diff --git a/protocol/BatterySerial/BatteryProtocol.py b/protocol/BatterySerial/BatteryProtocol.py index deb0b1f..6d56f0b 100644 --- a/protocol/BatterySerial/BatteryProtocol.py +++ b/protocol/BatterySerial/BatteryProtocol.py @@ -65,5 +65,6 @@ class BatteryManange(): return result def close(self): - self.ser.close() + pass + # self.ser.close() diff --git a/utils/DBModels/DeviceModels.py b/utils/DBModels/DeviceModels.py index a3bcb17..0df941d 100644 --- a/utils/DBModels/DeviceModels.py +++ b/utils/DBModels/DeviceModels.py @@ -62,8 +62,6 @@ class DeviceDB(BaseModel): # print(self.createTime) self.save() - - diff --git a/utils/DBModels/DeviceParModels.py b/utils/DBModels/DeviceParModels.py new file mode 100644 index 0000000..b0c7fae --- /dev/null +++ b/utils/DBModels/DeviceParModels.py @@ -0,0 +1,89 @@ +import sys +import os +import datetime +from peewee import * +import json +import pandas as pd + +from utils.DBModels.BaseModel import BaseModel + +sys.path.append('../') +sys.path.append('../../../') + + + + +class PressureTranslationBlock(BaseModel): + index = CharField() + paramName = CharField() + objectType = CharField() + dataType = CharField() + saveType = CharField() + dataSize = CharField() + accessType = CharField() + transferType = CharField() + description = CharField() + createTime = CharField() + + # 查询设备是否存在 + @classmethod + def getallParame(cls): + devices = cls.get_all() + if devices is 'error': + return + l = [] + for x in devices: + l.append([x.index, x.paramName, x.description, x.dataType, x.accessType]) + return l + + @classmethod + def getByName(cls, paramName): + try: + return cls.get(cls.paramName == str(paramName)) + except Exception as e: + return + + def addParame(self, index, paramName, objectType, dataType, saveType, dataSize, accessType, transferType, description): + self.index = index + self.paramName = paramName + self.objectType = objectType + self.dataType = dataType + self.saveType = saveType + self.dataSize = dataSize + self.accessType = accessType + self.transferType = transferType + self.description = description + self.createTime = datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S') + # print(self.createTime) + self.save() + + + + +class PhysicalBlock(PressureTranslationBlock): + index = CharField() + paramName = CharField() + objectType = CharField() + dataType = CharField() + saveType = CharField() + dataSize = CharField() + accessType = CharField() + transferType = CharField() + description = CharField() + createTime = CharField() + + + +class AIFunctionBlock(PressureTranslationBlock): + index = CharField() + paramName = CharField() + objectType = CharField() + dataType = CharField() + saveType = CharField() + dataSize = CharField() + accessType = CharField() + transferType = CharField() + description = CharField() + createTime = CharField() + + \ No newline at end of file diff --git a/utils/DBModels/InitParameterDB.py b/utils/DBModels/InitParameterDB.py new file mode 100644 index 0000000..f584320 --- /dev/null +++ b/utils/DBModels/InitParameterDB.py @@ -0,0 +1,19 @@ +from utils.DBModels.DeviceParModels import * + + +class InitParameterDB(): + def __init__(self) -> None: + self.writeParameter() + + def writeParameter(self) -> None: + blockNames = pd.ExcelFile('static/PA块信息表.xlsx').sheet_names + for blockName in blockNames: + parameters = pd.read_excel('static/PA块信息表.xlsx', sheet_name=str(blockName)) + + for index, row in parameters.iterrows(): + parameter = row.values + clsblockName = globals()[blockName]() #通过excel的sheet名字获取对应的数据库函数 + if not clsblockName.getByName(parameter[1]): + clsblockName.addParame(index = parameter[0], paramName = parameter[1], objectType = parameter[2], dataType = parameter[3], + saveType = parameter[4], dataSize = parameter[5], accessType = parameter[6], transferType = parameter[7], description = parameter[8]) + \ No newline at end of file