Python:允许作为类创建的单独进程读取/写入变量

时间:2018-07-27 04:01:16

标签: python tkinter python-multiprocessing pyserial

我正在开发一个项目,该项目将在一个进程中运行一个tkinter GUI,另一个进程正在通过pyserial从Arduino读取数据。这些过程是使用基于类的方法定义的,如this stackoverflow post所示。

我希望能够让tkinter类发送将通过串行线路发送的消息,并且让tkinter类能够从Arduino读取数据。我知道,如果我要读取所有传入的数据(例如,向arduino发送信息),则最好使用队列,但是为了使数据显示在tkinter GUI上,我只想定期轮询最新数据从arduino收到的线路。据我所知,在进程之间共享变量的最佳方法是使用管理器,但是所有使用管理器的示例都不使用基于类的进程。

我可以找到的唯一示例是this stackexchange post。但是,他编写的示例还不完整,我似乎无法弄清楚还需要在代码中添加什么才能使该方法起作用。

我想我的问题是双重的:

  1. 如果不是的话,经理班是最好的方法
  2. 我如何准确地共享数据,因为我的所有尝试似乎都没有在进程之间共享数据。

这是我编写的代码(没有经理类)

import tkinter as tk
import multiprocessing
import serial
import time
from multiprocessing.managers import BaseManager


# pylint: disable=C0111

accData = [1, 2, 3]
gyroData = [4, 5, 6]
magData = [7, 8, 9]
altitude = 10
temp = 11
pres = 12


class SerCotrol(multiprocessing.Process):

    def run(self):
        ser = serial.Serial('COM4', 9600)
        while not self.exit.is_set():
            s = ser.write(b'h')
            s = ser.read(10)
            s = s.decode("utf-8")
            x = s.split('\t')
            for i, num in enumerate(x):
                try:
                    x[i] = int(float(num))
                except ValueError:
                    pass

        ser.close()

    def __init__(self, shared):
        self.exit = multiprocessing.Event()
        multiprocessing.Process.__init__(self)
        self.shared = shared

    def shutdown(self):
        print("Shutdown initiated")
        self.exit.set()


class GUI():

    def __init__(self, master):

        master.title("A simple GUI")

        self.num = 0
        self.labelNum = tk.IntVar()
        self.labelNum.set(self.num)
        self.label = tk.Label(master, textvariable=self.labelNum)
        self.accString = tk.StringVar()
        self.accString.set('Accleration\nX: %.5f\nY: %.5f\nZ: %.5f' %
                           (accData[0], accData[1], accData[2]))
        self.gyroString = tk.StringVar()
        self.gyroString.set('Gyros\nX: %.5f\nY: %.5f\nZ: %.5f' %
                            (gyroData[0], gyroData[1], gyroData[2]))
        self.magString = tk.StringVar()
        self.magString.set('Magnetometer\nX: %.5f\nY: %.5f\nZ: %.5f' % (
            magData[0], magData[1], magData[2]))
        self.presString = tk.StringVar()
        self.presString.set('Pressure: \n%.5f' % (pres))
        self.tempString = tk.StringVar()
        self.tempString.set('Tempature: \n%.5f' % (temp))
        self.altString = tk.StringVar()
        self.altString.set('Alititude: \n%.5f' % (altitude))

        self.groundMode = tk.Button(
            master, text='GROUND\nREADY', height=10, width=20)
        self.launch = tk.Button(master, text='BOOST', width=20, height=10)
        self.stabilizeFlight = tk.Button(
            master, text='SEPARATE', height=10, width=20)
        self.targetAq = tk.Button(
            master, text='STABILIZE', height=10, width=20)
        self.recovery = tk.Button(master, text='SEARCH', height=10, width=20)
        self.flightComplete = tk.Button(
            master, text='ORBIT', height=10, width=20)
        self.landed = tk.Button(master, text='LANDED', height=10, width=20)
        self.abort_button = tk.Button(
            master, text="ABORT!", command=self.abort, height=10, background='red')
        self.close_button = tk.Button(master, text="Close", command=self.quit)
        self.accDisp = tk.Label(
            master, textvariable=self.accString, font=("TkDefaultFont", 10))
        self.gyroDisp = tk.Label(
            master, textvariable=self.gyroString, font=("TkDefaultFont", 10))
        self.magDisp = tk.Label(
            master, textvariable=self.magString, font=("TkDefaultFont", 10))
        self.presDisp = tk.Label(
            master, textvariable=self.presString, font=("TkDefaultFont", 10))
        self.tempDisp = tk.Label(
            master, textvariable=self.tempString, font=("TkDefaultFont", 10))
        self.altDisp = tk.Label(
            master, textvariable=self.altString, font=("TkDefaultFont", 10))
        self.startCom = tk.Button(
            master, text="Start Communication", command=self.startComProcess)

        self.label.grid(row=0, sticky=(tk.E, tk.W))
        self.groundMode.grid(row=1, sticky=(tk.E, tk.W, tk.S))
        self.launch.grid(row=1, column=1, sticky=(tk.E, tk.W, tk.S))
        self.stabilizeFlight.grid(row=1, column=2, sticky=(tk.E, tk.W, tk.S))
        self.targetAq.grid(row=1, column=3, sticky=(tk.E, tk.W, tk.S))
        self.recovery.grid(row=1, column=4,  sticky=(tk.E, tk.W, tk.S))
        self.flightComplete.grid(row=1, column=5,  sticky=(tk.E, tk.W, tk.S))
        self.landed.grid(row=1, column=6, sticky=(tk.E, tk.W, tk.S))
        self.abort_button.grid(row=2, columnspan=7, sticky=(tk.E, tk.W, tk.N))
        self.close_button.grid(row=3, columnspan=7)
        self.startCom.grid(row=4, columnspan=7)
        self.accDisp.grid(row=5, column=0)
        self.gyroDisp.grid(row=5, column=1)
        self.magDisp.grid(row=5, column=2)
        self.presDisp.grid(row=5, column=3)
        self.tempDisp.grid(row=5, column=4)
        self.altDisp.grid(row=6, column=3)

    @classmethod
    def quit(self):
        process.shutdown()
        print(process.is_alive())
        root.quit()

    @classmethod
    def abort(self):
        print(SharedData().get_value())
        print("ABORTING!")

    @classmethod
    def startComProcess(self):
        process.start()

    def getData(self):
        pass

