Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:如何在保持GUI交互性的同时使用单独进程中的变量更新GUI_Python_User Interface_Tkinter_Multiprocessing_Pipe - Fatal编程技术网

Python:如何在保持GUI交互性的同时使用单独进程中的变量更新GUI

Python:如何在保持GUI交互性的同时使用单独进程中的变量更新GUI,python,user-interface,tkinter,multiprocessing,pipe,Python,User Interface,Tkinter,Multiprocessing,Pipe,在阅读了大量关于多进程、管道等的内容后,我还没有找到答案,但如果答案已经存在,我深表歉意 我有一块外围硬件,我正试图为它创建一个GUI。我想让GUI不断地更新来自外围设备的数据,同时仍然保持用户的交互性。例如,我有一个增益参数,我用它来驱动一个条形图,当它不断被更新时,我希望用户能够点击一个按钮来进行一些操作。下面是一些示例代码。尽管我确信我在这里犯了一些严重的错误,但这实际上几乎起作用,但“退出”按钮仍然没有响应: #!/usr/bin/env python` # -*- coding: ut

在阅读了大量关于多进程、管道等的内容后,我还没有找到答案,但如果答案已经存在,我深表歉意

我有一块外围硬件,我正试图为它创建一个GUI。我想让GUI不断地更新来自外围设备的数据,同时仍然保持用户的交互性。例如,我有一个增益参数,我用它来驱动一个条形图,当它不断被更新时,我希望用户能够点击一个按钮来进行一些操作。下面是一些示例代码。尽管我确信我在这里犯了一些严重的错误,但这实际上几乎起作用,但“退出”按钮仍然没有响应:

#!/usr/bin/env python`
# -*- coding: utf-8 -*-
# 2014-07-24 S. Petit

import matplotlib.pyplot as plt
from serial import Serial
import serial, socket, time, datetime, sys, struct
from datetime import datetime
import numpy as np
import shutil
import os
from random import randint
from Tkinter import *
from multiprocessing import *

dcbSerialPort = 'COM10'

def getGainLNA(pipeToParent):
    try:
        S_dcb = Serial(dcbSerialPort, 115200, timeout=.1)
        print 'Opened DCB at', dcbSerialPort
    except:
        print '\r\n'
        print '*************************************************'
        print 'ERROR: Unable to open', dcbSerialPort, 'serial connection.'
        print '*************************************************'
        print '\r\n'
        raw_input()
        exit()

    while True:
        promptFound = False
        PICreturn = ''
        S_dcb.write('gain\r')
        while not promptFound:
            PICreturn += S_dcb.read(S_dcb.inWaiting())
            if 'DCB>' in PICreturn:
                promptFound = True

        gainLNA = float(PICreturn[20:28].strip())
        gainLNA_scaled = int(100*(gainLNA/33))

        pipeToParent.send(gainLNA_scaled)

    return()

if __name__ == '__main__':

    gainUpdaterPipe, gainUpdaterPipeChild = Pipe()

    lnaGainUpdater = Process(target=getGainLNA, args=(gainUpdaterPipeChild,))
    lnaGainUpdater.start()

    root=Tk()
    root.title = 'AGC'

    while True:
        if gainUpdaterPipe.poll():
            gainLNA = gainUpdaterPipe.recv()
            print gainLNA

            quitButton = Button(text='Quit', command=quit)
            quitButton.grid(row=1, column=0)

            areaAGC = Canvas(width=120, height=100, bg='blue')
            objectAGC = areaAGC.create_polygon(20,20, gainLNA,20, gainLNA,50, 20,50, outline='green', fill='yellow')
            areaAGC.grid(row=0, column=0)

        root.update_idletasks()
谢谢你的帮助。。。 史蒂夫P

编辑:好的,在尝试使用@ebarr的示例之后,我得到了以下内容。标签小部件会随着计数而更新,但条形图不会:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 2014-07-24 S. Petit

import matplotlib.pyplot as plt
from serial import Serial
import serial, socket, time, datetime, sys, struct
from datetime import datetime
import numpy as np
import shutil
import os
from random import randint
import Tkinter as tk
from multiprocessing import *

dcbSerialPort = 'COM10'

# count from 0 to infinity, writing the value to a pipe
def count(pipe,stop):
    ii = 0
    while not stop.is_set():
        ii+=1
        pipe.send(ii)
        time.sleep(1)

