added RPCServerThread; attach RPCServerThread to MainWindow, exposing append method to append to DictList and to MDISubPlot; data from DictList needs to be transposed now; apply pyqtgraph theming
This commit is contained in:
35
mainwin.py
35
mainwin.py
@ -1,11 +1,12 @@
|
||||
import numpy as np
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
from PyQt5.QtWidgets import QMainWindow, QSplitter
|
||||
|
||||
import assets
|
||||
from dictlist import DictList
|
||||
from mdi import MDIArea, MDISubPlot
|
||||
from rpcserverthread import RPCServerThread
|
||||
|
||||
|
||||
X = np.arange(100) / 10
|
||||
@ -13,6 +14,8 @@ X = np.arange(100) / 10
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
|
||||
sig_make_new_plot = pyqtSignal(str, list)
|
||||
|
||||
def __init__(self, *args, title="grum", **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.setWindowTitle(title)
|
||||
@ -24,6 +27,7 @@ class MainWindow(QMainWindow):
|
||||
"exp": [X, np.exp(X)],
|
||||
"log": [X, np.log(X+1)]
|
||||
}
|
||||
data = {k: zip(*v) for k, v in data.items()} # due to the appending of xy pairs, data needs to be transposed
|
||||
self.lst = lst = DictList(data)
|
||||
lst.setAlternatingRowColors(True)
|
||||
lst.doubleClicked.connect(self.on_select_list_item)
|
||||
@ -39,18 +43,41 @@ class MainWindow(QMainWindow):
|
||||
|
||||
self.setCentralWidget(splitter)
|
||||
|
||||
rst = RPCServerThread("localhost", 8000)
|
||||
rst.start()
|
||||
rst.server.register_function(self.append)
|
||||
|
||||
self.sig_make_new_plot.connect(self.make_new_plot)
|
||||
|
||||
|
||||
def append(self, name, xy):
|
||||
lst = self.lst
|
||||
show_it = (name not in lst.data)
|
||||
|
||||
lst.append(name, xy)
|
||||
for sub in self.mdi.subWindowList():
|
||||
if sub.windowTitle() == name:
|
||||
data = lst.data[name]
|
||||
data = list(zip(*data))
|
||||
sub.plot.setData(*data)
|
||||
|
||||
if show_it:
|
||||
data = lst.data[name]
|
||||
self.sig_make_new_plot.emit(name, data)
|
||||
|
||||
|
||||
def on_select_list_item(self, index):
|
||||
key, value = self.lst.get(index)
|
||||
|
||||
#TODO: just a test for dynamic adding
|
||||
self.lst.add("x", [X, X])
|
||||
|
||||
for sub in self.mdi.subWindowList():
|
||||
if sub.windowTitle() == key:
|
||||
self.mdi.setActiveSubWindow(sub)
|
||||
return
|
||||
|
||||
self.make_new_plot(key, value)
|
||||
|
||||
|
||||
def make_new_plot(self, key, value):
|
||||
sub = MDISubPlot(key, value)
|
||||
self.mdi.addSubWindow(sub)
|
||||
sub.show()
|
||||
|
7
mdi.py
7
mdi.py
@ -4,7 +4,7 @@ from PyQt5.QtGui import QPainter
|
||||
from pyqtgraph import PlotWidget
|
||||
|
||||
import assets
|
||||
from theme import MDI_BKG
|
||||
from theme import MDI_BKG, pg_plot_style
|
||||
|
||||
|
||||
class MDIArea(QMdiArea):
|
||||
@ -71,8 +71,11 @@ class MDISubPlot(QMdiSubWindow):
|
||||
# without this, the SubWindow is not removed from the subWindowList
|
||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||
|
||||
data = zip(*data)
|
||||
style = pg_plot_style()
|
||||
|
||||
plt = PlotWidget()
|
||||
plt.plot(*data)
|
||||
self.plot = plt.plot(*data, **style)
|
||||
self.setWidget(plt)
|
||||
|
||||
|
||||
|
61
rpcserverthread.py
Normal file
61
rpcserverthread.py
Normal file
@ -0,0 +1,61 @@
|
||||
import atexit
|
||||
import xmlrpc.server as xrs
|
||||
from threading import Thread
|
||||
|
||||
|
||||
class RPCServerThread(Thread):
|
||||
|
||||
def __init__(self, host, port, *args, **kwargs):
|
||||
super().__init__(daemon=True) # atexit seems to only work for deamon threads
|
||||
|
||||
addr = (host, port)
|
||||
kwargs.setdefault("allow_none", True)
|
||||
self.server = xrs.SimpleXMLRPCServer(addr, *args, **kwargs)
|
||||
|
||||
self.thread_shutdown = None
|
||||
|
||||
|
||||
def run(self):
|
||||
atexit.register(self.wait_for_stop)
|
||||
self.server.serve_forever()
|
||||
|
||||
|
||||
# BaseServer.shutdown docs say:
|
||||
# This must be called while serve_forever() is running in another thread,
|
||||
# or it will deadlock.
|
||||
|
||||
def wait_for_stop(self):
|
||||
if self.thread_shutdown is None:
|
||||
self.stop()
|
||||
self.thread_shutdown.join()
|
||||
print("RPC server stopped")
|
||||
|
||||
def stop(self):
|
||||
self.thread_shutdown = t = Thread(target=self.shutdown)
|
||||
t.start()
|
||||
|
||||
def shutdown(self):
|
||||
self.server.shutdown()
|
||||
self.server.server_close()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from time import sleep
|
||||
|
||||
def test():
|
||||
print("test")
|
||||
return "test"
|
||||
|
||||
rst = RPCServerThread("localhost", 8000)
|
||||
rst.server.register_function(test)
|
||||
rst.server.register_function(rst.stop)
|
||||
rst.start()
|
||||
|
||||
while rst.is_alive():
|
||||
sleep(1)
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user