M-VC Open Motif Project
Here is a simple object based sample Open Motif program
that places a button on a window. You pass a pointer to a callback
function to the button. When the user presses the button, your callback function
is called. In this case, the callback function prints out a message to the terminal
window and then pops up a message box. To compile this code you will need to download the Open Motif package.
You can do this with FINK. If
you have trouble getting this to compile and link check here.
If you connect to this program remotely using X11 forwarding, you do _not_ need to
install the Open Motif library on the local computer, the X11
"server".
Note: The use of a callback function is somewhat similar in function to calling
an abstract method in a base class. The concrete class defines the implementation
details. In this program, the callback function defines the implementation
details. Unfortunately, callbacks do not play well in C++. In this solution, we
pass a pointer to this when we register the callback. The callback function is a
static method that takes the pointer and cast it back to its proper type.
This project demonstrates the use of the M-VC architecture. The Model class
contains the program algorithms and knows nothing about the presentation. The
View-Controller class contains an instance of the Model class, displays the View
and responds to user and system input. The Unix programmer may recognize this
architecture as ENGINE-INTERFACE. Although this sample is written in C++, only
the object based aspects of C++ appear valid when invoked directly from an Open Motif callback. In
other words, Open Motif callbacks support C++ without inheritance, pure virtual classes (interfaces) or
polymorphism.
// *** BEGIN PROJECT ***
/*
* viewcontroller.h
* M-VCMotif
*
* Created by Jeff Louie on Thu Mar 04 2004.
* Copyright (c) 2004 __MyCompanyName__. All rights reserved.
*
*/ #ifndef VIEW_CONTROLLER_H
#define VIEW_CONTROLLER_H 1 #include <iostream.h>
#include <string.h>
#include <exception> /* include the X library headers */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h> #include "model.h"
#include "modalinfodialog.h" // include OpenMotif headers
#include <Xm/Xm.h> // --> <X11/Intrinsic.h>, <X11/StringDefs.h>
#include <Xm/XmAll.h> // --> #include <Xm/PushB.h>
class ViewController {
public:
ViewController(int argc, char ** const argv);
//virtual ~ViewController();
static void doItPushButtonCallback(Widget w,
XtPointer client_data,
XmPushButtonCallbackStruct * cbs);
private:
Widget shell, form1, pane1, rowColumn1, label1, button1;
XtAppContext app;
Model model; // creates an instance of the Model Class void doItPushButtonHandler(); };
#endif //
// viewcontroller.cpp
// main.cpp
// M-VCMotif an object based Open Motif program
// by Jeff Louie 02.26.2004
//
// Demonstrates separating out the algorithms into a separate Model class.
// Presentation and event handling code goes into the ViewController class.
// Callback Solution as in Object Oriented Programming With C++ and Osf/Motif
// by Douglas A. Young
// #include <viewcontroller.h> // application entry point
int main(int argc, char **argv)
{
// create an instance of ViewController
ViewController vc(argc,argv); // contains an instance of the Model
return 0;
}
// ViewController Class
// Contains an instance of the Model Class
// Using composition or containment by ownership // Class Constructor
ViewController::ViewController(int argc, char ** argv) { // Initialize XT Intrinsics
shell = XtVaAppInitialize(&app,
"TestWidget",
NULL,
0,
&argc,
argv,
NULL,
NULL);
// create a form
form1= XtCreateManagedWidget("form1",
xmFormWidgetClass,
shell,
NULL,
0);
// create a vertical pane
pane1= XtCreateManagedWidget("pane1",
xmPanedWindowWidgetClass,
form1,NULL,
0);
// create a row
rowColumn1= XtCreateManagedWidget("rowColumn1",
xmRowColumnWidgetClass,
pane1,
NULL,
0);
// create a Label
label1= XtCreateManagedWidget("Press Me",
xmLabelWidgetClass,
rowColumn1 ,
NULL,
0);
// create a labeled button
button1 = XtCreateManagedWidget("DoIt",
xmPushButtonWidgetClass,
rowColumn1,
NULL,
0);
// Register our callback with the widget
// I hacked the code here, but it seems to work.
// Callbacks don't play well in C++.
// In this solution we pass a pointer to this as an XtPointer
// We use a static method doItPushButtonHandler to implement the callback
XtAddCallback(button1, XmNactivateCallback,
(XtCallbackProc)&ViewController::doItPushButtonCallback,
(XtPointer)this);
// Associate widget with a window
// Widget will be visible when it is managed,
// realized and mapped (window is displayed)
XtRealizeWidget(shell); // enter event loop
// From the docs:
/*The code for the input processing loop looks something like this:
while(TRUE) {
XEvent event;
XtAppNextEvent(app, &event);
XtDispatchEvent(&event);
} */
XtAppMainLoop(app);
}void ViewController::doItPushButtonHandler()
{
model.doIt();
ModalInfoDialog(shell,"Information","Model");
}
// virtual destructor
//ViewController::~ViewController {;}// Our callback function
// Sort of a high level event handler
// From the docs
/* Each callback procedure is a function of type XtCallbackProc.
The procedure takes three arguments: a widget and two pointers to data.*/ // Again, callbacks don't play well in C++. In this solution we use a
// static callback. We cast the (XtPointer) this back to a ViewController *
// and call our instance event handler
void ViewController::doItPushButtonCallback(Widget w,
XtPointer client_data,
XmPushButtonCallbackStruct *cbs) {
ViewController *p= (ViewController*)client_data;
p->doItPushButtonHandler();
}// You can do a Mac OS10.3 manual build from the command line.
// g++ calls gcc and links to the c++ standard library
// note the lack of a call to -lX11!
// > g++ viewcontroller.cpp -o TestWidget
// -I./ -I/usr/x11r6/include/x11/ -L/usr/x11r6/lib -lXm -lXt
// Using XCode enter the header path and linker commands
// from the Project Info window. // You can create a text file named TestWidget and set the app
// properties for TestWidget
// >cd /etc/X11/app-defaults
// >sudo exemacs TestWidget
// xemacs-->
// *geometry:200X30
// *rowColumn1*orientation:horizontal
// *rowColumn1*numColumns: 2
// Or you can pass the geometry on the command line
// >TestWidget -geometry 200X30 /*
* model.h
* M-VCMotif
*
* Created by Jeff Louie on Thu Mar 04 2004.
* Copyright (c) 2004 __MyCompanyName__. All rights reserved.
*
*/ #ifndef MODEL_H
#define MODEL_H 1 #include <iostream.h>
#include <string.h>
#include <exception> class Model {
public: Model();
//Model(Model &model);
//virtual ~Model(); void doIt(); }; #endif /*
* model.cpp
* M-VCMotif
*
* Created by Jeff Louie on Thu Mar 04 2004.
* Copyright (c) 2004 __MyCompanyName__. All rights reserved.
*
*/ #include "model.h" // Model Class // Class Constructor
Model::Model(){;}// virtual destructor
// virtual Model::~Model(){;}// copy constructor
// Model::Model(Model &model) {}// YOUR COMPLEX ALGORITHM GOES HERE
void Model::doIt() {
cout << "Do It" << endl;
}/*
* modalinfodialog.h
* M-VCMotif
*
* Created by Jeff Louie on Thu Mar 04 2004.
* Copyright (c) 2004 __MyCompanyName__. All rights reserved.
*
* Pops up a modal information dialog
*/ #ifndef MODAL_INFO_DIALOG_H
#define MODAL_INFO_DIALOG_H 1 #include <Xm/Xm.h>
#include <Xm/MessageB.h>
#include <string>
//#include <iostream.h> class ModalInfoDialog {
public:
ModalInfoDialog(Widget parent,
std::string title,
std::string message);
//virtual ~ModalPop();}; #endif /*
* modalinfodialog.cpp
* M-VCMotif
*
* Created by Jeff Louie on Thu Mar 04 2004.
* Copyright (c) 2004 __MyCompanyName__. All rights reserved.
*
*/ #include "modalinfodialog.h" ModalInfoDialog::ModalInfoDialog(Widget parent,
std::string title,
std::string message) {
Widget dialog;
char strTitle[strlen(title.c_str())+1];
strcpy(strTitle,title.c_str());
dialog= XmCreateInformationDialog(parent, strTitle ,NULL, 0);
const char * strMessage= message.c_str(); // valid through next line only
XtVaSetValues(dialog,
XmNdialogStyle,
XmDIALOG_FULL_APPLICATION_MODAL,
XtVaTypedArg,
XmNmessageString,
XmRString,
strMessage,
strlen (strMessage) +1,
NULL);
XtManageChild(dialog);
while(XtIsManaged(dialog))
{
XEvent event;
XtAppNextEvent(XtWidgetToApplicationContext(dialog), &event);
XtDispatchEvent(&event);
}
XtDestroyWidget(dialog);
}// *** END PROJECT *** Have fun! |