if __name__ == "__main__":
    # ShareManager.register(BaseManager)
    process = SerCotrol()
    root = tk.Tk()
    root.rowconfigure((1), weight=1, uniform='test')
    root.columnconfigure((0, 1, 2, 3, 4, 5, 6), weight=1)
    GUI = GUI(root)
    root.mainloop()

这是相同的代码,但是最近一次尝试使用manager类:

import tkinter as tk
import multiprocessing
import serial
import time
from multiprocessing.managers import BaseManager


# pylint: disable=C0111

accData = [1, 2, 3]
gyroData = [4, 5, 6]
magData = [7, 8, 9]
altitude = 10
temp = 11
pres = 12


class SharedData():

    def __init__(self):
        self._data = []

    def update(self, value):
        self._data = value

    def get_value(self):
        return self._data

class SerCotrol(multiprocessing.Process):

    def run(self):
        ser = serial.Serial('COM4', 9600)
        while not self.exit.is_set():
            s = ser.write(b'h')
            s = ser.read(10)
            s = s.decode("utf-8")
            x = s.split('\t')
            for i, num in enumerate(x):
                try:
                    x[i] = int(float(num))
                except ValueError:
                    pass
            SharedData().update(x)
            # print(manager)

        ser.close()

    def __init__(self, shared):
        self.exit = multiprocessing.Event()
        multiprocessing.Process.__init__(self)
        self.shared = shared

    def shutdown(self):
        print("Shutdown initiated")
        self.exit.set()


