The best way to get to know PhAB is to use it. This chapter provides hands-on sessions to give you a jump start on creating applications.
This chapter includes:
We'll take a closer look at using PhAB in the chapters that follow.
The first two tutorials cover the basics: creating widgets, changing how widgets look and behave, generating code, running your application, and so on.
The remaining tutorials go beyond the basics to show you how to create working menus, dialogs, and windows. When you've completed these tutorials, you'll be ready to start building almost any Photon application.
If you're developing Photon applications in the IDE, the way you use PhAB there is slightly different than from standalone PhAB. The differences are:
To create a new PhAB project, see “Creating a QNX Photon Appbuilder project” in the Developing Photon Applications chapter of the IDE User's Guide. When you create a new project, the IDE opens PhAB, and you see the New Window Style dialog from which you can select the type of base window for your application.
You can start PhAB from the Launch menu in the lower-left corner of the screen; choose the Development submenu, and then choose Builder.
You can also start PhAB from a pterm window by typing:
appbuilder
For information about command-line options, see appbuilder in the QNX Neutrino Utilities Reference.
Before you start the tutorials, take a moment to make yourself familiar with PhAB's user interface:
The widget palette and control panels are initially in the same window, but you can drag any of them into a different window. To switch between panels in a window, click the tab at the top and choose a panel from the menu.
If you close a control panel, you can redisplay it by selecting the appropriate item from the View menu.
In this tutorial you learn how to use PhAB to create and compile a simple application.
From the File menu, choose Save As to open the Application Selector dialog. Click the Application Name field, type tut1, then press Enter or click Save Application.
PhAB automatically:
Now you're ready to generate, compile, and execute the application. How you perform this step depends on whether you're using PhAB from the IDE or standalone.
When running PhAB from the IDE, PhAB generates the code for your application's user interface, and the IDE compiles and executes the application. You'll notice that only the Generate UI item is available in PhAB's Build menu.
The application will appear in its own window, with the text “Hello World” in the center and the default title “My Application” in the title bar:
Congratulations! You've just created your first Photon application using PhAB.
To quit the application, click the window menu button in its top-left corner, then choose the Close item.
For more info on compiling, running, and debugging an application, see the Generating, Compiling, and Running Code chapter.
This tutorial introduces you to PhAB's resource editors, which let you change how widgets look and behave. You'll find out how to edit virtually any kind of resource a widget may have, including:
You'll also learn how to create a template so you can create other instances of an existing widget.
Let's now edit a numerical resource—the button's bevel width.
This editor lets you change the value of any numerical widget resource.
or:
You can also edit this resource (and most resources) right in the Resources control panel. Choose whichever method you like. |
Let's change the font of the button's text:
This editor lets you change the text font of any widget that has text.
Now let's change the button's horizontal text alignment:
This editor serves a dual purpose in PhAB:
You can also set this resource right in the Resources control panel.
Let's now use the flag/option editor to set one of the widget's flags:
The bits in this flag resource aren't mutually exclusive, so this time you can use the editor to select multiple options, if desired.
Let's change a color resource—the button's fill color.
This editor lets you edit any color resource. It provides several preset base colors, which should work well with all graphic drivers, and 48 customizable colors for drivers that support 256 or more colors.
If you'd like to experiment with the Hue/Saturation/Brightness (HSB) color model, click the HSB Model button.
Your button should now look something like this:
Don't delete this widget; we'll use it to create a template later on, so that you can create other widgets like it.
Let's now use the pixmap editor to edit a PtLabel widget. This editor is called “pixmap” instead of “bitmap” since it lets you edit many types of image resources besides bitmaps.
A PtLabel widget display text and/or an image.
If you click Edit Color, you'll see the Color Editor, as described earlier.
Feel free to try the other drawing tools.
Next, we'll edit a multiline text resource—the text of a PtMultiText widget.
Mary hadEnter
aEnter
little lamb.Enter
You can edit the text right in the control panel, but it displays only the current line of text. |
Let's now create a PtList widget and add text to the widget using the list editor. This editor lets you add and edit text for any widget that provides a list of text items.
Click Add After to place this new item after the previous item.
At times, you might want to create many widgets that look and behave alike. You can do this by creating a widget, editing its resources, and then copying and pasting it, but this isn't always very convenient, and doesn't copy certain important elements like callbacks.
PhAB makes it simpler by letting you create a template from an existing widget or widgets. PhAB creates a palette, similar to the widget palette, for your templates.
Let's create a template from the button that you created earlier in this tutorial.
Choose User Folder, type My_templates as the folder's name, and click Add. The dialog closes, and the folder's name is displayed in the Define template dialog.
Click Done.
You've just created a template! Now, let's see how to use it.
If you wish, you can save, generate, make, and run the application.
Whenever you start PhAB, it automatically loads the palette for My_templates.
You now know the basics of editing any widget resource in PhAB. For more information, see the following sections in the Editing Resources and Callbacks in PhAB chapter:
To edit: | See this section: |
---|---|
Bitmaps or images | Pixmap editor |
Colors | Color editor |
Flags | Flag/option editor |
Fonts | Font editor |
Lists of text items | List editor |
Numbers | Number editor or Flag/option editor |
Single-line or multiline text strings | Text editors |
For more information on templates, see “Templates” in the Creating Widgets in PhAB chapter.
This tutorial takes you through the steps required to create menus and menubars.
In this tutorial, you'll learn how to set up a link callback, one of the key components of PhAB. To understand what a link callback is, let's start with some background info on widget callbacks.
Almost all widgets support a variety of callbacks. These callbacks enable your application's interface to interact with your application code. For example, let's say you want your application to perform an action when the user clicks on a button. In that case, you would attach a callback function to the button's “Activate” callback.
In some windowing environments, you can attach only code functions to widget callbacks. But whenever you use PhAB to create a callback, you can go one step further and attach entire windows, dialogs, menus, and much more. It's this extended functionality that we call a link callback.
PhAB provides two basic types of link callbacks:
To access a widget from your application code, you must first give the widget an instance name. Since all widget instance names reside in the same global namespace, no two widgets within an application can have the same instance name.
We recommend that you start every instance name with a module prefix. For example, if your base window has a PtButton widget that contains the label text “Blue,” you could give this widget an instance name of base_blue.
Adopting a naming convention for your widgets will make it easier for you to work with large applications. |
To learn about using link callbacks, let's create two functioning menus—File and Help—that you can later incorporate into your own applications.
In PhAB, menus are built in two pieces:
Using link callbacks, you'll link the menu modules to the File and Help buttons in a menubar. You'll also link a code-type callback to the Quit menu item in the File menu module. This callback will enable the Quit item to close the application.
The menubar grows and shrinks as you change the width of the window, and it always stays at the top of the window. You can see this by clicking in the titlebar of the window, then resizing the window by dragging on one of its resize handles.
If you accidentally click the Test button, the window won't resize or accept new widgets. If this happens, you just switched into Test Mode. To go back to Edit Mode, select | .
By the time you're finished the following steps, the menubar will look like this:
Now that you have menu buttons, you need to create your menu modules. Let's start with the File menu.
Let's now add some menu items to the File menu.
If you click another module, the menu module becomes deselected, which means you can't work on it. To reselect the menu module, click its titlebar. |
If you look at the Menu Items list, you'll see that the <New> item is selected. This special item lets you add menu items to the menu.
Using what you just learned about creating a menu module, do the following:
If one of your menu modules seems to “disappear” (you may have accidentally closed it or placed it behind another module), it's easy to bring the module back into view. See the “Finding lost modules and icons” in the Working with Modules chapter. |
Let's return to the menu buttons you created earlier and attach link callbacks so that the buttons can pop up your menu modules.
Click Arm to bring up the callback editor.
You can also select filemenu from a popup list of available modules. To bring up the list, click the icon to the right of the Name field.
Let's now attach a code-type link callback to the File menu's Quit item so that it can terminate the application.
The function should have a meaningful name. So type quit in the Function field.
You'll now generate the code for your application and edit a generated code stub so that the Quit item will cause your application to exit.
Scroll through the list until you see the quit.c file. This is the generic code template that PhAB generated for your quit() function.
int quit( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { /* eliminate 'unreferenced' warnings */ widget = widget, apinfo = apinfo, cbinfo = cbinfo; PtExit( EXIT_SUCCESS ); /* This statement won't be reached, but it will keep the compiler happy. */ return( Pt_CONTINUE ); }
PtExit() is a function that cleans up the Photon environment and then exits the application. It's described in the Photon Library Reference.
If you are using the IDE, you can also edit quit.c, or any other source code file, from the IDE editor by double-clicking the file in the project navigator tree. |
For more info on: | See the section: | In the chapter: |
---|---|---|
Widget callbacks | Callbacks | Editing Resources and Callbacks in PhAB |
Editing callbacks | Editing Resources and Callbacks in PhAB | |
Instance names | Instance names | Creating Widgets in PhAB |
Menu modules | Menu modules | Working with Modules |
This tutorial describes how to create a dialog. It also provides a good example of how you can use setup code to modify a widget's resources before the widget appears onscreen.
This tutorial uses the application you created in Tutorial 3. |
In this tutorial, you'll:
Dialog modules are designed to let you obtain additional information from the user. Typically, you use this information to carry out a particular command or task.
Since you don't usually need to get the same information twice, dialogs are single-instance modules. That is, you can't realize the same dialog more than once at the same time. If you try create a second instance of a dialog, PhAB simply brings the existing dialog to the front and gives it focus.
If you need to create a window that supports multiple instances, use a window module. You'll learn about window modules in the next tutorial.
To make it easier for you to access widgets from within your application code, PhAB generates a constant and a manifest. Both of these are based on the widget's instance name.
The constant, which has the prefix ABN_, represents the widget's name. The manifest, which has the prefix ABW_, represents the widget's instance pointer.
For example, let's say you have a widget named about_version. PhAB uses this name to generate a constant named ABN_about_version and a manifest named ABW_about_version.
In this tutorial you'll learn how to use these generated names.
The value of a widget's ABN_... constant is unique in the entire application. |
Using this function, we'll change the content of a label widget within the dialog to display a version number.
Your callback information should now look something like this (depending on the location you chose):
You'll see the new dialog in the work area. You'll also see the new callback in the Callbacks list in the callback editor.
Later, you'll fill in the aboutdlg_setup() function so that it changes the blank text of this label to display a version number.
The two labels and the button should now be centered horizontally within your dialog. Your aboutdlg module should now look like this:
Now let's add a callback to the Done button so that the dialog closes when the user clicks on the button.
Selecting the Done code type tells the widget to perform a “Done” operation when the widget is activated. That is, the widget calls the function specified in the Function field (if one is specified) and then closes the dialog module.
You'll now modify the generated aboutdlg_setup() function so that it changes the text of the about_version label to show a version number.
Change the code from:
int aboutdlg_setup( PtWidget_t *link_instance, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { /* eliminate 'unreferenced' warnings */ link_instance = link_instance, apinfo = apinfo, cbinfo = cbinfo; return( Pt_CONTINUE ); }
to the following:
int aboutdlg_setup( PtWidget_t *link_instance, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { /* eliminate 'unreferenced' warnings */ link_instance = link_instance, apinfo = apinfo, cbinfo = cbinfo; PtSetResource( ABW_about_version, Pt_ARG_TEXT_STRING, "1.00", 0); return( Pt_CONTINUE ); }
The code is placing the version number (1.00) into the text string resource for the about_version widget. To do this, the code calls PtSetResource() to set the resource for the about_version widget. The code uses the PhAB-generated manifest ABW_about_version, which provides access to the widget's instance pointer.
We can use this manifest safely since we're dealing with a dialog module—PhAB ensures that only one instance of the dialog will exist at any given time.
You're now ready to compile and run the program:
For more info on: | See the section: | In the chapter: |
---|---|---|
Using dialogs | Dialog modules | Working with Modules |
Instance names | Instance names | Creating Widgets in PhAB |
Variables and manifests | Working with Code | |
Callbacks | Callbacks | Editing Resources and Callbacks in PhAB |
Code-callback functions | Working with Code | |
Generating code | Generating application code | Generating, Compiling, and Running Code |
In the previous tutorial, you learned how to handle dialog modules, which support just one instance. In this tutorial you'll learn how to handle window modules, which support multiple instances.
This tutorial uses the application you created in Tutorial 4. |
By supporting multiple instances, window modules provide more flexibility than dialogs. But to take advantage of this flexibility, you must keep track of each window's instance pointer. Doing so ensures that you correctly reference the widgets within each instance of a window. You can't safely use the generated global ABW_xxx manifest since it refers only to the last instance created.
To simplify the task of working with multiple instances, PhAB provides API library functions that let you access any widget by means of its generated constant name (ABN_xxx).
To start, let's create a window module and attach it to the New menu item in the File menu in tut4. This window will contain buttons that change the color of another widget.
In the previous tutorial, you created a dialog module from within the callback editor. But this time you'll add the window from the Project menu. In the future, use whatever method you prefer.
Because a window module supports multiple instances, you have to create code functions that will be called whenever the window opens or closes (i.e. whenever the window is created or destroyed). So let's first set up a callback to detect when the window closes:
Click Apply, then Done.
Open the filemenu menu module, then select the Menu Items resource in the Resources control panel. You'll see the menu editor.
Let's now add some widgets to the newwin window module. Using these widgets, you'll learn how to update information in the current or other instances of a window module.
Your window should now look something like this:
In the last tutorial, you used the generated ABW_xxx manifest to access a dialog's instance pointer. You can't use this manifest when dealing with multiple instances of a window module since it refers only to the last window created. Instead, you have to add code to the generated window-setup function so that it stores a copy of each window-instance pointer in a global widget array. In this tutorial, you'll need these pointers for the Change Previous Window Color button to work.
Open the Build menu and select Generate UI.
Now let's modify the newwin_setup() function so that it:
Edit the newwin_setup.c file as follows:
int win_ctr = 0; PtWidget_t *win[5]; int newwin_setup( PtWidget_t *link_instance, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { char buffer[40]; /* eliminate 'unreferenced' warnings */ link_instance = link_instance, apinfo = apinfo; cbinfo = cbinfo; /* Note: Returning Pt_END in a prerealize setup function tells PhAB to destroy the module without realizing it */ /* allow only 5 windows max */ if ( win_ctr == 5 ) { return( Pt_END ); } /* save window-module instance pointer */ win[win_ctr] = link_instance; sprintf( buffer, "Window %d", win_ctr + 1 ); PtSetResource( win[win_ctr], Pt_ARG_WINDOW_TITLE, buffer, 0 ); win_ctr++; return( Pt_CONTINUE ); }
Now let's modify the color_change() function so that:
If this were a dialog module you could use the ABW_color_rect manifest to update the color of the rectangle. However, because these are window modules, you must use the instance pointer for the window in which the button is being pressed. |
To get the instance pointer of a widget in the current window, you need to call:
If only one instance of the window were guaranteed, the following would work:
PtSetResource( ABW_color_rect, Pt_ARG_FILL_COLOR, buffer, 0 );
But in this case color_change() has to use:
PtSetResource( ApGetWidgetPtr( ApGetInstance( widget ), ABN_color_rect ), Pt_ARG_FILL_COLOR, buffer, 0 );
So you need to change color_change.c to look like:
PgColor_t colors[5] = {Pg_BLACK, Pg_YELLOW, Pg_MAGENTA, Pg_CYAN, Pg_GREEN}; int base_clr = -1; extern int win_ctr; extern PtWidget_t *win[5]; int color_change( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { int i, prev; PtWidget_t *this_window; /* eliminate 'unreferenced' warnings */ widget = widget, apinfo = apinfo, cbinfo = cbinfo; /* Get a pointer to the current window. */ this_window = ApGetInstance( widget ); if ( ApName( widget ) == ABN_btn_red ) { PtSetResource( ApGetWidgetPtr( this_window, ABN_color_rect ), Pt_ARG_FILL_COLOR, Pg_RED, 0 ); } else if ( ApName( widget ) == ABN_btn_green ) { PtSetResource( ApGetWidgetPtr( this_window, ABN_color_rect ), Pt_ARG_FILL_COLOR, Pg_GREEN, 0 ); } else if ( ApName( widget ) == ABN_btn_blue ) { PtSetResource( ApGetWidgetPtr( this_window, ABN_color_rect ), Pt_ARG_FILL_COLOR, Pg_BLUE, 0 ); } else if ( ApName( widget ) == ABN_btn_prev ) { /* Note: Here we use the window-module instance pointers saved in newwin_setup to update the window previous to the current window provided it hasn't been closed. Determine which window is previous to this window. */ prev = -1; for ( i = 0; i < win_ctr; i++ ) { if ( win[i] == this_window ) { prev = i - 1; break; } } /* If the window still exists, update its background color. */ if ( prev != -1 && win[prev] ) { base_clr++; if (base_clr >= 5) { base_clr = 0; } PtSetResource( win[prev], Pt_ARG_FILL_COLOR, colors[base_clr], 0 ); } } return( Pt_CONTINUE ); }
Last of all, you need to modify newwin_close() so that it sets the win array of instance pointers to NULL for a window when it's closed. That way, you can check for NULL in the win array to determine whether the window still exists.
Modify newwin_close.c as follows:
extern int win_ctr; extern PtWidget_t *win[5]; int newwin_close( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) { PhWindowEvent_t *we = cbinfo->cbdata; int i; /* eliminate 'unreferenced' warnings */ apinfo = apinfo; /* only process WM close events */ if ( we->event_f != Ph_WM_CLOSE ) { return( Pt_CONTINUE ); } /* okay it's a close so who is it? */ for ( i = 0; i < win_ctr; i++ ) { if ( win[i] == widget ) { win[i] = NULL; break; } } return( Pt_CONTINUE ); }
For more info on: | See the section: | In the chapter: |
---|---|---|
Using windows | Window modules | Working with Modules |
Instance names | Instance names | Creating Widgets in PhAB |
Variables and manifests | Working with Code chapter | |
Callbacks | Callbacks | Editing Resources and Callbacks in PhAB |
Code-callback functions | Working with Code | |
Generating code | Generating application code | Generating, Compiling, and Running Code |
Window events | Window-management flags | Window Management |