// MovingBallViewer.java (c) Kari Laitinen // http://www.naturalprogramming.com // 2013-02-06 File created. // 2013-10-03 Last modification. // This program communicates with MovingBallServlet import java.awt.* ; import java.awt.event.* ; import javax.swing.* ; import java.io.* ; import java.net.* ; import java.awt.geom.* ; // The Ball class in this program is almost the same as the Ball class // in file Ball.java. The only difference between these two classes // is that the class below is Serializable. class Ball implements Serializable { int ball_center_point_x = 0 ; int ball_center_point_y = 0 ; Color ball_color = Color.red ; int ball_diameter = 100 ; boolean this_ball_is_activated = false ; public Ball( int given_center_point_x, int given_center_point_y, Color given_color ) { ball_center_point_x = given_center_point_x ; ball_center_point_y = given_center_point_y ; ball_color = given_color ; } public void activate_ball() { this_ball_is_activated = true ; } public void deactivate_ball() { this_ball_is_activated = false ; } public int get_ball_center_point_x() { return ball_center_point_x ; } public int get_ball_center_point_y() { return ball_center_point_y ; } public int get_ball_diameter() { return ball_diameter ; } public void move_right() { ball_center_point_x += 3 ; } public void move_left() { ball_center_point_x -= 3 ; } public void move_up() { ball_center_point_y -= 3 ; } public void move_down() { ball_center_point_y += 3 ; } public void move_this_ball( int movement_in_direction_x, int movement_in_direction_y ) { ball_center_point_x = ball_center_point_x + movement_in_direction_x ; ball_center_point_y = ball_center_point_y + movement_in_direction_y ; } public void move_to_position( int new_center_point_x, int new_center_point_y ) { ball_center_point_x = new_center_point_x ; ball_center_point_y = new_center_point_y ; } public void shrink() { // The if-construct ensures that the ball does not become // too small. if ( ball_diameter > 10 ) { ball_diameter -= 6 ; } } public void enlarge() { ball_diameter += 6 ; } public void set_diameter( int new_diameter ) { if ( new_diameter > 5 ) { ball_diameter = new_diameter ; } } public void set_color( Color new_color ) { ball_color = new_color ; } public boolean contains_point( Point given_point ) { int ball_radius = ball_diameter / 2 ; // Here we use the Pythagorean theorem to calculate the distance // from the given point to the center point of the ball. // See the note at the end of this file. int distance_from_given_point_to_ball_center = (int) Math.sqrt( Math.pow( ball_center_point_x - given_point.x, 2 ) + Math.pow( ball_center_point_y - given_point.y, 2 ) ) ; return ( distance_from_given_point_to_ball_center <= ball_radius ) ; } public boolean intersects_rectangle( Rectangle2D given_rectangle ) { Area this_ball_area = new Area( new Ellipse2D.Float( ball_center_point_x - ball_diameter / 2, ball_center_point_y - ball_diameter / 2, ball_diameter, ball_diameter ) ) ; return this_ball_area.intersects( given_rectangle ) ; } public void draw( Graphics graphics ) { graphics.setColor( ball_color ) ; graphics.fillOval( ball_center_point_x - ball_diameter / 2, ball_center_point_y - ball_diameter / 2, ball_diameter, ball_diameter ) ; graphics.setColor( Color.BLACK ) ; graphics.drawOval( ball_center_point_x - ball_diameter / 2, ball_center_point_y - ball_diameter / 2, ball_diameter, ball_diameter ) ; // If this ball is activated, it will have a thick black edge if ( this_ball_is_activated == true ) { graphics.drawOval( ball_center_point_x - ball_diameter / 2 + 1, ball_center_point_y - ball_diameter / 2 + 1, ball_diameter - 2, ball_diameter - 2 ) ; graphics.drawOval( ball_center_point_x - ball_diameter / 2 + 2, ball_center_point_y - ball_diameter / 2 + 2, ball_diameter - 4, ball_diameter - 4 ) ; } } } class MovingBallViewerPanel extends JPanel implements ActionListener, Runnable { Thread thread_for_ball_updating ; boolean thread_must_be_executed ; JButton refresh_button = new JButton( " REFRESH " ) ; int frame_width, frame_height ; Ball ball_on_screen ; public MovingBallViewerPanel( int given_frame_width, int given_frame_height ) { frame_width = given_frame_width ; frame_height = given_frame_height ; // Let's create the Ball object so that the ball is in the // middle of the screen at the beginning. ball_on_screen = new Ball( frame_width / 2, frame_height / 2, Color.YELLOW ) ; setLayout( new BorderLayout() ) ; refresh_button.addActionListener( this ) ; add( "South", refresh_button ) ; } public void start_thread() { if ( thread_for_ball_updating == null ) { thread_must_be_executed = true ; thread_for_ball_updating = new Thread( this ) ; thread_for_ball_updating.start() ; } } public void stop_thread() { if ( thread_for_ball_updating != null ) { thread_for_ball_updating.interrupt() ; thread_must_be_executed = false ; thread_for_ball_updating = null ; } } public void run() { while ( thread_must_be_executed == true ) { get_ball_from_servlet() ; repaint() ; try { Thread.sleep( 400 ) ; } catch ( InterruptedException caught_exception ) { // No actions to handle the exception. } } System.out.print( "\n Thread finished." ) ; } /** * Get a connection to the servlet. */ private URLConnection get_servlet_connection() throws MalformedURLException, IOException { URL servlet_url = new URL( "http://localhost:8080/MovingBallServlet/") ; URLConnection url_connection = servlet_url.openConnection() ; url_connection.setDoInput( true ) ; url_connection.setDoOutput( true ) ; url_connection.setUseCaches( false ) ; url_connection.setRequestProperty( "Content-Type", "application/x-java-serialized-object") ; return url_connection ; } private void get_ball_from_servlet() { try { // send data to the servlet URLConnection url_connection = get_servlet_connection() ; OutputStream output_stream = url_connection.getOutputStream() ; ObjectOutputStream object_output_stream = new ObjectOutputStream( output_stream ) ; object_output_stream.writeObject( "CLIENT WANTS A Ball" ) ; object_output_stream.flush() ; object_output_stream.close() ; // receive result from servlet InputStream input_stream = url_connection.getInputStream() ; ObjectInputStream object_input_stream = new ObjectInputStream( input_stream ) ; Object object_from_servlet = object_input_stream.readObject() ; object_input_stream.close() ; input_stream.close() ; if ( object_from_servlet instanceof Ball ) { ball_on_screen = (Ball) object_from_servlet ; repaint() ; } else { System.out.print( "\nBall reception failed." ) ; } } catch ( Exception exception ) { exception.printStackTrace() ; // exceptionArea.setText(ex.toString()); } } public void actionPerformed( ActionEvent event ) { if ( event.getSource() instanceof JButton ) { if ( event.getSource() == refresh_button ) { get_ball_from_servlet() ; } repaint() ; } } public void paintComponent( Graphics graphics ) { // The superclass version of paintComponent() clears the // component area and does other necessary things. super.paintComponent( graphics ) ; ball_on_screen.draw( graphics ) ; graphics.setColor( Color.black ) ; graphics.drawString( "(" + ball_on_screen.get_ball_center_point_x() + ", " + ball_on_screen.get_ball_center_point_y() + ")", 20, 20 ) ; } } class MovingBallViewerFrame extends JFrame implements WindowListener { public static final int FRAME_WIDTH = 600 ; public static final int FRAME_HEIGHT = 480 ; MovingBallViewerPanel moving_ball_panel ; public MovingBallViewerFrame() { setTitle( "B A L L V I E W E R" ) ; setSize( FRAME_WIDTH, FRAME_HEIGHT ) ; moving_ball_panel = new MovingBallViewerPanel( FRAME_WIDTH, FRAME_HEIGHT ) ; getContentPane().add( moving_ball_panel ) ; addWindowListener( this ) ; } public void windowActivated( WindowEvent event ) { // Invoked when the Window is set to be the active Window. } public void windowClosed( WindowEvent event ) { // Invoked when a window has been closed as the result of calling // dispose on the window. moving_ball_panel.stop_thread() ; } public void windowClosing( WindowEvent event ) { // Invoked when the user attempts to close the window from the window's system menu. moving_ball_panel.stop_thread() ; } public void windowDeactivated( WindowEvent event ) { // Invoked when a Window is no longer the active Window } public void windowDeiconified( WindowEvent event ) { // Invoked when a window is changed from a minimized to a normal state. moving_ball_panel.start_thread() ; } public void windowIconified( WindowEvent event ) { // Invoked when a window is changed from a normal to a minimized state. moving_ball_panel.stop_thread() ; } public void windowOpened( WindowEvent event ) { // Invoked the first time a window is made visible. moving_ball_panel.start_thread() ; } } public class MovingBallViewer { public static void main( String[] not_in_use ) { MovingBallViewerFrame moving_ball_frame = new MovingBallViewerFrame() ; //moving_ball_frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ) ; moving_ball_frame.setVisible( true ) ; } }