Presentation is loading. Please wait.

Presentation is loading. Please wait.

Using Motif with C++ ● X and Motif are written in C ● C++ is backward compatible with C, provided that the function prototypes are correctly given ● So.

Similar presentations


Presentation on theme: "Using Motif with C++ ● X and Motif are written in C ● C++ is backward compatible with C, provided that the function prototypes are correctly given ● So."— Presentation transcript:

1 Using Motif with C++ ● X and Motif are written in C ● C++ is backward compatible with C, provided that the function prototypes are correctly given ● So it is straightforward to call X and Motif from C++ programs ● But all of our examples so far just look like C programs with strong typing (no class-oriented design)

2 Classes in C++ and Motif ● Motif is designed with a class hierarchy and inheritance in mind (see next slide) ● But the approaches to classes used by Motif and C++ are incompatible: – C++ programmers often work with object-oriented libraries by creating new specialized subclasses of the library – However, although Motif widgets are described as classes, there is no way to create a C++ class that is a subclass of a Motif widget

3 Motif and Xt Widget Classes Core Composite Primitive Constraint Shell Text Label PushButton DrawnButton.... Manager... RowColumn Form BulletinBoar d

4 Approaches to Mixing Motif and C++ 1 Do not use OO features of C++ and just write applications in a style similar to C ➢ misses out on the benefit of OOP 2 Wrap each Motif widget class in a C++ class ➢ public domain and commercial wrapper sets are available ➢ disadvantages: additional code, support, portability 3 Create higher-level user interface components in C++ which use Motif widgets as data attributes ➢ use C++ classes to describe software architecture ➢ do not force Motif widgets to be C++ classes ➢ we will emphasize this approach

5 Example: A Tic-Tac-Toe Program Board canvas: Widget display: Display gc: GC Game state: CharArray count: Integer playerX: Player Dialog dialog: Widget Main shell: Widget app: XtAppContext board game board game startd endd summaryd *

6 Notes on TTT Class Diagram ● Only the class attributes are shown ● All classes have singleton members except Dialog ● The role of Motif widgets is to be attributes of C++ classes: – Main::shell, a shell widget – Board::canvas, an XmDrawingArea widget – Dialog::dialog, an XmDialogShell widget

