Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 53 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
53
Dung lượng
598,13 KB
Nội dung
The workbench invokes the createPartControl() method when the view is initialized. Here, you must first create a Canvas, set its background color, and assign a key for context-sensitive help to it. The HexHelpConstants interface is listed here. Then you need to create instances of the actions defined previously and to add these actions as tool buttons to the title bar of the view. Finally, you must create an instance of the game engine and configure it, and then you start the first game. /** * Constructs the view content */ public void createPartControl(Composite parent) { canvas = new Canvas(parent, SWT.NO_BACKGROUND); canvas.setBackground(parent.getDisplay().getSystemColor( SWT.COLOR_GRAY)); WorkbenchHelp.setHelp(canvas, HexHelpConstants.HELP_BOARD); makeActions(); contributeToActionBars(); game = new Game(); game.setStatusListener(this); game.setDrawingSurface(canvas); game.newGame(); } When you create a single action, its identification, the display label, a tool tip, and a key for the context- sensitive help are specified to construct the instance. The actions for color and level selection are constructed as toggle actions, the others as normal actions. /** * Create actions */ private void makeActions() { newGameAction = createAction(NEWGAME_ACTION, "New Game", "Starts new game", HexHelpConstants.HELP_NEWGAME_ACTION); whiteAction = createToggleAction(WHITE_ACTION, "White", "Player plays white", HexHelpConstants.HELP_COLOR_ACTION, true); blackAction = createToggleAction(BLACK_ACTION, "Black", "Player plays black", HexHelpConstants.HELP_COLOR_ACTION, false); basicAction = createToggleAction(BASIC_ACTION, "Basic", "Basic Level", HexHelpConstants.HELP_LEVEL_ACTION, true); advancedAction = createToggleAction(ADVANCED_ACTION, "Advanced", "Advanced Level", HexHelpConstants.HELP_LEVEL_ACTION, false); helpAction = createAction(HELP_ACTION, "Help", "Help for Hex", null); } /** * Create single action * * @param id - Identification 523 Project 4: The Hex Game as a Rich Client Application 17_020059_ch15.qxd 10/8/04 12:58 PM Page 523 * @param label - Display label * @param tip - Tooltip * @param helpId - ID for context sensitive help * @return - the created action instance */ private Action createAction(final int id, String label, String tip, String helpId) { Action action = new Action() { public void run() { runAction(id); } }; action.setText(label); action.setToolTipText(tip); if (helpId != null) WorkbenchHelp.setHelp(action, helpId); return action; } /** * Create single toggle action * * @param id - Identification * @param label - Display label * @param tip - Tooltip * @param helpId - ID for context sensitive help * @param init - initial state * @return - the created action instance */ private Action createToggleAction(final int id, String label, String tip, String helpId, boolean init) { Action action = new ToggleAction(label, init) { public void run() { runAction(id); } }; action.setToolTipText(tip); if (helpId != null) WorkbenchHelp.setHelp(action, helpId); return action; } When an action is invoked, its corresponding operation (identified by the action’s ID) is executed. In case of toggle actions, the invoked action is locked via the setChecked() method and its counterpart is released. The game engine then performs the operation. An exception is the help action, which simply calls the displayHelp() method of the Eclipse help system. /** * Run action * * @param id - Action identification */ protected void runAction(int id) { 524 Chapter 15 17_020059_ch15.qxd 10/8/04 12:58 PM Page 524 switch (id) { case NEWGAME_ACTION : game.newGame(); break; case WHITE_ACTION : game.setPlayerColor(IGame.WHITE); whiteAction.setChecked(true); blackAction.setChecked(false); break; case BLACK_ACTION : game.setPlayerColor(IGame.BLACK); whiteAction.setChecked(false); blackAction.setChecked(true); break; case BASIC_ACTION : game.setLevel(IGame.LEVEL1); basicAction.setChecked(true); advancedAction.setChecked(false); break; case ADVANCED_ACTION : game.setLevel(IGame.LEVEL2); basicAction.setChecked(false); advancedAction.setChecked(true); break; case HELP_ACTION : WorkbenchHelp.displayHelp(); break; } } Then, the actions are added to the view’s title bar. To do this, you must first fetch the ViewSite. From this site you can obtain the action bars, and from the action bars you obtain the toolbar manager. Then you can add the individual actions to the toolbar manager. In addition, you can separate the different action groups with the help of separators. /** * Construct menu and tool bar */ private void contributeToActionBars() { IActionBars bars = getViewSite().getActionBars(); fillLocalToolBar(bars.getToolBarManager()); } /** * Construct tool bar * * @param manager - the tool bar manager */ private void fillLocalToolBar(IToolBarManager manager) { manager.add(newGameAction); manager.add(new Separator()); manager.add(whiteAction); manager.add(blackAction); 525 Project 4: The Hex Game as a Rich Client Application 17_020059_ch15.qxd 10/8/04 12:58 PM Page 525 manager.add(new Separator()); manager.add(basicAction); manager.add(advancedAction); manager.add(new Separator()); manager.add(helpAction); } Finally, you need to implement the methods required by the superclass and the implemented interfaces. First, the setFocus() method: If the view gets the focus, it has to pass it to its drawing surface, the Canvas instance. Then you need to implement the showMessage() method from the IStatusListener interface. From the action bars of the ViewSite, fetch the StatusLineManager and pass the message to this manager via its setMessage() method. This needs to be performed in an asyncExec() block since this method can be called from the thread of the game engine. You probably remember this technique from the previous example applications. /** * Pass focus to Canvas-Widget */ public void setFocus() { canvas.setFocus(); } /** * Display message in status line * * @param message - the message to be displayed */ public void showMessage(final String message) { canvas.getDisplay().asyncExec(new Runnable() { public void run() { IStatusLineManager sManager = getViewSite() .getActionBars().getStatusLineManager(); sManager.setMessage(message); } }); } } And here are the required keys for the context-sensitive help. They are defined in the separate interface HexHelpConstants: package com.bdaum.Hex; public interface HexHelpConstants { static final String PREFIX = "com.bdaum.Hex."; public static final String HELP_COLOR_ACTION = PREFIX + "colorAction"; public static final String HELP_LEVEL_ACTION = PREFIX + "levelAction"; 526 Chapter 15 17_020059_ch15.qxd 10/8/04 12:58 PM Page 526 public static final String HELP_NEWGAME_ACTION = PREFIX + "newGameAction"; public static final String HELP_BOARD = PREFIX + "board"; } The Game Engine The game engine consists of the classes AI, BestMove, Board, Game, and StaticEval. I refrain from presenting these classes here to their full extent since this code has nothing at all to do with Eclipse. Readers interested in the implementation of the game can find the source code at www.wrox.com. Of interest in the context of Eclipse is only the Board class, which I will discuss here in sections. This class is responsible for drawing the game board and for processing the mouse actions. The data model of the game board is represented by the two-dimensional array cells, whose elements can take the values IGame.EMPTY, IGame.WHITE, and IGame.BLACK. It is the responsibility of the drawing routine to con- vert this abstract model into a graphical representation. First, some fields are defined. These fields are initialized in the constructor. The current Board instance is assigned to the Canvas as both a MouseListener and a PaintListener. private int cells[][] = new int[Game.SIZE][Game.SIZE]; private Canvas canvas; private Game game; private Display display; private Color white, black, gray, green, cyan; // Constructor public Board(Canvas canvas, Game game) { this.game = game; this.canvas = canvas; display = canvas.getDisplay(); white = display.getSystemColor(SWT.COLOR_WHITE); black = display.getSystemColor(SWT.COLOR_BLACK); gray = display.getSystemColor(SWT.COLOR_GRAY); green = display.getSystemColor(SWT.COLOR_DARK_GREEN); cyan = display.getSystemColor(SWT.COLOR_DARK_CYAN); canvas.addPaintListener(this); canvas.addMouseListener(this); } The redrawing of the canvas can occur in two different situations. First, if a view must be redrawn, then the canvas must also be redrawn, for example, when the application moves from the desktop back- ground to the foreground. Second, the canvas must be redrawn when a player or the computer has made a move. This case is handled by the draw() method. Since this method is called from the thread of the game engine, its accesses to the SWT are encapsulated again into an syncExec() block. /** * Redraw game board */ public void draw() { 527 Project 4: The Hex Game as a Rich Client Application 17_020059_ch15.qxd 10/8/04 12:58 PM Page 527 canvas.getDisplay().syncExec(new Runnable() { public void run() { // Signal partial redraw canvas.redraw(1, 1, 10000, 10000, false); } }); } In this case, it is necessary to redraw not the whole canvas but only the game board, so you have to indi- cate to the paintControl() given in the following code that only a partial redraw is required. You can do this by specifying a redraw from position (1,1). This trick is not very nice, but it works. You probably will have noticed in the section “The HexView Class” that the Canvas instance was created with the style constant SWT.NO_BACKGROUND. This style constant enforces that the canvas background is not automatically redrawn. I specified this constant in order to avoid flicker. The consequence was that I had to organize the drawing of the canvas background myself, and I redraw the canvas background only when the whole view is redrawn but not after a game move. This is controlled by specifying the redraw position of (1,1). In the following code section, I specify the geometry of the game board by defining appropriate constants: // Edge length of a hexagon (= outer radius) private static final int OUTER_RAD = 30; // Inner radius of a hexagon private static final int INNER_RAD = (int) (Math.sqrt(0.75d) * OUTER_RAD); // Outline of a hexagon private static final int[] CELL = new int[]{ -OUTER_RAD, 0, -OUTER_RAD/2, -INNER_RAD, OUTER_RAD/2, -INNER_RAD, OUTER_RAD, 0, OUTER_RAD/2, INNER_RAD, -OUTER_RAD/2, INNER_RAD}; // Horizontal distance between cells private static final int XDIST = OUTER_RAD * 3 / 2; // Horizontal offset of the game board private static final int XOFF = Game.SIZE * OUTER_RAD + 150; // Vertical offset of the game board private static final int YOFF = 100; // Horizontal border width of game board private static final int XMARGIN = 20; // Vertical border width of game board private static final int YMARGIN = 15; // Radius of a game button private static final int BUTTON_RAD = OUTER_RAD / 2; // Corner positions of the game board private static final Point TOP = hexToPixel(0, 0); private static final Point BOTTOM = hexToPixel(Game.SIZE,Game.SIZE); private static final Point RIGHT = hexToPixel(Game.SIZE, 0); private static final Point LEFT = hexToPixel(0, Game.SIZE); // Outlines of the game board edges 528 Chapter 15 17_020059_ch15.qxd 10/8/04 12:58 PM Page 528 private static final int[] WHITEBORDER = new int[]{ LEFT.x - XMARGIN, LEFT.y - INNER_RAD, RIGHT.x + XMARGIN, RIGHT.y - INNER_RAD, TOP.x, TOP.y - YMARGIN - INNER_RAD, BOTTOM.x, BOTTOM.y + YMARGIN - INNER_RAD}; private static final int[] BLACKBORDER = new int[]{ LEFT.x - XMARGIN, LEFT.y - INNER_RAD, TOP.x, TOP.y - YMARGIN - INNER_RAD, BOTTOM.x, BOTTOM.y + YMARGIN - INNER_RAD, RIGHT.x + XMARGIN, RIGHT.y - INNER_RAD}; The following method converts the rows and columns into pixel coordinates: /** * Convert rows and columns into pixel values * @param i - row * @param j - column * @return - (x,y)-coordinate */ private static Point hexToPixel(int i, int j) { return new Point( ((i - j) * XDIST) + XOFF, ((i + j) * INNER_RAD) + YOFF); } Now you can draw the game board. If the indicator totalRedraw is set, you first fill the complete back- ground with the background color (gray). Then the black-and-white game board edges are drawn, which are later overdrawn by the game board cells. Next you can draw the game board cell by cell. First, the cell background is drawn. You use a different background color for the cell in the center because this cell has a special meaning. Then you can draw the game button belonging to the cell—provided the cell is not empty. /** * Draw Canvas * * @param e - Event object */ public void paintControl(PaintEvent e) { GC gc = e.gc; if (e.x != 1 || e.y != 1) { // Draw background gc.setBackground(gray); gc.fillRectangle(canvas.getClientArea()); // Draw game board edges gc.setBackground(white); gc.fillPolygon(WHITEBORDER); gc.setBackground(black); gc.fillPolygon(BLACKBORDER); } // Draw all hexagon cells for (int i = 0; i < Game.SIZE; i++) for (int j = 0; j < Game.SIZE; j++) 529 Project 4: The Hex Game as a Rich Client Application 17_020059_ch15.qxd 10/8/04 12:58 PM Page 529 drawCellWithButton(gc, i, j, cells[i][j]); } /** * Draw single cell * @param gc - Graphic Context * @param i - Row * @param j - Column * @param buttonColor - Color of game button */ private void drawCellWithButton(GC gc, int i, int j, int buttonColor) { Point p = hexToPixel(i, j); if (i == Game.SIZE / 2 && j == Game.SIZE / 2) drawCell(gc, p.x, p.y, cyan, black); else drawCell(gc, p.x, p.y, green, black); switch (buttonColor) { case Game.BLACK : drawButton(gc, p.x, p.y, black, white); break; case Game.WHITE : drawButton(gc, p.x, p.y, white, black); break; } } /** * Draw cell background * @param gc - Graphic Context * @param x - X-offset * @param y - Y-offset * @param cellColor - fill color * @param outlineColor - outline color */ private void drawCell(GC gc, int x, int y, Color cellColor, Color outlineColor) { int[] points = new int[CELL.length]; for (int k = 0; k < CELL.length; k += 2) { points[k] = x + CELL[k]; points[k + 1] = y + CELL[k + 1]; } gc.setBackground(cellColor); gc.setForeground(outlineColor); gc.fillPolygon(points); gc.drawPolygon(points); } /** * Draw game button * @param gc - Graphic Context * @param x - X-offset * @param y - Y-offset * @param bgColor - fill color 530 Chapter 15 17_020059_ch15.qxd 10/8/04 12:58 PM Page 530 * @param fgColor - outline color */ private void drawButton(GC gc, int x, int y, Color bgColor, Color fgColor) { gc.setBackground(bgColor); gc.fillOval(x - BUTTON_RAD, y - BUTTON_RAD, 2 * BUTTON_RAD, 2 * BUTTON_RAD); gc.setForeground(fgColor); gc.drawOval(x - BUTTON_RAD, y - BUTTON_RAD, 2 * BUTTON_RAD, 2 * BUTTON_RAD); } This concludes the drawing operations. What is still missing is the processing of the mouse events. Only the single mouse down event is processed; the release of the mouse button and the double-click are ignored. On a mouse click, the mouse coordinates are converted into board coordinates. The game engine is informed about this event via the selectHex() method. /* * Mouse button pressed * * @param e - Event object */ public void mouseDown(MouseEvent e) { Point p = pixelToHex(e.x, e.y); game.selectHex(p.x, p.y); } /** * Convert pixels into row and column * @param x - X-offset * @param y - Y-offset * @return - (row, column)-tuple */ private static Point pixelToHex(int x, int y) { int dist2 = INNER_RAD * INNER_RAD; for (int i = 0; i < Game.SIZE; i++) { for (int j = 0; j < Game.SIZE; j++) { Point p = hexToPixel(i, j); int dx = p.x - x; int dy = p.y - y; if (dx * dx + dy * dy < dist2) return new Point(i, j); } } return new Point(-1, -1); } The Welcome Screen The HexIntro class is also generated during the definition of the plug-in manifest (Listing 15.6). However, it is better and easier to write this class from scratch and to subclass the IntroPart class 531 Project 4: The Hex Game as a Rich Client Application 17_020059_ch15.qxd 10/8/04 12:58 PM Page 531 instead of implementing the IIntroPart interface. The only thing that remains to do is to complete the setFocus() method and to construct the welcome screen in the createPartControl() method. Here, I have decided to use forms technology. Forms are well suited for presenting some instructions for the game. In addition, I have provided a hyperlink for starting the game. The example demonstrates how different colors and fonts can be used in forms texts. The colors and fonts are referenced via sym- bolic names within the marked-up text, and then further down these names are defined via setColor() and setFont(). Also, for the hyperlink I have chosen a special representation: it is underlined only when the mouse hovers over it. Events produced by this hyperlink are captured by the hyperlink listener. If the user clicks on the hyperlink, the welcome screen closes and the game can begin. package com.bdaum.Hex; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.forms.HyperlinkSettings; import org.eclipse.ui.forms.events.HyperlinkAdapter; import org.eclipse.ui.forms.events.HyperlinkEvent; import org.eclipse.ui.forms.widgets.Form; import org.eclipse.ui.forms.widgets.FormText; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.TableWrapLayout; import org.eclipse.ui.intro.IIntroManager; import org.eclipse.ui.part.IntroPart; public class HexIntro extends IntroPart { // The Form-Widget Form introForm; /* (non-Javadoc) * @see org.eclipse.ui.part.IntroPart#setFocus() */ public void setFocus() { introForm.setFocus(); } /* (non-Javadoc) * @see org.eclipse.ui.part.IntroPart * #createPartControl(org.eclipse.swt.widgets.Composite) */ public void createPartControl(Composite parent) { // Fetch Toolkit FormToolkit tk = new FormToolkit(parent.getDisplay()); // Create Form and set Layout introForm = tk.createForm(parent); TableWrapLayout layout = new TableWrapLayout(); introForm.getBody().setLayout(layout); 532 Chapter 15 Listing 15.6 (Continues) 17_020059_ch15.qxd 10/8/04 12:58 PM Page 532 [...]... Based on this selection, the Java Build Path is adapted automatically The workspace of the new platform now contains the complete development project for the imported plug-in Migration to Eclipse 3 Plug-in projects that were developed under Eclipse versions prior to Eclipse 3 and are now deployed on Eclipse 3 platforms, or where development is to be continued under the Eclipse 3 SDK, require special treatment... Plug-ins for Eclipse Name Description Home Page TimeStorm 2.0 Cross-platform IDE for embedded-Linux target platforms Commercial product www.timesys.com SpellChecker for Eclipse The spell checker developed in this book, and enhanced versions Free www.bdaum.de /eclipse Embedded Systems 549 B Migrating Projects to a New Eclipse Version The migration of projects to a new version of the Eclipse platform is... Kaufman Publishing, 20 03 Daum, Berthold “Mutatis mutandis – Using Preference Pages as Property Pages.” Eclipse Corner, www .eclipse. org, 20 03 Daum, Berthold “Equipping SWT Applications with Content Assistants." IBM developerWorks, www106.ibm.com/developerworks/opensource/library/os-ecca/, Nov 25, 20 03 Daum, Berthold Eclipse 2 for Java Developers Chichester: John Wiley & Sons, 20 03 Daum, Berthold, Stefan... powerful compiler-compiler implemented as an Eclipse plug-in Free sourceforge.net/projects/ antlreclipse 547 Appendix A Name Description Home Page Profiler Tuning instrument for performing measurements in Java programs eclipsecolorer.sourceforge.net/ index_profiler.html Rational ClearCase A UML-based CASE tool Commercial product www.rational.com Together Edition for Eclipse A UML-based CASE tool Commercial... servlet-based projects Free www.sysdeo.com /eclipse/ tomcatplugin.html Systinet WASP Server for Java Creates Web services from Java classes Supports the execution and debugging of Web services from within Eclipse Free for end users www.systinet.com MyEclipse Various tools for J2EE www.myeclipseide.org development, in particular, a JSP editor and debugger MyEclipse is the product of a joint venture between... the \eclipse\ configuration\ folder before restarting Eclipse The value eclipse. buildId identifies the installed version of the Eclipse platform and must be adapted accordingly when using a version of Eclipse later than 3. 0.0 It can be retrieved from the config.ini file that comes with the Eclipse product The installation of the Hex game consists of simply unpacking the ZIP file into an existing Eclipse. .. time to look for new developments Good starting points for searching plug-ins are, of course, the official Eclipse Web site at www .eclipse. org and SourceForge at sourceforge.net In addition, there are some Web sites dedicated to Eclipse plug-ins, such as www .eclipse- plugins.info and www.eclipseplugincentral.com Name Description Home Page Attrezzo per Xindice A graphical user interface for the Xindice... Changed! Responding to resource changes in the Eclipse workspace.” Eclipse Corner, www .eclipse. org, 2002 Arthorne, John “Drag and Drop in the Eclipse UI.” Eclipse Corner, www .eclipse. org, 20 03 Beck, Kent Extreme Programming Explained: Embrace Change Harlow: Addison-Wesley, 1999 Cornu, Christophe “A Small Cup of SWT.” IBM OTI Labs, Eclipse Corner, www .eclipse. org, 20 03 Daum, Berthold Modeling Business Objects... Linux) Free www .eclipse. org/cdt Eiffel for Eclipse Eiffel editor and compiler Compile into Java byte code, C, and machine code Free www .eclipse. audaly.com Improve C# Plugin C# editor and builder Free www.improve-technologies.com/ alpha/esharp xored WebStudio PHP IDE Free www.xored.com JavaCC A popular compiler-compiler implemented as an Eclipse plug-in Free sourceforge.net/projects/ eclipse- javacc ANTLR... to an SWT Application.” Eclipse Corner, www .eclipse. org, 20 03 Kehn, Dan, Scott Fairbrother, and Cam-Thu Le “How to Internationalize Your Eclipse Plug-In,” Eclipse Corner, www .eclipse. org, 2002 MacLeod, Carolyn and Shantha Ramachandran “Understanding Layouts in SWT,” Eclipse Corner, www .eclipse. org, 2002 Moody, James and Carolyn MacLeod “SWT Color Model.” Eclipse Corner, www .eclipse. org, 2001 Robinson, . org .eclipse. ui.forms.widgets.Form; import org .eclipse. ui.forms.widgets.FormText; import org .eclipse. ui.forms.widgets.FormToolkit; import org .eclipse. ui.forms.widgets.TableWrapLayout; import org .eclipse. ui.intro.IIntroManager; import. org .eclipse. ui.IWorkbench; import org .eclipse. ui.IWorkbenchWindow; import org .eclipse. ui.forms.HyperlinkSettings; import org .eclipse. ui.forms.events.HyperlinkAdapter; import org .eclipse. ui.forms.events.HyperlinkEvent; import. its 3. 0 release, Eclipse does not support Java 1.5, and JRE 1.5 is not an official platform for running Eclipse. However, under the codename Cheetah, there is an experimental version for Java