Hello Slicer community.
I’d like to incorporate a function within Slicer that asynchronously waits for reception.
What I want is for the function to execute when Slicer is turned on, asynchronously wait for reception, and if received, send the corresponding value.
I’d like this function to continue running asynchronously independently of other functions.
My function looks like
async def ServerOpen(self):
HOST = '127.0.0.1'
PORT = 65432
print("server open")
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
print(f"{HOST}:{PORT}")
while True:
conn, addr = await loop.sock_accept(s)
await self.receive_data(conn)
async def receive_data(self, conn):
def convert_to_doubles(input_string):
length = len(input_string)
result = []
for i in range(0, length, 2):
substring = input_string[i:i+2]
num = float(substring)
result.append(num)
return result
while True:
data = await loop.sock_recv(conn, 1024)
if not data:
break
received_message = data.decode()
await loop.sock_sendall(conn, data)
numbers = convert_to_doubles(received_message)
print( numbers[0], numbers[1], numbers[2])
center = [numbers[0], numbers[1], numbers[2]]
radius = 6.0
sphereSource = vtk.vtkSphereSource()
sphereSource.SetCenter(center[0], center[1], center[2])
sphereSource.SetRadius(radius)
sphereSource.SetPhiResolution(30)
sphereSource.SetThetaResolution(30)
sphereSource.Update()
sphere = sphereSource.GetOutput()
renderer = slicer.app.layoutManager().threeDWidget(0).threeDView().renderWindow().GetRenderers().GetFirstRenderer()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(sphere)
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer.AddActor(actor)
renderer.ResetCamera()
slicer.app.layoutManager().threeDWidget(0).threeDView().renderWindow().Render()
Where and how should I insert this Python code? Thank you very much as always.
Slicer uses Qt’s event loop, not python’s asyncio. You can look at the code for OpenIGTLink, which I believe uses a timer to periodically check for events, or the WebServer, which uses QSocketNotifier so that events are generated when the network is active.
Slicer’s architecture is different, so you can’t use PyQt, but instead use PythonQt, which is pre-loaded in the Slicer python environment in the qt package. So you would use a line like qt.QTcpServer(). It’ll help you to go through the developer tutorials to learn some of the specifics of the Slicer environment.
Thank you so much sir. I made a code based on your advice.
There’s a little bit of a problem with the code. The function seems to work, but when I run the executives, it only runs cmd and the Slicer UI doesn’t. I want to make the function of this wait for reception similar to Asynco and send a specific code if it gets it after doing something else. I always appreciate it so much and I’d really appreciate any advice.
My code is as follows `self.server = MyTcpServer()
self.server.listen(qt.QHostAddress(“127.0.0.1”), 65432)
Init MyTcpServer is in NavigationWidget's sepup Method and
def checkClientData(self):
for socket in self.server.children():
if isinstance(socket, qt.QTcpSocket):
if socket.bytesAvailable():
data = socket.readAll()
print("Received data from client:", bytes(data).decode())
else:
pass`
and my Class is
class MyTcpServer(qt.QTcpServer):
def __init__(self, parent=None):
super().__init__(parent)
self.newConnection.connect(self.handleConnection)
def handleConnection(self):
client_socket = self.nextPendingConnection()
client_socket.readyRead.connect(self.readData)
def readData(self):
client_socket = self.sender()
if client_socket is not None:
data = client_socket.readAll()
print("Received data from client:", bytes(data).decode())
I don’t understand exactly what you mean here. Can you describe more?
It should happen that QSocketNotifier, as I mentioned earlier, make the entire process event-driven and efficient and generally doesn’t require timers or UI blockage. Try the WebServer and look at the implementation.