У меня небольшая проблема со средством просмотра последовательного порта. Я запрограммировал файл python для чтения данных с моего COM-порта, который получает их с моей платы Arduino. Следующий файл - это пример кода с этого сайта форума (это графопостроитель в реальном времени). Оба кода хороши и просты для понимания, но есть одна фатальная проблема. Первый файл - считыватель COM-порта использует библиотеку с именем tkinter, а второй - pyqt5. Я понятия не имел, как разделить эти два файла в один (чтобы использовать только tkinter), но я убедился, что, возможно, есть одно решение: открыть файл создания графиков из первого.
Как я могу заставить один python файл запустить другой?
Моя проблема: я не могу открыть его. Я использовал команды из упомянутого URL и поместил их в отмеченное место в коде. Мой терминал (когда я запускаю файл, преобразованный в .exe, говорит, что в каталоге нет файла "modul1.py", я понятия не имею, что не так ...
Terminal.py
import tkinter as tk
import tkinter.scrolledtext as tkscrolledtext
from tkinter import *
from tkinter import filedialog
import serial_rx_tx
import _thread
import time
import webbrowser
from tkinter import messagebox
# globals
serialPort = serial_rx_tx.SerialPort()
logFile = None
global str_message
root = tk.Tk() # create a Tk root window
root.title( "TERMINAL - Serial Data Terminal v1.01" )
# set up the window size and position
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
window_width = screen_width/2
window_height = screen_width/3
window_position_x = screen_width/2 - window_width/2
window_position_y = screen_height/2 - window_height/2
root.geometry('%dx%d+%d+%d' % (window_width, window_height, window_position_x, window_position_y))
# scrolled text box used to display the serial data
frame = tk.Frame(root, bg='cyan')
frame.pack(side="bottom", fill='both', expand='no')
textbox = tkscrolledtext.ScrolledText(master=frame, wrap='word', width=180, height=28) #width=characters, height=lines
textbox.pack(side='bottom', fill='y', expand=True, padx=0, pady=0)
textbox.config(font="bold")
#COM Port label
label_comport = Label(root,width=10,height=2,text="COM Port:")
label_comport.place(x=10,y=26)
label_comport.config(font="bold")
#COM Port entry box
comport_edit = Entry(root,width=10)
comport_edit.place(x=100,y=36)
comport_edit.config(font="bold")
comport_edit.insert(END,"COM7")
# serial data callback function
def OnReceiveSerialData(message):
global str_message
str_message = message.decode("utf-8")
textbox.insert('1.0', str_message)
def Dataprint():
str_message
# Register the callback above with the serial port object
serialPort.RegisterReceiveCallback(OnReceiveSerialData)
def sdterm_main():
root.after(200, sdterm_main) # run the main loop once each 200 ms
#
# commands associated with button presses
#
def OpenCommand():
if button_openclose.cget("text") == 'Open COM Port':
comport = comport_edit.get()
baudrate = baudrate_edit.get()
serialPort.Open(comport,baudrate)
button_openclose.config(text='Close COM Port')
textbox.insert('1.0', "COM Port Opened\r\n")
elif button_openclose.cget("text") == 'Close COM Port':
if button_replaylog.cget('text') == 'Stop Replay Log':
textbox.insert('1.0',"Stop Log Replay first\r\n")
else:
serialPort.Close()
button_openclose.config(text='Open COM Port')
textbox.insert('1.0',"COM Port Closed\r\n")
def ClearDataCommand():
textbox.delete('1.0',END)
def SendDataCommand():
message = senddata_edit.get()
if serialPort.IsOpen():
message += '\r\n'
serialPort.Send(message)
textbox.insert('1.0',message)
else:
textbox.insert('1.0', "Not sent - COM port is closed\r\n")
def ReplayLogFile():
try:
if logFile != None:
readline = logFile.readline()
global serialPort
serialPort.Send(readline)
except:
print("Exception in ReplayLogFile()")
def ReplayLogThread():
while True:
time.sleep(1.0)
global logFile
if serialPort.IsOpen():
if logFile != None:
ReplayLogFile()
def OpenLogFile():
if not serialPort.IsOpen():
textbox.insert('1.0', "Open COM port first\r\n")
else:
if button_replaylog.cget('text') == 'Replay Log':
try:
root.filename = filedialog.askopenfilename(initialdir="/", title="Select file",
filetypes=(("log files", "*.log"), ("all files", "*.*")))
global logFile
logFile = open(root.filename,'r')
_thread.start_new_thread(ReplayLogThread, ())
button_replaylog.config(text='Stop Log Replay')
textbox.insert('1.0', "Sending to open COM port from: " + root.filename + "\r\n")
except:
textbox.insert('1.0', "Could not open log file\r\n")
else:
button_replaylog.config(text='Replay Log')
textbox.insert('1.0', "Stopped sending messages to open COM port\r\n")
logFile = None
def DisplayAbout():
tk.messagebox.showinfo("About")
def TutorialsWebPage():
tk.messagebox.showinfo("www.gykovysat.cz")
def Openport():
execfile('modul1.py')
# COM Port open/close button
button_openclose = Button(root,text="Open COM Port",width=20,command=OpenCommand)
button_openclose.config(font="bold")
button_openclose.place(x=210,y=30)
#Clear Rx Data button
button_cleardata = Button(root,text="Clear Rx Data",width=20,command=ClearDataCommand)
button_cleardata.config(font="bold")
button_cleardata.place(x=210,y=72)
#Send Message button
button_senddata = Button(root,text="Send Message",width=20,command=SendDataCommand)
button_senddata.config(font="bold")
button_senddata.place(x=420,y=72)
#Replay Log button
button_replaylog = Button(root,text="Replay Log",width=20,command=OpenLogFile)
button_replaylog.config(font="bold")
button_replaylog.place(x=420,y=30)
#About button
button_about = Button(root,text="About",width=16,command=DisplayAbout)
button_about.config(font="bold")
button_about.place(x=620,y=30)
#Tutorials
button_tutorials = Button(root,text="Tutorials",width=16,command=execfile('modul1.py'))
#
#
#
#
# !!!!!!!!!!!!!!!!!UP HERE!!!!!!!!!!!!!!
#
#
#
#
#
#
#
#
#
#
#
#
#
button_tutorials.config(font="bold")
button_tutorials.place(x=780,y=30)
#
# data entry labels and entry boxes
#
#Send Data entry box
senddata_edit = Entry(root,width=34)
senddata_edit.place(x=620,y=78)
senddata_edit.config(font="bold")
senddata_edit.insert(END,"Message")
#Baud Rate label
label_baud = Label(root,width=10,height=2,text="Baud Rate:")
label_baud.place(x=10,y=70)
label_baud.config(font="bold")
#Baud Rate entry box
baudrate_edit = Entry(root,width=10)
baudrate_edit.place(x=100,y=80)
baudrate_edit.config(font="bold")
baudrate_edit.insert(END,"9600")
#
# The main loop
#
root.after(200, sdterm_main)
root.mainloop()
#
Modul1.py
import sys
import os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import functools
import numpy as np
import random as rd
import matplotlib
matplotlib.use("Qt5Agg")
from matplotlib.figure import Figure
from matplotlib.animation import TimedAnimation
from matplotlib.lines import Line2D
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import time
import threading
import serial_rx_tx
from terminal import Dataprint
class CustomMainWindow(QMainWindow):
def __init__(self):
super(CustomMainWindow, self).__init__()
# Define the geometry of the main window
self.setGeometry(300, 300, 800, 400)
self.setWindowTitle("my first window")
# Create FRAME_A
self.FRAME_A = QFrame(self)
self.FRAME_A.setStyleSheet("QWidget { background-color: %s }" % QColor(210,210,235,255).name())
self.LAYOUT_A = QGridLayout()
self.FRAME_A.setLayout(self.LAYOUT_A)
self.setCentralWidget(self.FRAME_A)
# Place the zoom button
self.zoomBtn = QPushButton(text = 'zoom')
self.zoomBtn.setFixedSize(100, 50)
self.zoomBtn.clicked.connect(self.zoomBtnAction)
self.LAYOUT_A.addWidget(self.zoomBtn, *(0,0))
# Place the matplotlib figure
self.myFig = CustomFigCanvas()
self.LAYOUT_A.addWidget(self.myFig, *(0,1))
# Add the callbackfunc to ..
myDataLoop = threading.Thread(name = 'myDataLoop', target = dataSendLoop, daemon = True, args = (self.addData_callbackFunc,))
myDataLoop.start()
self.show()
return
def zoomBtnAction(self):
print("zoom in")
self.myFig.zoomIn(5)
return
def addData_callbackFunc(self, value):
# print("Add data: " + str(value))
self.myFig.addData(value)
return
''' End Class '''
class CustomFigCanvas(FigureCanvas, TimedAnimation):
def __init__(self):
self.addedData = []
print(matplotlib.__version__)
# The data
self.xlim = 200
self.n = np.linspace(0, self.xlim - 1, self.xlim)
a = []
b = []
a.append(2.0)
a.append(4.0)
a.append(2.0)
b.append(4.0)
b.append(3.0)
b.append(4.0)
self.y = (self.n * 0.0) + 50
# The window
self.fig = Figure(figsize=(5,5), dpi=100)
self.ax1 = self.fig.add_subplot(111)
# self.ax1 settings
self.ax1.set_xlabel('time')
self.ax1.set_ylabel('raw data')
self.line1 = Line2D([], [], color='blue')
self.line1_tail = Line2D([], [], color='red', linewidth=2)
self.line1_head = Line2D([], [], color='red', marker='o', markeredgecolor='r')
self.ax1.add_line(self.line1)
self.ax1.add_line(self.line1_tail)
self.ax1.add_line(self.line1_head)
self.ax1.set_xlim(0, self.xlim - 1)
self.ax1.set_ylim(0, 100)
FigureCanvas.__init__(self, self.fig)
TimedAnimation.__init__(self, self.fig, interval = 50, blit = True)
return
def new_frame_seq(self):
return iter(range(self.n.size))
def _init_draw(self):
lines = [self.line1, self.line1_tail, self.line1_head]
for l in lines:
l.set_data([], [])
return
def addData(self, value):
self.addedData.append(value)
return
def zoomIn(self, value):
bottom = self.ax1.get_ylim()[0]
top = self.ax1.get_ylim()[1]
bottom += value
top -= value
self.ax1.set_ylim(bottom,top)
self.draw()
return
def _step(self, *args):
# Extends the _step() method for the TimedAnimation class.
try:
TimedAnimation._step(self, *args)
except Exception as e:
self.abc += 1
print(str(self.abc))
TimedAnimation._stop(self)
pass
return
def _draw_frame(self, framedata):
margin = 2
while(len(self.addedData) > 0):
self.y = np.roll(self.y, -1)
self.y[-1] = self.addedData[0]
del(self.addedData[0])
self.line1.set_data(self.n[ 0 : self.n.size - margin ], self.y[ 0 : self.n.size - margin ])
self.line1_tail.set_data(np.append(self.n[-10:-1 - margin], self.n[-1 - margin]), np.append(self.y[-10:-1 - margin], self.y[-1 - margin]))
self.line1_head.set_data(self.n[-1 - margin], self.y[-1 - margin])
self._drawn_artists = [self.line1, self.line1_tail, self.line1_head]
return
''' End Class '''
# You need to setup a signal slot mechanism, to
# send data to your GUI in a thread-safe way.
# Believe me, if you don't do this right, things
# go very very wrong..
class Communicate(QObject):
data_signal = pyqtSignal(float)
''' End Class '''
def dataSendLoop(addData_callbackFunc):
# Setup the signal-slot mechanism.
mySrc = Communicate()
mySrc.data_signal.connect(addData_callbackFunc)
# Simulate some data
n = np.linspace(0, 499, 500)
y = Dataprint()
i = 0
while(True):
if(i > 499):
i = 0
time.sleep(0.1)
mySrc.data_signal.emit(y[i]) # <- Here you emit a signal!
i += 1
###
###
if __name__== '__main__':
app = QApplication(sys.argv)
QApplication.setStyle(QStyleFactory.create('Plastique'))
myGUI = CustomMainWindow()
sys.exit(app.exec_())