class UpdatingGUI(tk.Frame):
    def __init__(self,parent):
        tk.Frame.__init__(self,parent)
        self.parent = parent
        self.parent_pipe, self.child_pipe = Pipe()
        self.stop_event = Event()

        # label to show count value
        self.updating_int = tk.IntVar()
        self.updating_int.set(0)
        self.updating_lbl = tk.Label(self,textvariable=self.updating_int)
        self.updating_lbl.pack()

        # bargraph to show count value
        self.area_barGraph = tk.Canvas(width=120, height=100, bg='blue')
        self.bargraph = self.area_barGraph.create_polygon(10,10, (10+self.updating_int.get()),10, (10+self.updating_int.get()),20, 10,20, outline='green', fill='yellow')
        self.area_barGraph.pack()

        # button that will stay responsive to requests while count is on going
        self.quit_btn = tk.Button(self,text="Quit",command=self.quit)
        self.quit_btn.pack()

        # launch count as a process
        self.counter = Process(target=count,args=(self.child_pipe,self.stop_event))
        self.counter.start()

        # call an update method to check the pipe and update the label
        self.update()

    def quit(self):
        self.stop_event.set()
        self.parent.destroy()

    def update(self):
        # While the pipe has data, read and update the StringVar
        while self.parent_pipe.poll():
            self.updating_int.set(self.parent_pipe.recv())

        # set the update method to run again in 1 seconds time
        self.parent.after(1000,self.update)


def main():
    root = tk.Tk()
    gui = UpdatingGUI(root)
    gui.pack()
    root.mainloop()

# print __name__

if __name__ == "__main__":
    main()

您非常接近一个有效的解决方案。如上所述,在之后使用tkinter
将解决大部分问题

下面是一个单独进程(运行简单计数器)传递可用于更新GUI的状态的最小示例:

import Tkinter as tk
from multiprocessing import Event,Process,Pipe
from time import sleep

# count from 0 to infinity, writing the value to a pipe
def count(pipe,stop):
    ii = 0
    while not stop.is_set():
        ii+=1
        pipe.send(ii)
        sleep(1)

class UpdatingGUI(tk.Frame):
    def __init__(self,parent):
        tk.Frame.__init__(self,parent)
        self.parent = parent
        self.parent_pipe, self.child_pipe = Pipe()
        self.stop_event = Event()

        # label to show count value
        self.updating_txt = tk.StringVar()
        self.updating_txt.set("Waiting...")
        self.updating_lbl = tk.Label(self,textvariable=self.updating_txt)
        self.updating_lbl.pack()

        # button that will stay responsive to requests while count is on going
        self.quit_btn = tk.Button(self,text="Quit",command=self.quit)
        self.quit_btn.pack()

        # launch count as a process
        self.counter = Process(target=count,args=(self.child_pipe,self.stop_event))
        self.counter.start()

        # call an update method to check the pipe and update the label
        self.update()

    def quit(self):
        self.stop_event.set()
        self.parent.destroy()

    def update(self):
        # While the pipe has data, read and update the StringVar
        while self.parent_pipe.poll():
            self.updating_txt.set(self.parent_pipe.recv())

        # set the update method to run again in 1 seconds time
        self.parent.after(1000,self.update)


def main():
    root = tk.Tk()
    gui = UpdatingGUI(root)
    gui.pack()
    root.mainloop()

if __name__ == "__main__":
    main()
更新

作为对更新代码的回应:您已经基本完成了,唯一的问题是您只调用了一次条形图创建者,而它需要添加到您的
update
函数中,如:

def update(self):
    # While the pipe has data, read and update the StringVar                                                                                
    while self.parent_pipe.poll():
        self.updating_int.set(self.parent_pipe.recv())
    dx = self.updating_int.get()
    self.area_barGraph.create_polygon(10,10, (10+dx),10, (10+dx),20, 10,20, outline='green', fill='yellow')
    # set the update method to run again in 1 seconds time                                                                                  
    self.parent.after(1000,self.update)

这将确保每次更新intVar时,图形也会相应地更新。

只是说,
tk
在大多数情况下都被认为是一个玩具gui,您可能想先看看类似于
wxpython
的东西:不要在Tkinter中使用
而在Tkinter中使用
而在
根之后(时间,函数)
要重复运行某个东西,第二:root.mainloop()在哪里?我认为这是一个很好的起点。所以我做了两件事。我将更新变量类更改为
IntVar
,然后尝试使用它来驱动多边形的大小。在图形窗口中,标签小部件会随着计数器计数而更新,但条形图就在那里。我正试图在这里发布一些代码,但我愚蠢地不知道如何让评论窗口接受换行符…如果您想发布代码,请将其作为原始问题进行编辑或发布新问题。听起来您需要为图形部分调用一些更新方法。这很有效,谢谢。我在这里要补充的另一件事是,我必须在每次更新时也绘制一个“背景”矩形,否则,如果我的条形图缩小,则旧的、长的矩形没有被清理。