在GUI中显示来自外部源的数据
我对这个问题有点迷茫,想用Python的Tkinter来写一个图形界面,但我最开始是用Qt的,发现这个问题似乎在所有的图形界面框架中都有,可能是因为我理解得不够透彻。
在这个情况下,数据是通过一个命名管道传来的,我想把管道里传来的内容显示在一个文本框里。我试过让一个线程监听管道,另一个线程来创建图形界面,但无论哪种情况,总是有一个线程卡住了,或者图形界面根本没法创建。
有没有什么建议呢?
3 个回答
0
我做类似的事情时,会用一个单独的线程来监听管道。这个线程有一个指针或者句柄可以回到图形界面,这样它就能把数据发送到界面上显示。
我想你也可以在图形界面的更新或事件循环里处理这些,但你得确保在读取管道时不会阻塞。之所以用单独的线程,是因为我需要对传过来的数据进行很多处理。
哦,对了,在显示数据时,记得一次要处理适量的“块”。因为如果一次处理太多,很容易把消息队列(至少在Windows上)弄满,这样就会影响到发送更新命令到文本框的效率。
0
以前我在做图形用户界面(GUI)的时候,需要从外部设备(比如以太网插口)读取数据。我通常会开一个单独的线程来处理这些外部设备的工作,同时设置一个定时回调(一般是半秒一次),用来更新显示外部数据的界面组件。
0
这是我在Windows上会这样做的方法:
import wx, wx.lib.newevent, threading
import win32event, win32pipe, win32file, pywintypes, winerror
NewMessage, EVT_NEW_MESSAGE = wx.lib.newevent.NewEvent()
class MessageNotifier(threading.Thread):
pipe_name = r"\\.\pipe\named_pipe_demo"
def __init__(self, frame):
threading.Thread.__init__(self)
self.frame = frame
def run(self):
open_mode = win32pipe.PIPE_ACCESS_DUPLEX | win32file.FILE_FLAG_OVERLAPPED
pipe_mode = win32pipe.PIPE_TYPE_MESSAGE
sa = pywintypes.SECURITY_ATTRIBUTES()
sa.SetSecurityDescriptorDacl(1, None, 0)
pipe_handle = win32pipe.CreateNamedPipe(
self.pipe_name, open_mode, pipe_mode,
win32pipe.PIPE_UNLIMITED_INSTANCES,
0, 0, 6000, sa
)
overlapped = pywintypes.OVERLAPPED()
overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None)
while 1:
try:
hr = win32pipe.ConnectNamedPipe(pipe_handle, overlapped)
except:
# Error connecting pipe
pipe_handle.Close()
break
if hr == winerror.ERROR_PIPE_CONNECTED:
# Client is fast, and already connected - signal event
win32event.SetEvent(overlapped.hEvent)
rc = win32event.WaitForSingleObject(
overlapped.hEvent, win32event.INFINITE
)
if rc == win32event.WAIT_OBJECT_0:
try:
hr, data = win32file.ReadFile(pipe_handle, 64)
win32file.WriteFile(pipe_handle, "ok")
win32pipe.DisconnectNamedPipe(pipe_handle)
wx.PostEvent(self.frame, NewMessage(data=data))
except win32file.error:
continue
class Messages(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.messages = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_READONLY)
self.Bind(EVT_NEW_MESSAGE, self.On_Update)
def On_Update(self, event):
self.messages.Value += "\n" + event.data
app = wx.PySimpleApp()
app.TopWindow = Messages()
app.TopWindow.Show()
MessageNotifier(app.TopWindow).start()
app.MainLoop()
可以通过发送一些数据来测试一下:
import win32pipe
print win32pipe.CallNamedPipe(r"\\.\pipe\named_pipe_demo", "Hello", 64, 0)
(在这种情况下,你也会收到一个回复)