class Window(QtWidgets.QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("グラフ") self.setGeometry(300, 300, 500, 500) self.figure = plt.figure() self.axes = self.figure.add_subplot(111) # We want the axes cleared every time plot() is called self.axes.hold(False) self.canvas = FigureCanvas(self.figure) self.canvas.setParent(self) self.canvas.move(100, 20) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Just some button self.button1 = QtWidgets.QPushButton('Plot', self) self.button1.clicked.connect(self.plot) self.button1.move(0, 400) def plot(self): ''' plot some random stuff ''' data = [random.random() for i in range(25)] self.axes.plot(data, '*-') self.canvas.draw()
class Window(QtWidgets.QDialog): def __init__(self, parent=None): super().__init__(parent) self.figure = plt.figure() self.axes = self.figure.add_subplot(111) # We want the axes cleared every time plot() is called self.axes.hold(False) self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Just some button self.button1 = QtWidgets.QPushButton('Plot') self.button1.clicked.connect(self.plot) self.button2 = QtWidgets.QPushButton('Zoom') self.button2.clicked.connect(self.zoom) self.button3 = QtWidgets.QPushButton('Pan') self.button3.clicked.connect(self.pan) self.button4 = QtWidgets.QPushButton('Home') self.button4.clicked.connect(self.home) # set the layout layout = QtWidgets.QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) btnlayout = QtWidgets.QHBoxLayout() btnlayout.addWidget(self.button1) btnlayout.addWidget(self.button2) btnlayout.addWidget(self.button3) btnlayout.addWidget(self.button4) qw = QtWidgets.QWidget(self) qw.setLayout(btnlayout) layout.addWidget(qw) self.setLayout(layout) def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan() def plot(self): ''' plot some random stuff ''' data = [random.random() for i in range(25)] self.axes.plot(data, '*-') self.canvas.draw()
class Window(QtWidgets.QDialog): def __init__(self, parent=None): super().__init__(parent) self.figure = plt.figure() self.axes = self.figure.add_subplot(111) # We want the axes cleared every time plot() is called self.axes.hold(False) self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Just some button self.button1 = QtWidgets.QPushButton('Plot') self.button1.clicked.connect(self.plot) self.button2 = QtWidgets.QPushButton('Save') self.button2.clicked.connect(self.save) # set the layout layout = QtWidgets.QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) btnlayout = QtWidgets.QHBoxLayout() btnlayout.addWidget(self.button1) btnlayout.addWidget(self.button2) qw = QtWidgets.QWidget(self) qw.setLayout(btnlayout) layout.addWidget(qw) self.setLayout(layout) def save(self): from pathlib import Path file_name, _ = QFileDialog.getSaveFileName(self) if len(file_name) == 0: return print(file_name) file_name = str(Path(file_name).with_suffix(".png")) print(file_name) self.figure.savefig(file_name) def plot(self): ''' plot some random stuff ''' data = [random.random() for i in range(25)] self.axes.plot(data, '*-') self.canvas.draw()
class Ui_Form(object): def setupUi(self, Form): Form.setWindowTitle("流量监测系统") Form.resize(950, 630) self.horizontalLayoutWidget = QtWidgets.QWidget(Form) self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 530, 30)) self.horizontalLayout = QtWidgets.QHBoxLayout( self.horizontalLayoutWidget) self.horizontalLayout.setContentsMargins(0, 0, 0, 0) self.horizontalLayout.setSpacing(10) Form.setFixedSize(Form.width(), Form.height()) self.monitor = Monitor(self) """主字体""" font = QtGui.QFont() font.setFamily("Lucida Sans Typewriter") font.setPointSize(10) """应用选择框""" self.comboBox = QtWidgets.QComboBox(self.horizontalLayoutWidget) self.comboBox.setFont(font) self.horizontalLayout.addWidget(self.comboBox) """流量预警线设置""" self.warn_line = QtWidgets.QLineEdit(self.horizontalLayoutWidget) self.warn_line.setText("1024") self.horizontalLayout.addWidget(self.warn_line) self.label = QtWidgets.QLabel(self.horizontalLayoutWidget) self.label.setText("kb/s") self.horizontalLayout.addWidget(self.label) self.start_button = QtWidgets.QPushButton(self.horizontalLayoutWidget) self.start_button.setText("开始监测") self.start_button.clicked.connect(self.start) self.horizontalLayout.addWidget(self.start_button) self.stop_button = QtWidgets.QPushButton(self.horizontalLayoutWidget) self.stop_button.setText("停止监测") self.stop_button.clicked.connect(self.stop) self.horizontalLayout.addWidget(self.stop_button) self.stop_button.setEnabled(False) self.update_button = QtWidgets.QPushButton(self.horizontalLayoutWidget) self.update_button.setText("更新列表") self.horizontalLayout.addWidget(self.update_button) self.horizontalLayout.setStretch(0, 2) self.horizontalLayout.setStretch(1, 1) self.horizontalLayout.setStretch(2, 1) self.horizontalLayout.setStretch(3, 1) self.horizontalLayout.setStretch(4, 1) self.APPList_label = QtWidgets.QLabel(Form) self.APPList_label.setText("进程连接列表") self.APPList_label.setStyleSheet("font-size: 20px; font-family: 宋体") self.APPList_label.setGeometry(QtCore.QRect(680, 10, 150, 30)) """应用树列表""" self.App_Tree = QtWidgets.QTreeWidget(Form) self.App_Tree.header().setVisible(False) self.App_Tree.setFont(font) self.App_Tree.setStyleSheet("QTreeView::item{margin:2px;}") self.App_Tree.setGeometry(QtCore.QRect(560, 40, 380, 580)) self.update_button.clicked.connect(self.refresh_process) self.verticalLayoutWidget = QtWidgets.QWidget(Form) self.verticalLayoutWidget.setGeometry(QtCore.QRect(10, 60, 530, 570)) self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.conList = QtWidgets.QListWidget(self.verticalLayoutWidget) self.conList.setFont(font) self.conList.setStyleSheet("QListView::item{margin:2px;}") self.conList.setMinimumSize(421, 200) self.verticalLayout.addWidget(self.conList) self.figure = plt.figure(figsize=(6, 3)) self.upload_plot = self.figure.add_subplot(1, 1, 1) self.upload_plot.set_xlabel("Time (s)") self.upload_plot.set_ylabel("Speed (kB/s)") self.figure.tight_layout() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self.verticalLayoutWidget) self.toolbar.hide() self.verticalLayout.addWidget(self.toolbar) self.verticalLayout.addWidget(self.canvas) QtCore.QMetaObject.connectSlotsByName(Form) self.comboBox.addItems(self.monitor.getProcessList()) self.show_process_tree() self.timer = QtCore.QTimer(Form) self.timer.timeout.connect(self.conList.scrollToBottom) def show_process_tree(self): """ 添加节点 """ self.App_Tree.clear() process_name, process_conn = self.monitor.getProcessConnections() for name in process_name: item1 = QtWidgets.QTreeWidgetItem(self.App_Tree) item1.setText(0, name) for connections in process_conn[name]: item1_1 = QtWidgets.QTreeWidgetItem(item1) item1_1.setText(0, connections) def alert(self, info): """ 警告信息 """ alert_font = QtGui.QFont() alert_font.setFamily("Lucida Sans Typewriter") alert_font.setPointSize(14) now = time_to_formal(time()) item = QtWidgets.QListWidgetItem("%s\n%s" % (now, info), self.conList) item.setForeground(QtGui.QColor('red')) item.setFont(alert_font) def refresh_process(self): """ 刷新进程列表 """ self.comboBox.clear() self.comboBox.addItems(self.monitor.getProcessList()) self.show_process_tree() def setSpeed(self): """ 设置速度图 """ upload = [] download = [] speed = int(self.warn_line.text()) # 警告线 alert = [speed for _ in range(60)] while not self.monitor.start_flag.is_set(): info = get_rate(None) plt.cla() self.upload_plot.set_xlabel("Time (s)") self.upload_plot.set_ylabel("Speed (kB/s)") info[1] >>= 10 info[0] >>= 10 upload.append(info[1]) download.append(info[0]) if len(upload) >= 60: upload.pop(0) download.pop(0) self.upload_plot.plot( alert, 'red', linewidth='2', label="Warning") self.upload_plot.legend(loc='upper right') self.upload_plot.plot( upload, 'darkorange', linewidth='1', label="Upload") self.upload_plot.legend(loc='upper right') self.upload_plot.plot( download, 'blue', linewidth='1', label="Download") self.upload_plot.legend(loc='upper right') self.canvas.draw() # 流量警告 # 当速度大于设定值时流量警告 if info[1] > speed or info[0] > speed: self.alert("警告: 流量已超过预警线 %dkB/s!" % speed) def start(self): """ 开始检测 """ if self.monitor.start_flag.is_set(): self.start_button.setEnabled(False) self.stop_button.setEnabled(True) self.comboBox.setEnabled(False) self.warn_line.setEnabled(False) self.monitor.start(self.comboBox.currentText()) Thread(target=self.setSpeed, daemon=True).start() self.timer.start(1000) def stop(self): """ 停止检测 """ if not self.monitor.start_flag.is_set(): self.monitor.stop() self.timer.stop() self.start_button.setEnabled(True) self.stop_button.setEnabled(False) self.comboBox.setEnabled(True) self.warn_line.setEnabled(True)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) # Init 0 for draw... plt.rcParams['agg.path.chunksize'] = 0 matplotlib.rcParams['agg.path.chunksize'] = 0 matplotlib.rcParams.update(matplotlib.rc_params()) self.dpi = 100 self.signalframe = self.widget_Signal_TimeDomain self.figure = Figure((11.3, 6.3), dpi=self.dpi) self.canvas = FigureCanvas(self.figure) self.canvas.setParent(self.signalframe) self.axes = self.figure.add_subplot(111) #self.axes.set_title('Signal') self.axes.set_xlabel('Time(μs)') self.axes.set_ylabel('Voltage') #plt.subplots_adjust(left=0.2, bottom=0.2, right=0.8, top=0.8, hspace=0.2, wspace=0.3) timespan = self.getRecordLength() * 1024 / self.getSampleRate( ) # in us x = np.linspace(0, timespan, self.getRecordLength() * 1024) normalLimY = self.getVoltageScale() * 10 self.axes.set_ylim(-normalLimY / 2 + self.getOffset(), normalLimY / 2 + self.getOffset()) ymajorLocator = MultipleLocator(self.getVoltageScale()) yminorLocator = MultipleLocator(self.getVoltageScale() / 2) self.axes.yaxis.set_major_locator(ymajorLocator) self.axes.yaxis.set_minor_locator(yminorLocator) self.axes.grid(True) self.figure.tight_layout() # Adjust spaces #self.NavToolbar = NavigationToolbar(self.canvas, self.signalframe) #self.addToolBar(QtCore.Qt.RightToolBarArea, NavigationToolbar(self.canvas, self.signalframe)) self.toolbar = NavigationToolbar(self.canvas, self.signalframe) self.toolbar.hide() # Button slots self.pushButton_Home.clicked.connect(self.home) self.pushButton_Back.clicked.connect(self.back) self.pushButton_Forward.clicked.connect(self.forward) self.pushButton_Pan.clicked.connect(self.pan) self.pushButton_Zoom.clicked.connect(self.zoom) self.pushButton_SavePic.clicked.connect(self.savepic) # Init Socket self.udpSocketClient = UDPSocketClient() # Init FrameNum self.checkBox_FrameMode.setEnabled(True) self.frameNum = self.getFrameNumber() # 0x4 self.sendCmdFramNum(self.frameNum) # Init Length 0x8 self.comboBox_RecordLength.setCurrentIndex(6) # 64k # Set RecordLength self.sendCmdRecordLength(self.getRecordLength() * self.getFrameNumber()) #Init Trigger 0x2, bit2 self.comboBox_TriggerDomain.setCurrentIndex(1) # External self.sendCmdTriggerType(self.getTriggerType()) # Reset PFGA to read to capture data if (self.getTriggerType() == 0): self.sendCmdWRREG(0x2, 0x20) self.sendCmdWRREG(0x2, 0x28) else: self.sendCmdWRREG(0xa, 0x0) self.sendCmdWRREG(0x2, 0x2c) self.sendCmdWRREG(0x2, 0x2d) # Read sampleRate value = self.readCmdSampleRate() if value > 5: value = 0 self.comboBox_SampleRate.setCurrentIndex(value) # The last data self.lastChAData = [] self.lastChBData = [] self.realTimeThread = None self.externalTriggerThread = None def home(self): self.toolbar.home() def back(self): self.toolbar.back() def forward(self): self.toolbar.forward() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan() def savepic(self): self.toolbar.save_figure() def sendcommand(self, cmdid, status, msgid, len, type, offset, apiversion, pad, CRC16, cmdData): cmdid = struct.pack('H', htons(cmdid)) status = struct.pack('H', htons(status)) msgid = struct.pack('H', htons(msgid)) len = struct.pack('H', htons(len)) type = struct.pack('H', htons(type)) offset = struct.pack('H', htons(offset)) apiversion = struct.pack('B', apiversion) # 1 Byte unsigned char pad = struct.pack('B', pad) # 1 Byte unsigned char CRC16 = struct.pack('H', htons(CRC16)) # 2 Byte unsigned short cmdHeader = cmdid + status + msgid + len + type + offset + apiversion + pad + CRC16 if (cmdData != None): self.udpSocketClient.mData = cmdHeader + cmdData else: self.udpSocketClient.mData = cmdHeader self.udpSocketClient.sendData() def sendCmdTriggerType(self, value): regAddr = 0x2 # 0x2, Bit[2], 0: Auto, 1: External currentValue = self.readCmdTriggerType() if value == 0: # Auto Trigger mask = 0b1111111111111011 currentValue = currentValue & mask elif value == 1: # External mask = 0b100 currentValue = currentValue | mask self.sendCmdWRREG(regAddr, currentValue) def readCmdTriggerType(self): print("readCmdTriggerType ") self.sendCmdRDREG(0x02, 0x00) data = self.udpSocketClient.receiveData() value = ntohl(int(struct.unpack('L', data[20:24])[0])) return value def readDataCount(self): self.sendCmdRDREG(0x10, 0x00) data = self.udpSocketClient.receiveData() data = data[20:24] lowValue = ntohl(int(struct.unpack('L', data)[0])) print("0x10 Value:", hex(lowValue)) self.sendCmdRDREG(0x12, 0x00) data = self.udpSocketClient.receiveData() data = data[20:24] highValue = ntohl(int(struct.unpack('L', data)[0])) print("0x12 Value:", hex(highValue)) value = highValue << 16 | lowValue return value #return 1024 def sendCmdSampleRate(self, value): global gSocketBodySize gSocketBodySize = 4 self.udpSocketClient.setBufSize(gSocketBodySize + gSocketHeaderSize) cmdData = struct.pack('L', htonl(value)) self.sendcommand(0x5a09, 0x0000, 0x5a09, 0x0004, 0x0000, 0x0000, 0x00, 0x00, 0x0000, cmdData) self.udpSocketClient.receiveData() # Do nothing def readCmdSampleRate(self): global gSocketBodySize gSocketBodySize = 4 self.udpSocketClient.setBufSize(gSocketBodySize + gSocketHeaderSize) # Len is not cared self.sendcommand(0x5a0a, 0x0000, 0x5a0a, 0x0004, 0x0000, 0x0000, 0x00, 0x00, 0x0000, None) data = self.udpSocketClient.receiveData() value = ntohl(int(struct.unpack('L', data[16:20])[0])) return value def sendCmdRecordLength(self, length): #recordLength = self.getRecordLength() regAddr = 0x8 regValue = length self.sendCmdWRREG(regAddr, regValue) def receiveCmdRecordLength(self): global gSocketBodySize gSocketBodySize = 8 self.udpSocketClient.setBufSize(gSocketBodySize + gSocketHeaderSize) self.udpSocketClient.receiveData() # Do nothing def sendCmdRAW_AD_SAMPLE(self, length): #print (sys._getframe().f_code.co_name) global gSocketBodySize gSocketBodySize = length * 1024 self.udpSocketClient.setBufSize(gSocketBodySize + gSocketHeaderSize) len = 0 #self.getRecordLength() self.sendcommand(0x5a04, 0x0000, 0x5a04, len, 0x0000, 0x0000, 0x00, 0x00, 0x0000, None) def receiveCmdRAW_AD_SAMPLE(self, length): global gSocketBodySize gSocketBodySize = length * 1024 self.udpSocketClient.setBufSize(gSocketBodySize + gSocketHeaderSize) self.udpSocketClient.receiveData() def sendCmdFramNum(self, frameNum): if (frameNum <= 2**16 - 1): regAddr = 0x4 regValue = frameNum self.sendCmdWRREG(regAddr, regValue) else: # Low regAddr = 0x4 regValue = frameNum & (2**16 - 1) self.sendCmdWRREG(regAddr, regValue) # High regAddr = 0x6 regValue = frameNum >> 16 self.sendCmdWRREG(regAddr, regValue) def sendCmdWRREG(self, regAddress, regValue): #print (sys._getframe().f_code.co_name) global gSocketBodySize gSocketBodySize = 8 self.udpSocketClient.setBufSize(gSocketBodySize + gSocketHeaderSize) cmdData = struct.pack('L', htonl(regAddress)) + struct.pack( 'L', htonl(regValue)) self.sendcommand(0x5a02, 0x0000, 0x5a02, 0x0008, 0x0000, 0x0000, 0x00, 0x00, 0x0000, cmdData) self.udpSocketClient.receiveData() # Do nothing def sendCmdRDREG(self, regAddress, regValue): #print (sys._getframe().f_code.co_name) global gSocketBodySize gSocketBodySize = 8 self.udpSocketClient.setBufSize(gSocketBodySize + gSocketHeaderSize) cmdData = struct.pack('L', htonl(regAddress)) + struct.pack( 'L', htonl(regValue)) self.sendcommand(0x5a01, 0x0000, 0x5a01, 0x0008, 0x0000, 0x0000, 0x00, 0x00, 0x0000, cmdData) def getTriggerType(self): index = self.comboBox_TriggerDomain.currentIndex() return int(index) def getSampleRate(self): index = self.comboBox_SampleRate.currentText() return int(index) def getRecordLength(self): index = self.comboBox_RecordLength.currentIndex() if (index == 18): return 40 else: return 2**index def getVoltageScale(self): volScale = 200 volScaleStr = self.lineEdit_VolScale.text() volScale = 200 if (('-') == volScaleStr or "" == volScaleStr): volScale = 200 else: volScale = int(volScaleStr) return volScale def getOffset(self): offset = 0 offsetStr = self.lineEdit_Offset.text() if (('-') == offsetStr or "" == offsetStr): offset = 0 else: offset = int(offsetStr) return offset def getFrameNumber(self): if (self.checkBox_FrameMode.isChecked() and self.checkBox_FrameMode.isEnabled()): return int(self.lineEdit_FrameNum.text()) else: return 1 @pyqtSlot() def on_pushButton_Stop_TimeDomain_clicked(self): """ Slot documentation goes here. """ if self.realTimeThread != None: self.realTimeThread.stop() if self.externalTriggerThread != None: self.externalTriggerThread.stop() self.pushButton_Start_TimeDomain.setEnabled(True) self.pushButton_Stop_TimeDomain.setEnabled(False) self.pushButton_Save_TimeDomain.setEnabled(True) self.comboBox_RecordLength.setEnabled(True) # Disable them for zhengzhou self.comboBox_SampleRate.setEnabled(True) self.comboBox_TriggerDomain.setEnabled(True) self.lineEdit_FrameNum.setEnabled(True) @pyqtSlot() def on_pushButton_Start_TimeDomain_clicked(self): """ Slot documentation goes here. """ # Restart LCD display self.lcdNumber_FrameNum.display(0) self.pushButton_Start_TimeDomain.setEnabled(False) self.pushButton_Stop_TimeDomain.setEnabled(True) self.pushButton_Save_TimeDomain.setEnabled(False) self.comboBox_RecordLength.setEnabled(False) self.comboBox_SampleRate.setEnabled(False) self.comboBox_TriggerDomain.setEnabled(False) self.lineEdit_FrameNum.setEnabled(False) if self.getTriggerType() == 0: # Auto Trigger Type self.realTimeThread = RealTimeThread( self.axes, self.canvas, self.radioButton_CHA.isChecked(), 1.0, False) self.realTimeThread.setDaemon(True) self.realTimeThread.start() elif self.getTriggerType() == 1: # External Trigger Type self.externalTriggerThread = RealTimeThread( self.axes, self.canvas, self.radioButton_CHA.isChecked(), 1.0, True) self.externalTriggerThread.setDaemon(True) self.externalTriggerThread.start() @pyqtSlot() def on_pushButton_Save_TimeDomain_clicked(self): """ Slot documentation goes here. """ # Write into file now = datetime.datetime.now() currentTime = now.strftime('%Y-%m-%d-%H-%M-%S') if (len(self.lastChAData) == 1): FileName_CHA = "ChA-" + currentTime + ".txt" File_CHA = open(FileName_CHA, 'w') FileName_CHB = "ChB-" + currentTime + ".txt" File_CHB = open(FileName_CHB, 'w') for pos in range(0, len(self.lastChAData[0])): File_CHA.write(str(self.lastChAData[0][pos])) File_CHA.write('\n') File_CHB.write(str(self.lastChBData[0][pos])) File_CHB.write('\n') File_CHA.close() File_CHB.close() else: for fileIndex in range(0, len(self.lastChAData)): FileName_CHA = "ChA-" + currentTime + "-" + str(fileIndex + 1) + ".txt" File_CHA = open(FileName_CHA, 'w') FileName_CHB = "ChB-" + currentTime + "-" + str(fileIndex + 1) + ".txt" File_CHB = open(FileName_CHB, 'w') for pos in range(0, len(self.lastChAData[fileIndex])): File_CHA.write(str(self.lastChAData[fileIndex][pos])) File_CHA.write('\n') File_CHB.write(str(self.lastChBData[fileIndex][pos])) File_CHB.write('\n') File_CHA.close() File_CHB.close() # Do not clear it #self.lastChAData = [] #self.lastChBData = [] @pyqtSlot(int) def on_comboBox_TriggerDomain_currentIndexChanged(self, index): self.sendCmdTriggerType(index) # Enable/Disable Frame Mode if index == 1: self.checkBox_FrameMode.setEnabled(True) self.label_FrameNum.setEnabled(True) self.lineEdit_FrameNum.setEnabled(True) self.label_FrameNum_Current.setEnabled(True) self.lcdNumber_FrameNum.setEnabled(True) else: self.checkBox_FrameMode.setEnabled(False) self.label_FrameNum.setEnabled(False) self.lineEdit_FrameNum.setEnabled(False) self.label_FrameNum_Current.setEnabled(False) self.lcdNumber_FrameNum.setEnabled(False) # Restor RecordLength self.sendCmdRecordLength(self.getRecordLength() * self.getFrameNumber()) @pyqtSlot(int) def on_comboBox_SampleRate_currentIndexChanged(self, index): if index > -1: self.sendCmdSampleRate(index) @pyqtSlot(int) def on_comboBox_RecordLength_currentIndexChanged(self, index): if (index == 18): # this is 40k self.sendCmdRecordLength(40 * self.getFrameNumber()) else: self.sendCmdRecordLength((2**index) * self.getFrameNumber()) @pyqtSlot() def on_lineEdit_FrameNum_editingFinished(self): self.frameNum = int(self.lineEdit_FrameNum.text()) self.sendCmdFramNum(self.frameNum) self.sendCmdRecordLength(self.getRecordLength() * self.frameNum) @pyqtSlot(bool) def on_checkBox_FrameMode_clicked(self, checked): """ Slot documentation goes here. @param checked DESCRIPTION @type bool """ # Set recordLength value to register self.frameNum = self.getFrameNumber() self.sendCmdFramNum(self.frameNum) self.sendCmdRecordLength(self.getRecordLength() * self.frameNum)
class Window(QtWidgets.QMainWindow, Ui_MainWindow): """ 重写修改该类即可实现自定义后端界面,相加什么按钮可以随便加,目前还只是个demo self.canvas.draw() 每执行该函数,图形重绘 """ def __init__(self, figure): super(Window, self).__init__() self.setupUi(self) # 先执行父类方法,以产生成员变量 self.figure = figure self.canvas = FigureCanvas(self.figure) # 这里的canvas就是曲线图 self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # 隐藏QT原来的工具栏 # self.graphicsView.addWidget(self.canvas) # 将canvas渲染到布局中 self.scene = QGraphicsScene() self.scene.addWidget(self.canvas) self.graphicsView.setScene(self.scene) self.graphicsView.show() self.actionX_X.triggered.connect(self.axes_control_slot) # 初始化当前界面 self.init_gui() # 槽函数连接 # 当前子图对象切换 self.current_path = os.path.dirname(__file__) self.saveAction = QAction( QIcon(os.path.join(self.current_path, 'icons/save.png')), 'save', self) self.saveAction.setShortcut('Ctrl+S') self.saveAction.triggered.connect(self.save_slot) self.toolBar.addAction(self.saveAction) self.settingAction = QAction( QIcon(os.path.join(self.current_path, 'icons/setting.png')), 'setting', self) self.settingAction.triggered.connect(self.axes_control_slot) self.toolBar.addAction(self.settingAction) self.homeAction = QAction( QIcon(os.path.join(self.current_path, 'icons/home.png')), 'home', self) self.homeAction.setShortcut('Ctrl+H') self.homeAction.triggered.connect(self.home_slot) self.toolBar.addAction(self.homeAction) self.backAction = QAction( QIcon(os.path.join(self.current_path, 'icons/back.png')), 'back', self) self.backAction.triggered.connect(self.back_slot) self.toolBar.addAction(self.backAction) self.frontAction = QAction( QIcon(os.path.join(self.current_path, 'icons/front.png')), 'front', self) self.frontAction.triggered.connect(self.front_slot) self.toolBar.addAction(self.frontAction) self.zoomAction = QAction( QIcon(os.path.join(self.current_path, 'icons/zoom.png')), 'zoom', self) self.zoomAction.triggered.connect(self.zoom_slot) self.toolBar.addAction(self.zoomAction) self.panAction = QAction( QIcon(os.path.join(self.current_path, 'icons/pan.png')), '平移', self) self.panAction.triggered.connect(self.pan_slot) self.toolBar.addAction(self.panAction) self.rotateAction = QAction( QIcon(os.path.join(self.current_path, 'icons/rotate.png')), 'rotate', self) self.rotateAction.triggered.connect(self.rotate_slot) self.toolBar.addAction(self.rotateAction) self.textAction = QAction( QIcon(os.path.join(self.current_path, 'icons/text.png')), 'text', self) self.textAction.triggered.connect(self.add_text_slot) self.toolBar.addAction(self.textAction) self.rectAction = QAction( QIcon(os.path.join(self.current_path, 'icons/rect.png')), 'rect', self) self.rectAction.triggered.connect(self.add_rect_slot) self.toolBar.addAction(self.rectAction) self.ovalAction = QAction( QIcon(os.path.join(self.current_path, 'icons/oval.png')), 'oval', self) self.ovalAction.triggered.connect(self.add_oval_slot) self.toolBar.addAction(self.ovalAction) self.arrowAction = QAction( QIcon(os.path.join(self.current_path, 'icons/arrow.png')), 'arrow', self) self.arrowAction.triggered.connect(self.add_arrow_slot) self.toolBar.addAction(self.arrowAction) self.pointAction = QAction( QIcon(os.path.join(self.current_path, 'icons/point.png')), 'point', self) self.pointAction.triggered.connect(self.add_point_slot) self.toolBar.addAction(self.pointAction) self.styleAction = QAction( QIcon(os.path.join(self.current_path, 'icons/style.png')), 'style', self) self.styleAction.triggered.connect(self.add_style_slot) self.toolBar.addAction(self.styleAction) # 将下拉菜单放在最右边 self.toolBar.addSeparator() spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.toolBar.addWidget(spacer) self.toolBar.addWidget(self.comboBox) # 以上为工具栏1 self.gridAction = QAction( QIcon(os.path.join(self.current_path, 'icons/grid.png')), '显示/隐藏网格', self) self.gridAction.triggered.connect(self.show_grid_slot) self.toolBar_2.addAction(self.gridAction) self.legendAction = QAction( QIcon(os.path.join(self.current_path, 'icons/legend.png')), '显示/隐藏图例', self) self.legendAction.triggered.connect(self.show_legend_slot) self.toolBar_2.addAction(self.legendAction) self.colorbarAction = QAction( QIcon(os.path.join(self.current_path, 'icons/colorbar.png')), '显示/隐藏colorbar', self) self.colorbarAction.triggered.connect(self.show_colorbar_slot) self.toolBar_2.addAction(self.colorbarAction) self.layoutAction = QAction( QIcon(os.path.join(self.current_path, 'icons/layout.png')), '改变布局', self) # self.layoutAction.triggered.connect(self.show_layout_slot) self.toolBar_2.addAction(self.layoutAction) self.mainViewAction = QAction( QIcon(os.path.join(self.current_path, 'icons/mainView.png')), 'mainView', self) self.mainViewAction.triggered.connect(self.mainView_slot) self.toolBar_2.addAction(self.mainViewAction) self.leftViewAction = QAction( QIcon(os.path.join(self.current_path, 'icons/leftView.png')), 'leftView', self) self.leftViewAction.triggered.connect(self.leftView_slot) self.toolBar_2.addAction(self.leftViewAction) self.rightViewAction = QAction( QIcon(os.path.join(self.current_path, 'icons/rightView.png')), 'rightView', self) self.rightViewAction.triggered.connect(self.rightView_slot) self.toolBar_2.addAction(self.rightViewAction) self.topViewAction = QAction( QIcon(os.path.join(self.current_path, 'icons/topView.png')), 'topView', self) self.topViewAction.triggered.connect(self.topView_slot) self.toolBar_2.addAction(self.topViewAction) self.bottomViewAction = QAction( QIcon(os.path.join(self.current_path, 'icons/bottomView.png')), 'bottomView', self) self.bottomViewAction.triggered.connect(self.bottomView_slot) self.toolBar_2.addAction(self.bottomViewAction) self.backViewAction = QAction( QIcon(os.path.join(self.current_path, 'icons/backView.png')), 'backView', self) self.backViewAction.triggered.connect(self.backView_slot) self.toolBar_2.addAction(self.backViewAction) # 样式右键菜单功能集 self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.rightMenuShow) self.rightMenuShow() # 创建上下文菜单 self.comboBox.currentIndexChanged.connect(self.combobox_slot) # 获取子图对象 self.axes = self.canvas.figure.get_axes() if not self.axes: QtWidgets.QMessageBox.warning(self.canvas.parent(), "Error", "There are no axes to edit.") return elif len(self.axes) == 1: self.current_subplot, = self.axes titles = ['图1'] else: titles = ['图' + str(i + 1) for i in range(len(self.axes))] # 将三维图的初始视角保存下来,便于旋转之后可以复原 self.init_views = [(index, item.azim, item.elev) for index, item in enumerate(self.axes) if hasattr(item, 'azim')] self.comboBox.addItems(titles) # 鼠标拖拽,实现三维图形旋转功能 self.canvas.mpl_connect('motion_notify_event', self.on_rotate) # 鼠标拖拽,实现画矩形功能 self.canvas.mpl_connect('motion_notify_event', self.add_rect) self.mouse_pressed = False # 鼠标拖拽,实现画椭圆和按住shift画圆的功能实现 self.canvas.mpl_connect('motion_notify_event', self.add_oval) # 画箭头 self.canvas.mpl_connect('motion_notify_event', self.add_arrow) # 画点,并且按住点能够移动 self.canvas.mpl_connect('button_press_event', self.add_point) self.canvas.mpl_connect('motion_notify_event', self.add_point) self.canvas.mpl_connect('button_release_event', self.add_point) self.canvas.mpl_connect('pick_event', self.add_point) self.press_time = 0 # 记录鼠标运动的位置 self.rotate_mouse_point = None self.canvas.mpl_connect('button_press_event', self.add_text) # 为曲线添加样式的功能实现 self.canvas.mpl_connect('button_press_event', self.add_style) self.canvas.mpl_connect('pick_event', self.add_style) # 为图例绑定监听事件 self.canvas.mpl_connect('button_press_event', self.change_legend) self.canvas.mpl_connect('pick_event', self.change_legend) # 所有的按钮标志 self.make_flag_invalid() self.artist = None for ax in self.axes: for line in ax.lines: line.set_picker(True) line.set_pickradius(5) def make_flag_invalid(self): self.add_rect_flag = False self.add_oval_flag = False self.add_text_flag = False self.rotate_flag = False self.home_flag = False self.pan_flag = False self.zoom_flag = False self.add_arrow_flag = False self.add_point_flag = False self.add_style_flag = False self.show_grid_flag = False self.show_legend_flag = False # 禁用移动和缩放 self.toolbar.mode = None def home_slot(self): self.make_flag_invalid() self.home_flag = not self.home_flag self.home() def home(self): """ matplotlib lines里面放曲线,patches可以放图形,artists也可以放东西,设为空则可以删除对应的对象 """ if not self.home_flag: return self.toolbar.home() # 将三维图视角还原 for item in self.init_views: self.axes[item[0]].view_init(azim=item[1], elev=item[2]) # 将所有添加的形状去除 for item in self.axes: item.patches = [] item.artists = [] # 去除画在图中的点,是否需要去掉有待考究 self.canvas.draw() def zoom_slot(self): self.make_flag_invalid() self.zoom_flag = not self.zoom_flag self.zoom() def zoom(self): if not self.zoom_flag: return self.toolbar.zoom() def pan_slot(self): self.make_flag_invalid() self.pan_flag = not self.pan_flag self.pan() def pan(self): if not self.pan_flag: return self.toolbar.pan() def save_slot(self): self.toolbar.save_figure() def front_slot(self): self.toolbar._nav_stack.forward() self.toolbar._update_view() def back_slot(self): self.toolbar._nav_stack.back() self.toolbar._update_view() def add_text_slot(self): self.make_flag_invalid() self.add_text_flag = not self.add_text_flag def add_text(self, event): if not self.add_text_flag: return if self.add_text_flag and event.xdata and event.ydata and not hasattr( event.inaxes, 'azim'): text, ok = QtWidgets.QInputDialog.getText(self.canvas.parent(), '输入文字', '添加注释') if ok and text: event.inaxes.text(event.xdata, event.ydata, text) # plt.text(event.xdata, event.ydata, text) self.canvas.draw() def rotate_slot(self): self.make_flag_invalid() self.rotate_flag = not self.rotate_flag def on_rotate(self, event): """ 通过观察发现,旋转时产生的xdata,ydata是以图像中心为原点,正负0.1范围内的数值 """ if not self.rotate_flag: return # 如果鼠标移动过程有按下,视为拖拽,判断当前子图是否有azim属性来判断当前是否3D if event.button and hasattr(event.inaxes, 'azim'): for item in self.init_views: if self.axes[item[0]] == event.inaxes: delta_azim = 180 * event.xdata * -1 / 0.1 delta_elev = 180 * event.ydata / 0.1 azim = delta_azim + item[1] elev = delta_elev + item[2] event.inaxes.view_init(azim=azim, elev=elev) self.canvas.draw() def add_rect_slot(self): # 除了本标记,其余全置False self.make_flag_invalid() self.add_rect_flag = not self.add_rect_flag def add_rect(self, event): if not self.add_rect_flag: return if not event.button and event.inaxes: self.ax_init = event if self.mouse_pressed and event.inaxes.patches: event.inaxes.add_patch(event.inaxes.patches[0]) self.mouse_pressed = False # 仅能在二维图形中画矩形,鼠标按下,且当前子图和初始点的子图相同 try: if event.button and event.inaxes and event.inaxes == self.ax_init.inaxes and not hasattr( event.inaxes, 'azim'): self.mouse_pressed = True if event.inaxes.patches: event.inaxes.patches.pop() rect = plt.Rectangle((self.ax_init.xdata, self.ax_init.ydata), event.xdata - self.ax_init.xdata, event.ydata - self.ax_init.ydata, fill=False, edgecolor='red', linewidth=1) event.inaxes.add_patch(rect) self.canvas.draw() self.canvas.flush_events() except Exception: pass def add_oval_slot(self): self.make_flag_invalid() self.add_oval_flag = not self.add_oval_flag def add_oval(self, event): if not self.add_oval_flag: return if not event.button and event.inaxes: self.ax_init = event if self.mouse_pressed and event.inaxes.patches: event.inaxes.add_patch(event.inaxes.patches[0]) self.mouse_pressed = False try: if event.button and event.inaxes and event.inaxes == self.ax_init.inaxes and not hasattr( event.inaxes, 'azim'): self.mouse_pressed = True if event.inaxes.patches: event.inaxes.patches.pop() oval = Ellipse(xy=(self.ax_init.xdata, self.ax_init.ydata), width=abs(event.xdata - self.ax_init.xdata) * 2, height=abs(event.ydata - self.ax_init.ydata) * 2, angle=0, fill=False, edgecolor='red', linewidth=1) event.inaxes.add_patch(oval) self.canvas.draw() self.canvas.flush_events() except Exception: pass def add_arrow_slot(self): self.make_flag_invalid() self.add_arrow_flag = not self.add_arrow_flag def add_arrow(self, event): if not self.add_arrow_flag: return if not event.button and event.inaxes: self.ax_init = event if self.mouse_pressed and event.inaxes.patches: event.inaxes.add_patch(event.inaxes.patches[0]) self.mouse_pressed = False try: if event.button and event.inaxes and event.inaxes == self.ax_init.inaxes and not hasattr( event.inaxes, 'azim'): self.mouse_pressed = True if event.inaxes.patches: event.inaxes.patches.pop() arrow = event.inaxes.arrow(self.ax_init.xdata, self.ax_init.ydata, event.xdata - self.ax_init.xdata, event.ydata - self.ax_init.ydata, width=0.01, length_includes_head=True, head_width=0.05, head_length=0.1, fc='r', ec='r') event.inaxes.add_patch(arrow) # 请恕我无知,我也不懂这里为什么还要pop一次,我不想思考,但的确这样是正确的。 if event.inaxes.patches: event.inaxes.patches.pop() self.canvas.draw() self.canvas.flush_events() except Exception: pass def add_point_slot(self): self.make_flag_invalid() self.add_point_flag = not self.add_point_flag # def add_point(self, event): # if not self.add_point_flag: # return # if event.inaxes and event.button and not hasattr(event.inaxes, 'azim'): # x_range = np.array(event.inaxes.get_xlim()) # y_range = np.array(event.inaxes.get_ylim()) # self.offset = np.sqrt(np.sum((x_range - y_range) ** 2)) / 20 # 将坐标轴范围的1/50视为误差 # self.nearest_point = None # d_min = 10 * self.offset # for point in event.inaxes.artists: # xt, yt = point.get_data() # d = ((xt - event.xdata) ** 2 + (yt - event.ydata) ** 2) ** 0.5 # if d <= self.offset and d < d_min: # 如果在误差范围内,移动该点 # d_min = d # self.nearest_point = point # if self.nearest_point: # new_point = Line2D([event.xdata], [event.ydata], ls="", # marker='o', markerfacecolor='r', # animated=False) # event.inaxes.add_artist(new_point) # event.inaxes.artists.remove(self.nearest_point) # self.canvas.restore_region(self.bg) # event.inaxes.draw_artist(new_point) # self.canvas.blit(event.inaxes.bbox) # self.bg = self.canvas.copy_from_bbox(event.inaxes.bbox) def add_point(self, event): if not self.add_point_flag: return if event.name == 'pick_event': self.artist = event.artist return if event.name == 'button_press_event' and not self.artist and hasattr( event, 'inaxes') and not hasattr(event.inaxes, 'azim'): point = Line2D([event.xdata], [event.ydata], ls="", marker='o', markerfacecolor='r', animated=False, pickradius=5, picker=True) event.inaxes.add_artist(point) self.canvas.draw() return if event.name == 'motion_notify_event' and self.artist and hasattr( event, 'inaxes') and event.button and not hasattr( event.inaxes, 'azim'): xy = self.artist.get_data() if len(xy[0]) == 1: # 判断该对象是否是一个点。 self.artist.set_data(([event.xdata], [event.ydata])) self.canvas.draw() if event.name == 'button_release_event': self.artist = None def add_style_slot(self): self.make_flag_invalid() self.add_style_flag = not self.add_style_flag def add_style(self, event): if not self.add_style_flag: return if event.name == 'pick_event': self.artist = event.artist if self.artist and event.name == 'button_press_event': for line in event.inaxes.lines: if self.artist != line: line.set_alpha(0.5) else: line.set_alpha(1) self.canvas.draw_idle() if event.button == 3: self.contextMenu.popup(QCursor.pos()) # 2菜单显示的位置 self.contextMenu.show() return elif event.button == 1: self.artist = None return if not self.artist and event.name == 'button_press_event' and event.button == 1: for line in event.inaxes.lines: line.set_alpha(1) self.canvas.draw_idle() def show_legend_slot(self): legend_titles = [] for index in range(len(self.current_subplot.lines)): legend_titles.append('curve ' + str(index + 1)) # 从1开始算 if self.current_subplot.lines: # 如果存在曲线才允许画图例 leg = self.current_subplot.legend(self.current_subplot.lines, legend_titles) leg.set_draggable(True) # 设置legend可拖拽 for legline in leg.get_lines(): legline.set_pickradius(10) legline.set_picker(True) # 给每个legend设置可点击 self.canvas.draw() def change_legend(self, event): if event.name == 'pick_event': self.artist = event.artist if self.artist and event.name == 'button_press_event' and event.button == 3: self.contextMenu.popup(QCursor.pos()) # 2菜单显示的位置 self.contextMenu.show() def show_colorbar_slot(self): # print(self.current_subplot.curves) pass # self.canvas.figure.colorbar(self.canvas,self.current_subplot) def rightMenuShow(self): self.contextMenu = QMenu() self.actionStyle = self.contextMenu.addAction('修改曲线样式') self.actionLegend = self.contextMenu.addAction('修改图例样式') self.actionCurve = self.contextMenu.addAction('修改曲线类型') self.actionStyle.triggered.connect(self.styleHandler) self.actionLegend.triggered.connect(self.legendHandler) self.actionLegend.triggered.connect(self.curveHandler) def styleHandler(self): print(self.artist) def legendHandler(self): print(self.artist) def curveHandler(self): print(self.artist) def mainView_slot(self): if hasattr(self.current_subplot, 'azim'): self.current_subplot.view_init(azim=0, elev=0) self.canvas.draw() def leftView_slot(self): if hasattr(self.current_subplot, 'azim'): self.current_subplot.view_init(azim=90, elev=0) self.canvas.draw() def rightView_slot(self): if hasattr(self.current_subplot, 'azim'): self.current_subplot.view_init(azim=-90, elev=0) self.canvas.draw() def topView_slot(self): if hasattr(self.current_subplot, 'azim'): self.current_subplot.view_init(azim=0, elev=90) self.canvas.draw() def bottomView_slot(self): if hasattr(self.current_subplot, 'azim'): self.current_subplot.view_init(azim=0, elev=-90) self.canvas.draw() def backView_slot(self): if hasattr(self.current_subplot, 'azim'): self.current_subplot.view_init(azim=180, elev=0) self.canvas.draw() def show_grid_slot(self): self.show_grid_flag = not self.show_grid_flag self.current_subplot.grid(self.show_grid_flag) self.canvas.draw_idle() def init_gui(self): self.toolbar._update_view() def combobox_slot(self): self.current_subplot = self.axes[ self.comboBox.currentIndex()] # 将当前选择付给子图对象 def axes_control_slot(self): if not self.current_subplot: QtWidgets.QMessageBox.warning(self.canvas.parent(), "错误", "没有可选的子图!") return Ui_Form_Manager(self.current_subplot, self.canvas) def show(self): super().show()
class Window(QtWidgets.QDialog): index = 0 def __init__(self, parent=None): super().__init__(parent) self.figure = plt.figure() self.axes = self.figure.add_subplot(111, projection='3d') # We want the axes cleared every time plot() is called # self.axes.hold(False) self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Just some button self.button1 = QtWidgets.QPushButton('上一帧') self.button1.clicked.connect(self.up_pic) self.button2 = QtWidgets.QPushButton('下一帧') self.button2.clicked.connect(self.down_pic) self.button3 = QtWidgets.QPushButton('传输配置文件') self.button3.clicked.connect(self.send_config) self.button4 = QtWidgets.QPushButton('无用') self.button4.clicked.connect(self.home) # set the layout layout = QtWidgets.QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) btnlayout = QtWidgets.QHBoxLayout() btnlayout.addWidget(self.button1) btnlayout.addWidget(self.button2) btnlayout.addWidget(self.button3) btnlayout.addWidget(self.button4) qw = QtWidgets.QWidget(self) qw.setLayout(btnlayout) layout.addWidget(qw) self.setLayout(layout) self.res = [] def home(self): self.toolbar.home() def down_pic(self): ''' plot some random stuff ''' tmp, index = self.prvoid_data() self.axes.clear() # self.axes.plot(data, '*-') # self.canvas.draw() # for i in range(3): # print(tmp[:10]) for i in range(Window.index + 1): tmp_re = np.array(tmp[i]) self.axes.scatter(tmp_re[:, 0], tmp_re[:, 1], tmp_re[:, 2], marker='o', c=self.cValue[i % 4], s=8, label='class ' + str(Window.index)) Window.index = (Window.index + 1) if Window.index == self.n: Window.index = 0 # plt.text(1,2,1, ha='center', va='center') self.axes.set_xlabel('X 轴') self.axes.set_ylabel('Y 轴') self.axes.set_zlabel('Z 轴') self.canvas.draw() print(Window.index) def send_config(self): PortControlpoint.open_port() # print("f") def prvoid_data(self): data = { "1": [{ "x": 2, "y": 4, "z": 5 }, { "x": 3, "y": 4, "z": 2 }, { "x": 1, "y": 7, "z": 4 }], "2": [{ "x": 2, "y": 2, "z": 6 }, { "x": 3, "y": 4, "z": 8 }, { "x": 5, "y": 7, "z": 6 }], "3": [{ "x": 5, "y": 7, "z": 2 }, { "x": 1, "y": 5, "z": 6 }, { "x": 7, "y": 2, "z": 1 }], } if not self.res: with open(r'PortControl\hi.json', 'r', encoding='utf-8') as f: txt = json.load(f) for i in txt: t = [] for j in txt[i]: tt = [j['x'] * 10, j['y'] * 10, j['z'] * 10] t.append(tt) self.res.append(t) print(self.res) self.cValue = ['r', 'y', 'g', 'b'] self.n = len(self.res) print(self.n, "fffffffffffffff") tmp = np.array(self.res) return tmp, Window.index def randomcolor(self): colorArr = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' ] color = "" for i in range(6): color += colorArr[random.randint(0, 14)] return "#" + color def up_pic(self): ''' plot some random stuff ''' tmp, index = self.prvoid_data() self.axes.clear() # self.axes.plot(data, '*-') # self.canvas.draw() for i in range(Window.index + 1): tmp_re = np.array(tmp[i]) self.axes.scatter(tmp_re[:, 0], tmp_re[:, 1], tmp_re[:, 2], marker='o', c=self.cValue[i % 4], s=8, label='class ' + str(Window.index)) Window.index = Window.index - 1 if Window.index == -1: Window.index = self.n - 1 self.axes.set_xlabel('X 轴') self.axes.set_ylabel('Y 轴') self.axes.set_zlabel('Z 轴') self.canvas.draw() print(Window.index)