About this Tutorial

This tutorial builds on the Chat (empty game) tutorial. If you have not digested that tutorial I reccommend starting there.

The Paint Game

This code should look very familiar if you read the Chat Tutorial. The differences are discussed below.

 1: import java.awt.BorderLayout;
 2:
 3: import javax.swing.JFrame;
 4: import javax.swing.JMenu;
 5: import javax.swing.JMenuBar;
 6: import javax.swing.JMenuItem;
 7: import javax.swing.JPopupMenu;
 8:
 9: import net.mlw.gfw.client.ClientContext;
10: import net.mlw.gfw.client.DefaultClient;
11: import net.mlw.gfw.ext.basic.action.NewGameActionListener;
12: import net.mlw.gfw.ext.basic.event.ChatEvent;
13: import net.mlw.gfw.server.impl.DefaultServer;
14: import examples.paint.event.DrawEvent;
15: 
16: public class Main extends DefaultClient
17: {
18:    protected final JMenuBar  menuBar         = new JMenuBar();
19:    protected final JMenu     menuGame        = menuBar.add(new JMenu("Game"));
20:    protected final JMenuItem menuFileNewGame = menuGame.add(new JMenuItem("New Game"));
21:
22:    public final void init(final ClientContext clientContext)
23:    {
24:       setJMenuBar(menuBar);
25:       
26:       menuFileNewGame.addActionListener(
27:         new NewGameActionListener(this, server, DefaultServer.class,
28:                                   clientContext, clientEventHandler) );      
29:
30:       PaintPanel paint = new PaintPanel();
31:       paint.init(clientContext);
32:       paint.addEventHandler(server);
33:      
34:       clientEventHandler.addEventHandler(DrawEvent.class, paint);
35:       clientEventHandler.addEventHandler(ChatEvent.class, paint);
36:
37:       getContentPane().add(paint, BorderLayout.CENTER);
38:    }
39:
40:    public static void main(String[] args)
41:    {
42:       JPopupMenu.setDefaultLightWeightPopupEnabled(false);
43:       Main sample = new Main();
44:       sample.initialize(new ClientContext());
45:       sample.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
46:       sample.setSize(600, 400);
47:       sample.setVisible(true);
48:    }
49: }       

30 A new PaintPanel Component is created.

31 The PaintPanel Component is initialized.

32 An EventHandler is added to the PaintPanel. Notice the server is the EventHandler, all events created by this Component will be sent to the server.

34 Tell the clientEventHandler to send all the events from the server that are of type DrawEvent to the PaintPanel declared on line number 30.

35 Tell the clientEventHandler to send all the events from the server that are of type ChatEvent to the PaintPanel also.

37 Add the PaintPanel component to the center of the JFrame. Note that the DefaultClient has a BorderLayout manager.

Now we have everything wired together lets review.

  • We have a server that is defined (#27).
  • We have a client , and have added a custom component to that client (#37).
  • The custom component will sent its events to the server (#32). The custom component will listen for events from the server (#34-#35).

I will try not to loose you attention in the details of how the Component actually draws, but there are several important things to note.

....
  5: import java.awt.Color;
  6: import java.awt.Dimension;
  7: import java.awt.Graphics;
  8: import java.awt.Image;
  9:
 10: import javax.swing.JColorChooser;
 11:
 12: import net.mlw.gfw.client.ClientContext;
 13: import net.mlw.gfw.event.Event;
 14: import net.mlw.gfw.ext.basic.client.component.BasePanel;
 15: import net.mlw.gfw.ext.basic.event.ChatEvent;
 16: import examples.paint.event.DrawEvent;
....
 20: public class PaintPanel extends BasePanel
 21: {
 22:   private Dimension defaultDimension = new Dimension(600, 400);
 23:   private Color color = Color.black;
 24:   private Image buffer;
 25:   private Graphics b;
....
 30:   public void update(Graphics g)
....
 40:   public void paint(Graphics g)
....
 50:   private void initBuffer()
....
 60:   public Dimension getPreferredSize()
....
 70:   /**
 71:    * @see net.mlw.gfw.client.ClientEventHandler#init(net.mlw.gfw.client.ClientContext)
 72:    */
 73:   public void init(ClientContext context)
 74:   {
 75:      this.setBackground(Color.WHITE);
 76:      this.addMouseListener(new java.awt.event.MouseAdapter()
 77:      {
 78:         public void mousePressed(java.awt.event.MouseEvent evt)
 79:         {
 80:            if (evt.getModifiers() != 16)
 81:            {
 82:               color = JColorChooser.showDialog(PaintPanel.this, "", Color.black);
 83:            }
 84:         }
 85:      });
 86:      this.addMouseMotionListener(new java.awt.event.MouseMotionAdapter()
 87:      {
 88:         public void mouseDragged(java.awt.event.MouseEvent event)
 89:         {
 90:            getEventHandlers().onEvent(new DrawEvent(color, event.getX(), event.getY()));
 91:         }
 92:      });
 93:   }
 94:
 95:   /**
 96:    * @see net.mlw.gfw.event.EventHandler#onEvent(net.mlw.gfw.event.Event)
 97:    */
 98:   public void onEvent(Event event)
 99:   {
100:      if (event instanceof DrawEvent)
101:      {
102:         b.setColor(((DrawEvent) event).getColor());
103:         b.drawOval(((DrawEvent) event).getX(), ((DrawEvent) event).getY(), 2, 2);
104:         repaint();
105:      }
106:      else if (event instanceof ChatEvent)
107:      {
108:         if ("/clear".equals(((ChatEvent) event).getText()))
109:         {
110:            initBuffer();
111:            repaint();
112:         }
113:      }
114:   }
115: }

5-16 Import awt classes and some GameFramework classes.

22 This is the default Dimension I want this Component to be.

23 Holds the current color the client draws in.

24-50 These varables and methods are needed for double buffering.

60 The parent Component will call this ethod to get its size.

73 The init method called in the Main.class above.

75 Set the backgroud to white.

76-85 Add a MouseListener that pops up a JColorChooser dialog, storing the users selection in the color var.

86-92 Add a MouseMotionListener that listens for the mouse to be draged. NOTE: On line 90:

90:            getEventHandlers().onEvent(new DrawEvent(color, event.getX(), event.getY()));

The Component does not draw onto itself in th e MouseMotionListener ! The MouseMotionListener sends a DrawEvent to the registered EventListener . In this case the listener is the server. This pattern is the most significant pattern in the GameFramework. It is very similar to the observer pattern, with one exception. The Component never actuall changes its own state. The Component notifies the server that its state has changed. The server will verify the event and pass it to all the EventListeners registed. At this point the Component will get an Event back from the server that notifies the Component to change its state.

98 The onEvent method that makes this Component an EventListener.

100-105 If the Event is of type DrawEvent then draw a dot on the canvas and repaint the buffer.

106-113 If the Event is of type ChatEvent and the text is "/clear" the clear the buffer and repaint.

Below is a screenshot of the results of running the above Sample. If you want to try it out yourself click on Java Web Start .