7 Notes on TTT Class Diagram (cont'd) ● The Board class manages the game display: – Detects clicks, displays marks – Needs the game object to access internal state ● The Game class runs the game and keeps an internal representation – Needs the board object to update the display ● The Dialog class manages the start, end, and summary dialogs – Needs the game object to return results of dialog ● The Main class creates all of the above and manages the Xt connection

8 The Game Class Recall that Game also has a Board as an attribute as shown in the class diagram.

9 The Board Class Recall that Board also has a Game as an attribute as shown in the class diagram.

10 Board Class Methods ● drawGrid, drawX, and drawO are the subject of a lab exercise ● manage and unManage allow for exposing and hiding the drawing area ● asciiDisplay is for debugging purposes ● drawBoardCallback responds to any expose event generated for the drawing area ● boardClickCallback responds to any mouse input event generated for the drawing area

11 Callbacks Available for Drawing Areas ● XmNexposeCallback – Triggered when part of the widget is exposed. – We must provide a callback that will ``repaint'' the tic-tac-toe board when this is triggered ● XmNinputCallback – Triggered when the widget receives a keyboard or mouse event. – We must provide a callback that will determine the coordinates of the clicked square and ask the board to draw an appropriate mark there ● XmNresizeCallback – Triggered when the widget is resized. (We will not act on resizings.)

12 BoardInfo Constructor BoardInfo::BoardInfo(Widget parent, Game g) {... canvas = XtVaCreateManagedWidget ( "canvas", xmDrawingAreaWidgetClass, parent, XmNheight, 300, XmNwidth, 300, NULL );... XtAddCallback(canvas, XmNexposeCallback, &BoardInfo::drawBoardCallback,...); XtAddCallback(canvas, XmNinputCallback, &BoardInfo::boardClickCallback,...); } At the time we construct a new board, we will also add the callbacks for it: Since the callbacks are static class methods, they must be qualified by the class name and begun with `` & ''.

13 Writing the Draw Board Callback When an expose event occurs for the drawing area, the action called for is straightforward: drawGrid() ; for (Integer x = 0; x < 3; x++) // Draw the Xs & Os for (Integer y = 0; y < 3; y++) { if (game->getState(x,y) == 'X') drawX(x, y) ; else if (game->getState(x,y) == 'O') drawO(x, y) ; }

14 Writing the Draw Board Callback (cont'd) Q: So, will this work? void BoardInfo::drawBoardCallback(Widget, XtPointer, XtPointer) { drawGrid(); for (Integer x = 0; x < 3; x++) // Draw the Xs & Os for (Integer y = 0; y < 3; y++) { if (game->getState(x,y) == 'X') drawX(x, y); else if (game->getState(x,y) == 'O') drawO(x, y); } A: No, because: - callbacks are straight C functions and thus are static - static methods cannot access objects like game

15 Solution: Using Client Data Recall the XtAddCallback function prototype: void XtAddCallback ( Widget widget, //1 const String callbackName, //2 XtCallbackProc proc, //3 XtPointer clientData); //4 Recall the actual callback function prototype: void (Widget w, // 1 XtPointer clientData, // 2 XtPointer callData); // 3

16 Using Client Data ● The clientdata argument is specified by the call to XtAddCallback. The system remembers it and passes it along to the callback when appropriate. ● XtPointer is a generic pointer type defined by Xt. It can be type cast to any pointer type. ● So use it to obtain a pointer to an object that knows about the game object, i.e., the board object.

17 Strategy ● When adding the callback to draw the grid, include the this pointer (a pointer to this board) as clientData ● Write the (static) callback to use the clientData to get the board object for which the callback was added ● The (static) callback does nothing but call a nonstatic method on the board object that does the work of drawing the grid

18 BoardInfo Constructor Again BoardInfo::BoardInfo(Widget parent, Game g) {... canvas = XtVaCreateManagedWidget ( "canvas", xmDrawingAreaWidgetClass, parent, XmNheight, 300, XmNwidth, 300, NULL );... XtAddCallback(canvas, XmNexposeCallback, &BoardInfo::drawBoardCallback, (XtPointer) this ); XtAddCallback(canvas, XmNinputCallback, &BoardInfo::boardClickCallback, (XtPointer) this ); } – Since the clientData argument is of type XtPointer, the this pointer, which is of type BoardInfo*, must be type cast

19 BoardInfo Class Declaration class BoardInfo { private: Game game; // the game state Widget canvas; // drawing area Display* display; // display device for app GC gc; // graphics context public: BoardInfo(Widget parent, Game g); void drawGrid(); // draw game grid void drawX ( Integer x, Integer y); // Draw an X at (x,y) void drawO ( Integer x, Integer y); // Draw an O at (x,y) void manage(); // expose drawing area void unManage(); // hide the drawing area void asciiDisplay(); // display for debugging private: static void drawBoardCallback(Widget, XtPointer clientData, XtPointer); void drawBoard(); // draw board when it is exposed static void boardClickCallback(Widget, XtPointer clientData, XtPointer); void boardClick(); // get board coords when clicked }

20 Draw Board Callback Methods void BoardInfo::drawBoardCallback(Widget, XtPointer clientData, XtPointer) { Board * b = (Board *)clientData; b->drawBoard(); } void BoardInfo::drawBoard() { drawGrid(); for (Integer x = 0; x < 3; x++) // Draw the Xs & Os for (Integer y = 0; y < 3; y++) { if (game->getState(x,y) == 'X') drawX(x, y); else if (game->getState(x,y) == 'O') drawO(x, y); }

21 Macros to Handle C++ Callbacks #define name2(a,b) a ## b #define DECL_CALLBACK(func) \ private: \ static void name2(func,Callback) (Widget, \ XtPointer, \ XtPointer); \ protected: \ virtual void func ( Widget, XtPointer) Since it's a hassle to define two methods for every callback, we can define macros to simplify both the declaration and the implementation of callbacks.

22 Callback Declaration Macro ● Whenever the preprocessor sees name2(a,b), it plugs in the concatenation of a and b: – For example, name2(drawBoard,Callback) becomes drawBoardCallback ● Whenever the preprocessor sees DECL_CALLBACK(func) it plugs in two method declarations. – For example, DECL_CALLBACK(drawBoard) becomes: private: \ static void drawBoardCallback (Widget, \ XtPointer, \ XtPointer); \ protected: \ virtual void drawBoard ( Widget, XtPointer)

23 BoardInfo Class Declaration Again class BoardInfo { private: Game game; // the game state Widget canvas; // drawing area Display* display; // display device for app GC gc; // graphics context public: BoardInfo(Widget parent, Game g); void drawGrid(); // draw game grid void drawX ( Integer x, Integer y); // Draw an X at (x,y) void drawO ( Integer x, Integer y); // Draw an O at (x,y) void manage(); // expose drawing area void unManage(); // hide the drawing area void asciiDisplay(); // display for debugging private: DECL_CALLBACK(drawBoard); // draw board when it is exposed DECL_CALLBACK(boardClick); // get board coords when clicked }

24 Callback Implementation Macro #define IMPL_CALLBACK(cls, func) \ void cls::name2(func,Callback) (Widget w, \ XtPointer clientData, \ XtPointer callData) \ { \ ((cls *)clientData)->func(w, callData); \ } \ \ void cls::func(Widget w, XtPointer callData) We can also define a macro to simplify the implementation (definition) of callbacks: This macro will hide the details of the communication between the static and nonstatic class methods.

25 Simplified Implementation of Draw Board Callback IMPL_CALLBACK(BoardInfo, drawBoard) { drawGrid(); for (Integer x = 0; x < 3; x++) for (Integer y = 0; y < 3; y++) { if (game->getState(x,y) == 'X') drawX(x, y); else if (game->getState(x,y) == 'O') drawO(x, y); } The callback macros are in the file CallbackMacros.h in the Tic-Tac-Toe directory.

26 Board Click Callback ● When a mouse click is detected in the board's drawing area, what must be done? – The (x,y) pixel coordinates of the click location must be determined – From these coordinates the indices of the 3x3 character array (internal representation) must be calculated – The game object must be told to process a move given these indices ● To retrieve the (x,y) pixel coordinates, we must make use of the drawing area widget's call data

27 Using Call Data Recall the callback function prototype: void (Widget w, // 1 XtPointer clientData, // 2 XtPointer callData); // 3 The third argument is a pointer to a data structure holding information from the widget. At a minimum: typedef struct { int reason; // coded reason for callback XEvent *event; // event causing callback } XmAnyCallbackStruct This structure can be extended in widget-specific ways.

28 Using Call Data (cont'd) ● When call data is needed in a callback, first do: – XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) callData; ● Now we can get the general event causing the callback with: – cbs->event ● From the general event we can get the specific button event: – cbs->event->xbutton ● From the button event we can get the x and y pixel coordinates: – cbs->event->xbutton.x – cbs->event->xbutton.y

29 Board Click Callback Implementation // get board coordinates when clicked and process move IMPL_CALLBACK(BoardInfo, boardClick) { XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) callData; Integer x = (Integer) floor(cbs->event->xbutton.x/100); Integer y = (Integer) floor(cbs->event->xbutton.y/100); game->processMove(x,y); } Since a tic-tac-toe square is 100 x 100 pixels, this will translate pixel coordinates to game board coordinates in a 3 x 3 character array. For example: (150,150) -> (1,1)


Download ppt "Using Motif with C++ ● X and Motif are written in C ● C++ is backward compatible with C, provided that the function prototypes are correctly given ● So."

Similar presentations


Ads by Google