class GUI():

    def __init__(self, master):

        master.title("A simple GUI")

        self.num = 0
        self.labelNum = tk.IntVar()
        self.labelNum.set(self.num)
        self.label = tk.Label(master, textvariable=self.labelNum)
        self.accString = tk.StringVar()
        self.accString.set('Accleration\nX: %.5f\nY: %.5f\nZ: %.5f' %
                           (accData[0], accData[1], accData[2]))
        self.gyroString = tk.StringVar()
        self.gyroString.set('Gyros\nX: %.5f\nY: %.5f\nZ: %.5f' %
                            (gyroData[0], gyroData[1], gyroData[2]))
        self.magString = tk.StringVar()
        self.magString.set('Magnetometer\nX: %.5f\nY: %.5f\nZ: %.5f' % (
            magData[0], magData[1], magData[2]))
        self.presString = tk.StringVar()
        self.presString.set('Pressure: \n%.5f' % (pres))
        self.tempString = tk.StringVar()
        self.tempString.set('Tempature: \n%.5f' % (temp))
        self.altString = tk.StringVar()
        self.altString.set('Alititude: \n%.5f' % (altitude))

        self.groundMode = tk.Button(
            master, text='GROUND\nREADY', height=10, width=20)
        self.launch = tk.Button(master, text='BOOST', width=20, height=10)
        self.stabilizeFlight = tk.Button(
            master, text='SEPARATE', height=10, width=20)
        self.targetAq = tk.Button(
            master, text='STABILIZE', height=10, width=20)
        self.recovery = tk.Button(master, text='SEARCH', height=10, width=20)
        self.flightComplete = tk.Button(
            master, text='ORBIT', height=10, width=20)
        self.landed = tk.Button(master, text='LANDED', height=10, width=20)
        self.abort_button = tk.Button(
            master, text="ABORT!", command=self.abort, height=10, background='red')
        self.close_button = tk.Button(master, text="Close", command=self.quit)
        self.accDisp = tk.Label(
            master, textvariable=self.accString, font=("TkDefaultFont", 10))
        self.gyroDisp = tk.Label(
            master, textvariable=self.gyroString, font=("TkDefaultFont", 10))
        self.magDisp = tk.Label(
            master, textvariable=self.magString, font=("TkDefaultFont", 10))
        self.presDisp = tk.Label(
            master, textvariable=self.presString, font=("TkDefaultFont", 10))
        self.tempDisp = tk.Label(
            master, textvariable=self.tempString, font=("TkDefaultFont", 10))
        self.altDisp = tk.Label(
            master, textvariable=self.altString, font=("TkDefaultFont", 10))
        self.startCom = tk.Button(
            master, text="Start Communication", command=self.startComProcess)

        self.label.grid(row=0, sticky=(tk.E, tk.W))
        self.groundMode.grid(row=1, sticky=(tk.E, tk.W, tk.S))
        self.launch.grid(row=1, column=1, sticky=(tk.E, tk.W, tk.S))
        self.stabilizeFlight.grid(row=1, column=2, sticky=(tk.E, tk.W, tk.S))
        self.targetAq.grid(row=1, column=3, sticky=(tk.E, tk.W, tk.S))
        self.recovery.grid(row=1, column=4,  sticky=(tk.E, tk.W, tk.S))
        self.flightComplete.grid(row=1, column=5,  sticky=(tk.E, tk.W, tk.S))
        self.landed.grid(row=1, column=6, sticky=(tk.E, tk.W, tk.S))
        self.abort_button.grid(row=2, columnspan=7, sticky=(tk.E, tk.W, tk.N))
        self.close_button.grid(row=3, columnspan=7)
        self.startCom.grid(row=4, columnspan=7)
        self.accDisp.grid(row=5, column=0)
        self.gyroDisp.grid(row=5, column=1)
        self.magDisp.grid(row=5, column=2)
        self.presDisp.grid(row=5, column=3)
        self.tempDisp.grid(row=5, column=4)
        self.altDisp.grid(row=6, column=3)

    @classmethod
    def quit(self):
        process.shutdown()
        print(process.is_alive())
        root.quit()

    @classmethod
    def abort(self):
        print(SharedData().get_value())
        print("ABORTING!")

    @classmethod
    def startComProcess(self):
        process.start()

    def getData(self):
        pass


class ShareManager(BaseManager):
    pass


ShareManager.register('SharedData', BaseManager)

if __name__ == "__main__":
    # ShareManager.register(BaseManager)
    manager = ShareManager()
    manager.start()
    shared = manager.SharedData()
    process = SerCotrol(shared)
    root = tk.Tk()
    root.rowconfigure((1), weight=1, uniform='test')
    root.columnconfigure((0, 1, 2, 3, 4, 5, 6), weight=1)
    GUI = GUI(root)
    root.mainloop()

请不要使该GUI在大多数情况下不起作用。我的目标是让gui首先简单地将数据打印到命令行,然后再添加将数据发送到GUI中的标签的功能。

请让我知道是否需要任何其他信息,我很乐意提供。

0 个答案:

没有答案