Che mostra i dati in una GUI in cui i dati provengono da una fonte esterna
-
06-09-2019 - |
Domanda
Sono un po 'perso su come affrontare questo problema, mi piacerebbe scrivere una GUI idealmente usando Tkinter con Python, ma inizialmente ho iniziato con Qt e ha scoperto che il problema si estende sia con tutti i framework GUI o il mio limitato comprensione.
I dati di questo caso è venuta da un tubo di nome, e vorrei per visualizzare ciò che viene attraverso il tubo in una casella di testo. Ho provato con un filo ascoltare sul tubo e un altro di creare l'interfaccia grafica, ma in entrambi i casi un thread sembra sempre per appendere o l'interfaccia grafica non viene mai creato.
Qualche suggerimento?
Soluzione
Ecco il modo in cui lo farei (su 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()
Prova inviando alcuni dati con:
import win32pipe
print win32pipe.CallNamedPipe(r"\\.\pipe\named_pipe_demo", "Hello", 64, 0)
(si ottiene anche una risposta in questo caso)
Altri suggerimenti
Quando ho fatto qualcosa di simile ho usato un thread separato ascolto sul tubo. Il filo ha avuto un puntatore / manico torna alla GUI in modo che possa inviare i dati da visualizzare.
Immagino che si potrebbe fare in loop di aggiornamento / evento della GUI, ma che avrebbe dovuto fare in modo che sta facendo non bloccante si legge sul tubo. L'ho fatto in un thread separato perché ho dovuto fare un sacco di elaborazione sui dati che è venuto attraverso.
Oh, e quando si sta facendo la visualizzazione, assicuratevi di farlo in non banali "pezzi" alla volta. E 'molto facile al massimo fuori la coda di messaggi (su Windows, almeno) che è l'invio di comandi di aggiornamento per la casella di testo.
In passato, quando ho avuto la lettura dei dati di GUI fuori delle cose esterne (es: prese ethernet), ho avuto un thread separato che gestisce la manutenzione della cosa esterna, e di un callback a tempo (in genere impostato su qualcosa come la metà un secondo) per aggiornare il widget GUI che visualizza i dati esterni.