Presentation is loading. Please wait.

Presentation is loading. Please wait.

Using Motif with C++ X and Motif are written in C

Similar presentations


Presentation on theme: "Using Motif with C++ X and Motif are written in C"— 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
Label PushButton . DrawnButton Primitive . Text RowColumn Core Constraint Manager Form BulletinBoard Composite . . . Shell . . .

4 Approaches to Mixing Motif and C++
Do not use OO features of C++ and just write applications in a style similar to C misses out on the benefit of OOP Wrap each Motif widget class in a C++ class public domain and commercial wrapper sets are available disadvantages: additional code, support, portability 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 Game canvas: Widget display: Display gc: GC board game state: CharArray count: Integer playerX: Player game game board startd endd summaryd Main Dialog shell: Widget app: XtAppContext dialog: Widget *

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
At the time we construct a new board, we will also add the callbacks for it: 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, ...); } 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 <funcname> (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 static void drawBoardCallback(Widget, XtPointer clientData, XtPointer); void drawBoard(); // draw board when it is exposed static void boardClickCallback(Widget, XtPointer clientData, 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
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. #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)

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 DECL_CALLBACK(drawBoard); // draw board when it is exposed DECL_CALLBACK(boardClick); // get board coords when clicked }

24 Callback Implementation Macro
We can also define a macro to simplify the implementation (definition) of callbacks: #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) 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 <funcname> (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"

Similar presentations


Ads by Google