#!/usr/bin/env python
# -*- coding: utf-8 -*-


#
# Client side of the NetworkDemo application
#
# Receive the ball from the server, and display it
#


#
# External dependencies
#
import socket
import sys
import threading
from PyQt4 import QtCore
from PyQt4 import QtGui


#
# Class to receive the ball position from the server (threaded)
#
class BallClient( threading.Thread ) :
	
	#
	# Initialization
	#
	def __init__( self, server, widget ) :

		# Initialize the thread
		super( BallClient, self ).__init__()
		
		# Graphical user interface
		self.widget = widget

		# Ball position
		self.position = [ 0, 0 ]

		# Connect to the server
		self.connection = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
		self.connection.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
		self.connection.connect( ( server, 10000 ) )

	#
	# Thread main loop
	#
	def run( self ) :
		
		# Continuously receive messages from the server
		self.running = True
		while self.running :

			# Receive the message from the server
			message = self.connection.recv( 256 )
			
			# Server is dead
			if not message :
				
				# Stop the client connection
				self.running = False
				break
				
			# Decode the message to get the ball position
			sx, _, sy = message.decode( 'ascii' ).partition( ';' )

			# Save the ball position
			self.position = [ float( sx ), float( sy ) ]

			# Update the widget
			self.widget.update()

		# Close the connection
		self.connection.close()

		# Close the widget
		self.widget.close()


#
# Widget to display the ball
#
class BallWidget( QtGui.QWidget ) :
	
	#
	# Initialization
	#
	def __init__( self, parent = None ) :

		# Initialize the widget
		super( BallWidget, self ).__init__( parent )

		# Change the window title
		self.setWindowTitle( 'NetworkDemo' )
		
		# Change the widget position and size
		self.setGeometry( 0, 0, 1920, 1200 )
		
		# Set the Escape key to close the application
		QtGui.QShortcut( QtGui.QKeySequence( QtCore.Qt.Key_Escape ), self ).activated.connect( self.close )
		
		# Ball client thread
		self.ball = BallClient( sys.argv[ 1 ], self )
		self.ball.start()
		
	#
	# Paint the ball
	#
	def paintEvent( self, event ) :
		
		# Set up the painter
		paint = QtGui.QPainter( self )
		paint.setRenderHint( QtGui.QPainter.Antialiasing )
		paint.setBrush( QtCore.Qt.red )
		
		# Get the ball position
		position = QtCore.QPoint( self.ball.position[0] * self.size().width(),
								  self.ball.position[1] * self.size().height() )
								  
		# Draw the ball
		paint.drawEllipse( position, 60, 60 )

	#
	# Close the widget
	#
	def closeEvent( self, event ) :

		# Stop the ball client
		if self.ball.running :
			self.ball.running = False
			self.ball.join()
			
		# Close the widget
		event.accept()


#
# Main application
#
if __name__ == '__main__' :

	# Start Qt application
	application = QtGui.QApplication( sys.argv )
	widget = BallWidget()
	widget.show()
	sys.exit( application.exec_() )


@@ -504,24 +504,67 @@
 init__()%0A%09%09%0A
+%09%09# Server address%0A%09%09self.server = server%0A%0A
 %09%09#%C2%A0Graphica
@@ -650,16 +650,64 @@
 0, 0 %5D%0A%0A
+%09#%0A%09# Thread main loop%0A%09#%0A%09def run( self ) :%0A%09%09%0A
 %09%09# Conn
@@ -726,21 +726,16 @@
 erver%0A%09%09
-self.
 connecti
@@ -789,29 +789,24 @@
 _STREAM )%0A%09%09
-self.
 connection.s
@@ -862,21 +862,16 @@
 , 1 )%0A%09%09
-self.
 connecti
@@ -884,16 +884,21 @@
 nect( ( 
+self.
 server, 
@@ -912,56 +912,8 @@
  )%0A%0A
-%09#%0A%09# Thread main loop%0A%09#%0A%09def run( self ) :%0A%09%09%0A
 %09%09# 
@@ -1058,21 +1058,16 @@
 ssage = 
-self.
 connecti
@@ -1463,21 +1463,16 @@
 ction%0A%09%09
-self.
 connecti
@@ -1824,20 +1824,20 @@
 e the wi
-dget
+ndow
  positio

Make the client connection on start.