diff --git a/Static/Main.qss b/Static/Main.qss index 8575c34..fda4bf6 100644 --- a/Static/Main.qss +++ b/Static/Main.qss @@ -456,3 +456,10 @@ QHeaderView::section { font-size: 16pt; } +QProgressBar { + + text-align: center; + + color: black; + + } \ No newline at end of file diff --git a/UI/BlockParameterManageWidget.py b/UI/BlockParameterManageWidget.py index 8a4788b..86f9510 100644 --- a/UI/BlockParameterManageWidget.py +++ b/UI/BlockParameterManageWidget.py @@ -7,6 +7,10 @@ from UI.BlockParameterView import ParmView from UI.SearchAddressWidget import SearchAddressWidget from utils.DBModels.DeviceParModels import * +from UI.LoadingDataWidget import LoadingDataWidget + + + class BlockParameterManageWidget(QWidget): @@ -28,9 +32,9 @@ class BlockParameterManageWidget(QWidget): self.deviceAddressEdit = QLineEdit() self.deviceAddressEdit.setObjectName("deviceAddressEdit") - self.confirmBtn = QPushButton('确定') + self.confirmBtn = QPushButton('加载数据') self.confirmBtn.setIcon(qtawesome.icon('fa5s.check-circle', color='#1fbb6f')) - self.confirmBtn.clicked.connect(self.testUI) + self.confirmBtn.clicked.connect(self.refreshData) self.confirmBtn.setObjectName("parameBtn") self.deviceAddressSearchBtn = QPushButton('查找') @@ -116,7 +120,11 @@ class BlockParameterManageWidget(QWidget): case "tblockBtn": self.parameStackWidget.setCurrentIndex(2) - def testUI(self): + def refreshData(self): + + self.loadingDataWidget = LoadingDataWidget() + self.loadingDataWidget.loadData() + model = self.parameStackWidget.currentWidget().model model.updateColumn(5, '查询中...') diff --git a/UI/BlockParameterModel.py b/UI/BlockParameterModel.py index 801fa3e..b48e26a 100644 --- a/UI/BlockParameterModel.py +++ b/UI/BlockParameterModel.py @@ -1,10 +1,11 @@ import typing import re +from matplotlib.pyplot import box import qtawesome from PyQt5 import QtGui,QtCore,QtWidgets from PyQt5.QtCore import QAbstractTableModel, QModelIndex, Qt, QVariant, QSize from PyQt5.QtWidgets import QItemDelegate, QHBoxLayout, QWidget, QPushButton, QMessageBox, QLineEdit, QComboBox, QStyledItemDelegate - +from UI.LoadingDataWidget import LoadingDataWidget @@ -143,15 +144,24 @@ class VarButtonDelegate(QItemDelegate): if 'w' not in self.parent().model.datas[index.row()][4]: return - startActionBtn.index = [index.row(), index.column()] + startActionBtn.setToolTip('强制') + + refreshButton = QPushButton( + qtawesome.icon('mdi6.refresh', color='#1fbb6f'), + "", + self.parent() + ) + refreshButton.setToolTip('刷新') + refreshButton.clicked.connect(self.refreshData) parameEditline = QLineEdit() parameEditline.setObjectName('parameEditline') boxLayout = QHBoxLayout() boxLayout.addWidget(parameEditline) boxLayout.addWidget(startActionBtn) + boxLayout.addWidget(refreshButton) startActionBtn.clicked.connect(lambda: self.startAction(parameEditline)) startActionBtn.setObjectName('startActionBtn') @@ -179,6 +189,11 @@ class VarButtonDelegate(QItemDelegate): QMessageBox.Yes) return + + def refreshData(self): + + self.loadingDataWidget = LoadingDataWidget() + self.loadingDataWidget.loadData() class ComboBoxDelegate(QStyledItemDelegate): def __init__(self, parent=None): @@ -210,3 +225,43 @@ class ComboBoxDelegate(QStyledItemDelegate): def updateEditorGeometry(self, editor, option, index): editor.setGeometry(option.rect) + + +class refreshButtonDelegate(QItemDelegate): + """该类用于向单元格中添加按钮 任务表格""" + def __init__(self, parent=None): + super(refreshButtonDelegate, self).__init__(parent) + + def paint(self, painter, option, index): + if not self.parent().indexWidget(index): + startActionBtn = QPushButton( + qtawesome.icon('mdi6.refresh', color='#1fbb6f'), + "", + self.parent() + ) + + if 'w' not in self.parent().model.datas[index.row()][4]: + return + + + startActionBtn.index = [index.row(), index.column()] + + parameEditline = QLineEdit() + parameEditline.setObjectName('parameEditline') + + boxLayout = QHBoxLayout() + boxLayout.addWidget(parameEditline) + boxLayout.addWidget(startActionBtn) + + startActionBtn.clicked.connect(lambda: self.startAction(parameEditline)) + startActionBtn.setObjectName('startActionBtn') + + boxLayout.setContentsMargins(2, 0, 0, 2) + boxLayout.setAlignment(Qt.AlignCenter) + widget = QWidget() + widget.setLayout(boxLayout) + self.parent().setIndexWidget( + index, + widget + ) + \ No newline at end of file diff --git a/UI/LoadingDataWidget.py b/UI/LoadingDataWidget.py new file mode 100644 index 0000000..5f82341 --- /dev/null +++ b/UI/LoadingDataWidget.py @@ -0,0 +1,57 @@ +import sys +import time +from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QVBoxLayout, QPushButton, QLabel, QProgressBar +from PyQt5.QtCore import Qt, QThread, pyqtSignal + +class LoadDataThread(QThread): + progress = pyqtSignal(int) + + def run(self): + for i in range(101): + time.sleep(0.05) # 模拟数据加载过程 + self.progress.emit(i) + +class LoadingDialog(QDialog): + def __init__(self): + super().__init__() + self.initUI() + + def initUI(self): + vbox = QVBoxLayout() + + self.label = QLabel("加载数据中,请稍后...", self) + self.progressBar = QProgressBar(self) + + vbox.addWidget(self.label) + vbox.addWidget(self.progressBar) + + self.setLayout(vbox) + self.setWindowTitle('数据查询') + self.setWindowFlags(Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint) + self.setModal(True) + + def updateProgress(self, value): + self.progressBar.setValue(value) + +class LoadingDataWidget(QWidget): + def __init__(self): + super().__init__() + + def loadData(self): + self.loadingDialog = LoadingDialog() + + # 创建和启动数据加载线程 + self.loadThread = LoadDataThread() + self.loadThread.progress.connect(self.loadingDialog.updateProgress) + self.loadThread.finished.connect(self.onLoadingFinished) + + self.loadThread.start() + self.loadingDialog.exec_() + + def onLoadingFinished(self): + self.loadingDialog.accept() + +if __name__ == '__main__': + app = QApplication(sys.argv) + ex = LoadingDataWidget() + sys.exit(app.exec_()) diff --git a/UI/SearchAddressWidget.py b/UI/SearchAddressWidget.py index 2028d52..d918f2b 100644 --- a/UI/SearchAddressWidget.py +++ b/UI/SearchAddressWidget.py @@ -1,3 +1,4 @@ +import imp from UI.DeviceDialogWidget import DeviceDialog import sys import re @@ -12,6 +13,15 @@ from PyQt5.QtWidgets import QDialog, QListWidgetItem from protocol.ModBus.DPV1Master import DPV1Master +class CustomProgressBar(QProgressBar): + def text(self): + # 获取当前值和最大值 + currentValue = self.value() + maxValue = self.maximum() + # 返回自定义的显示文本 + return f"{currentValue}/{maxValue}" + + class SearchAddressWidget(QWidget): def __init__(self, deviceAddressEdit): super().__init__() @@ -23,9 +33,15 @@ class SearchAddressWidget(QWidget): self.resize(800, 500) self.setObjectName('deviceDialog') self.addressListWidget = QListWidget() + self.addressListWidget.clicked.connect(self.onCellClicked) + self.addressListWidget.doubleClicked.connect(lambda: self.onCellClicked(True)) self.mainlayout = QVBoxLayout() - self.progressBar = QProgressBar(self) + + self.progressBar = CustomProgressBar() + self.progressBar.setMaximum(125) + self.progressBar.setValue(0) + self.bottomLayout = QHBoxLayout() self.confirmBtn = QPushButton('确定') @@ -44,28 +60,29 @@ class SearchAddressWidget(QWidget): self.setLayout(self.mainlayout) self.setWindowTitle('从站地址查找') - test = DPV1Master('192.168.3.10', 502) - test.searchMaster(self.updateProgress) + self.test = DPV1Master('192.168.3.10', 502) + self.test.searchMaster(self.updateProgress) + self.cancelBtn.clicked.connect(self.test.closeThread) # self.timer = QTimer() # self.timer.timeout.connect(self.updateProgress) # self.timer.start(500) def updateProgress(self, address, isSlave): # 模拟一个任务,逐步更新进度条 - self.progressBar.setValue(int(address * (100/125))) + + self.progressBar.setValue(address) if isSlave: self.addressListWidget.addItem(QListWidgetItem(str(address))) # QApplication.processEvents() # 确保UI及时更新 # QTimer.singleShot(100, lambda: None) # 暂停一小段时间,模拟任务执行时间 - def onCellClicked(self, row, column, double = False): - item = self.addressListWidget.item(row, column) - if item: - self.address = item.text() + def onCellClicked(self, double = False): + self.address = self.addressListWidget.currentItem().text() if double: self.onConfirm() def onConfirm(self): + self.deviceAddressEdit.setText(self.address) self.close() diff --git a/protocol/ModBus/DPV1Master.py b/protocol/ModBus/DPV1Master.py index b27d037..8fa88d7 100644 --- a/protocol/ModBus/DPV1Master.py +++ b/protocol/ModBus/DPV1Master.py @@ -16,12 +16,14 @@ class DPV1Master(): self.master = modbus_tcp.TcpMaster(host = host, port = port) self.master.set_timeout(5.0) except Exception as e: - pass + self.master = None # hooks.install_hook("modbus_tcp.TcpMaster.after_recv", afterRecv) # hooks.install_hook("modbus_tcp.TcpMaster.after_send", afterSend) def writeMultipleRegister(self, slaveId, address, outputValue): + if not self.master: + return 'error' try: self.master.execute(slaveId, cst.WRITE_MULTIPLE_REGISTERS, starting_address = address, output_value=outputValue) except Exception as e: @@ -29,6 +31,8 @@ class DPV1Master(): def readHoldingRegisters(self, slaveId, startAddress, varNums): + if not self.master: + return 'error' try: value = self.master.execute(slaveId, cst.READ_HOLDING_REGISTERS, startAddress, varNums) return value @@ -41,7 +45,6 @@ class DPV1Master(): def searchMaster(self, callback = None): def search(): - addressList = [] for address in range(1, 126): hexAddress = address.to_bytes(1, byteorder='little') searchByteStream = b'\x01' + hexAddress + b'\x01\x00\xF0\x00' @@ -49,7 +52,7 @@ class DPV1Master(): self.writeMultipleRegister(1, 750, searchDate) time.sleep(0.3) dir = self.readHoldingRegisters(1, 750, 6) - if not self.areAllZeros(dir): + if not self.areAllZeros(dir) and dir != 'error': callback(address, True) else: callback(address, False) @@ -57,9 +60,14 @@ class DPV1Master(): time.sleep(0.1) # print(address, dir) # if callable(callback): - - t = threading.Thread(target=search) - t.start() + if not self.master: + callback(125, False) + return + self.searchMasterThread = threading.Thread(target=search) + self.searchMasterThread.start() + + def closeThread(self): + self.searchMasterThread.join() def readParm(self, address, slot, index, length, callback = None): hexAddress = address.to_bytes(1, byteorder='little')