Beruflich Dokumente
Kultur Dokumente
Appendix B: Solutions
Step 10:
Step 12:
Page 2
Appendix B: Solutions
Step 17:
Open the Child Windows folder in the left pane. (you will see all the child objects you have created so far).
Step 18:
In the left pane, click on pbSet and in the right pane, click on tab Actions.Using the Coding Assistant, duplicate the code pictured below. Now write the code for the pbExit push button. (the code is shown below) Press F7 to save and test your application. Save it as Chapter 3 Exercise 1.app.
Page 3
Appendix B: Solutions
Step 4:
Step 5:
Save and test your application. Try and making it a floating toolbar See if you can move it to the bottom or the sides
Page 4
Appendix B: Solutions
Optional Tasks
Step 6:
Page 5
Appendix B: Solutions
Page 6
Appendix B: Solutions
Step 6:
Choose File | Save as and type in the name Chapter 4 Exercise 1.app.
Page 7
Appendix B: Solutions
Step 6:
Modify the code for dfMessage: Trap for the message PAM_Messages When the message is received, evaluate wParam If wParam is TRUE, set the data field value = Hello World If wParam is FALSE, clear the data field
Page 8
Appendix B: Solutions
Step 7: Step 8:
Test and debug. Test your theory: In the left pane, click on the form and in the right pane, click on the Layout tab. Click on the forms background, right-click and choose Preview. Resize the form and the optional frame to be a bit longer, similar to the one in the Preview. Copy and paste several versions of the data field. In the code, append the numbers 2,3 and 4 to names these data fields and run the application. Each data field you duplicated should behave exactly the same as your first. If so, you have completed the exercise correctly. If not - ask your instructor for ideas to fix the problem.
Page 9
Appendix B: Solutions
Step 4:
In the left pane, open the application folder. Right-click on the Windows folder and choose New | Form Window. Type the name of the form, SALCulator.
Step 5:
The Layout tab is already selected for you. Right-click anywhere on the forms background and choose Preview Window. Right-click on the form and choose Properties | Object Title and type in SALCulator.
Step 6:
Press Alt+4 to bring up the Controls Palette. Choose a data field from the Controls Palette and place it on the form. Press Alt+3 to bring up the Attribute Inspector with the focus on the data field and choose Properties Provide an Object Name of dfnVar1, change the Data Type to Numeric, Format to #,##0.00 and right Justify.
Step 7:
Now, copy this data field two times. Change the names of the two new objects to dfnVar2 and dfnResult. Right-click on dfnResult, choose Properties | Editable and set it to No.
Step 8:
Page 10
Appendix B: Solutions
Step 9:
Choose push button from the Controls Palette and drop it next to the Add background text. Type in the + key from the key board as the title and press Enter. Resize the push button to fit in the space you have provided. Right-click, choose Properties, provide a name of pbAdd and choose Done.
Step 10:
Right-click and choose Explore | Actions. (this is where we will write our first bit of code)
Step 11:
When completed, in the left pane, highlight the form SALCulator and choose the Layout tab. Now, repeat the steps above for pbSub, pbMul and pbDiv. Remember to replace the constant ADD with the appropriate constant for each push button. (to speed your development, you could simply copy the pbAdd push button and change the name and constant used in the code)
Step 12:
Now, create the push buttons and code for pbClear and pbExit. The respective code for each is shown below.
Step 13:
In the left pane, click on the Form Window SALCulator. In the right pane, click on the tab Actions and create the code to pass messages received from the push buttons to all the children of the current form.
Page 11
Appendix B: Solutions
Step 14:
Code at the data field level covers two aspects. The first is the PAM_Clear, which causes each data field to clear its own value. This code will reside within each data field.
Step 15:
The second is the PAM_Calc message which, when received, dfnResult will extract the value of wParam and calculate the correct result. For PAM_Clear, navigate in the left pane to the data field dfnVar1 and in the right pane, choose Actions tab and create an On PAM_Clear block of code as pictured below. Highlight the code, right-click and choose copy. Navigate in the left pane to dfnVar2, in the right pane click on the Actions tab, right-click and Paste the code you just copied from dfnVar1. Repeat this for dfnResult.
Step 16:
We have all the data fields set so that they receive a message to clear. Each has a method that calls the SalClearField function. Now, we must write the code for dfnResult to perform the appropriate arithmetic (code illustrated below). Below is the case statement that deals with add, subtract and multiply.
Page 12
Appendix B: Solutions
Step 17:
Above is the code required for the divide logic too. We will look at the part of the case statement that deals with division, and the code to ensure the user cannot divide by 0!.
Choose File | Save , or click on the diskette icon at the upper left portion of the tool bar. Press F7 and test your work.
Page 13
Appendix B: Solutions
Step 8:
Step 9:
Page 14
Appendix B: Solutions
Step 10:
Modify the code under dfnResult to call your function. (remember to provide error checking!)
Step 11:
Page 15
Appendix B: Solutions
Step 6: Step 7:
Use the Attribute Inspector to set its Object Name attribute to axCalculator. Using the data field tool, drop and size a field on the form. Double-click on it to set its Object Name attribute to dfAgeDays. Using the background text tool add suitable background text.
Step 8:
As we are done with the visual part of the application, we want to switch to outline view. In the right pane, click on the Outline tab. Review and duplicate the following code snippets:
Step 9:
Page 16
Appendix B: Solutions
Step 10:
Click on File | Save, or select the diskette icon on the toolbar. Name your application Chapter 09 Exercise 1.app.
Page 17
Appendix B: Solutions
Step 3:
Add a name to the Name datafield in the frmContainerControl. Then click on the Set Value push button. This form embeds the same Word document as a file into the Container control. The file isn't required (after insertion), as the document becomes part of the application. The two windows work totally independently of each other. They are there just to demonstrate different coding techniques. Usually you would either embed a Word document in your application, or invoke it in a separate instance of Word in its own window.
Page 18
Appendix B: Solutions
Page 19
Appendix B: Solutions
Step 3:
SELECT pres_name FROM president WHERE state_born = 'Texas'; SELECT pres_name FROM pres_marriage WHERE nr_children > 4; SELECT p.pres_name , p.party FROM president p , winner w WHERE p.pres_name = w.name AND w.year_elected = 1972; INSERT INTO president ( pres_name , state_born , birth_date ...) VALUES (your_name , etc...............); SELECT p.pres_name , m.spouse_name FROM president p , pres_marriage m WHERE p.pres_name = m.pres_name(+) AND p.death_age is null; DELETE FROM president WHERE pres_name = 'your_name'; COMMIT;
Step 4: Close the Database Explorer down.
Page 20
Appendix B: Solutions
Step 3:
Create a new standard Form Window. Give your new form the title 'Presidents' and name the form frmMain.
Step 4:
Use the standard data field and background text objects from the Controls Palette. Create data fields (and their associated background text) to contain the presidents data: Name Death Age Birth Date Party Years Served State Born
Page 21
Appendix B: Solutions
Step 5:
Use the standard push button from the Controls Palette to create two buttons on the form; one labeled &Next and one labeled &Previous. Disable each of them at start-up by capturing the SAM_Create message and using the function SalDisableWindow(hWndItem). We will enable them later in our code. Each button should have the associated code illustrated below. This is a illustration of what the left pane of your application might look like. You may have them in a different order, but the objects should.
Step 6:
Step 7:
Add an On SAM_AppStartup action to the Application Actions section. In here you will populate SqlDatabase, SqlUser and SqlPassword. Make a call to the function SqlConnect(), passing as a parameter the global SQL Handle, g_hSqlSelect. This function returns TRUE or FALSE indicating success or failure. This information will help us set the Boolean Variable g_bConnected. If the connect was successful, the variable will be set to TRUE, otherwise it will be set to FALSE. If we fail to get a connection to the database, the application will call the function SalQuit(). The code should look like the example shown below.
Page 22
Appendix B: Solutions
Step 8:
On closing the application, the connection to the database should dropped. This is done with an On SAM_AppExit message action in the Application Action section. If we successfully made a connection at the start of the program, the value of g_bConnected will be TRUE. If it is TRUE, we need to disconnect the Sql Handle, g_hSqlSelect. Do this by calling SqlDisconnect(), passing it the Sql Handle. The code to do this is illustrated above.
Step 9:
Add two menus to the Form. The first will be a Pop-up menu for the File | Exit option. In the left pane, click on Window Menu within frmMain. The illustration below shows the code.
Step 10:
Create a top-level menu item. This menu item executes a function immediately upon being clicked, rather than displaying a pop-up menu. The logic is explained below and the code is illustrated on the next page.
Step 11:
In the Menu Actions section create the code to: Prepare the SQL Statement, with SqlPrepare(). Select the desired columns from the president table and places them into the appropriate data fields. Use our global Sql Handle, g_hSqlSelect. Execute the SQL Statement with SqlExecute() Fetch the first row of data with SqlFetchNext() Enable the Next push button, pbNext.
Step 12:
If any of the Sql* functions fail, quit the menu action by returning FALSE immediately. Code is illustrated below:
Page 23
Appendix B: Solutions
Step 13:
For push button pbNext code for an On SAM_Click event. When the button is clicked, we want to fetch the next row of data. To do this, make a call to SqlFetchNext(). In the call, reference g_hSqlSelect and nInd. The global variable, g_hSqlSelect, points to the data associated with the select that was performed when you picked the Select_All menu Item.
Step 14:
Test the result of the Fetch (stored in nInd). If the end of the data set was reached, nInd will contain FETCH_EOF. In this case, inform the user with a message box and disable the pbNext push button.
Step 15:
Remember to enable the Previous push button when this point is reached, using SalEnableWindow().
Step 16:
Capture the Click event on the pbPrevious push button by coding an On SAM_Click action. The code will be similar to the Next button except we wish to fetch the previous row of data. Make a call to SqlFetchPrevious(). In the call, reference g_hSqlSelect and nInd.
Step 17:
Test the result of the Fetch (stored in nInd). If the end of the data set was reached, nInd will contain FETCH_EOF. Again, inform the user with a message box and disable the push button. Remember to enable the Next push button using SalEnableWindow().
Choose File | Save and save your work as Chapter 11 Exercise 1.app. Press F7 and test your work.
Page 24
Appendix B: Solutions
Step 2:
Create a new modal dialog box. In the Parameters tab, create a Receive Sql Handle. Name the variable hSqlParam. A receive variable is a variable that is passed into the dialog and, if changed in the dialog, has its changed value reflected in the calling routine.
Step 3:
Add a data field to the dialog box to prompt for the Database to connect to. Name the data field dfDatabase Set the attribute Max Data Length to 8 Set the attribute Format to Uppercase Create a background text object and set it to &Database (In the Outliner, ensure the background text appears immediately before the dfDatabase data field)
Step 4:
Add a data field to the dialog to prompt for the UserId to log in with. Name the data field dfUserId Set the attribute Max Data Length to 8 Set the attribute Format to Uppercase Create a background text object and set it to &User Name (In the Outliner, ensure the background text appears immediately before the dfUserId data field)
Page 25
Appendix B: Solutions
Step 5:
Add a data field to the dialog to prompt for the Password. Name the data field dfPassword Set the attribute Max Data Length to 8 Set the attribute Format to Invisible Create a background text object and set it to &Password (In the Outliner, ensure the background text appears immediately before the dfPassword data field)
Step 6:
Initialize dfDatabase to 'PRESIDNT' and dfUserId to 'PRESIDNT', by capturing the SAM_Create message in each of these data fields. In the outliner, the code in the contents section of the dialog should look like the example shown below.
Step 7:
Add a push button to allow you to close the dialog box and quit the application, without logging in. Title the push button &Cancel Name the push button pbCancel Set the attribute Keyboard Accelerator to Esc
Step 8:
Add a SAM_Click message action to pbCancel which closes the dialog without setting hSqlParam, and returns FALSE to the calling routine - SalEndDialog(hWndForm,FALSE).
Step 9:
Add two Window Variables to the dialog box to track the process of logging in to the database. Add a Boolean called bConnect and a Sql Handle called hSqlLocal. These will be used as working variables in step 14 where we process the SAM_Click action on a Connect push button.
Step 10:
Add a push button to the dialog to allow connection to the database with the current selections. Title the push button &Connect Name the push button pbConnect Set the attribute, Keyboard Accelerator, to Enter.
Step 11:
Add a SAM_Click message action to pbConnect, which attempts to connect a Sql Handle to the database and, if successful, returns TRUE to the calling routine, indicating success.
Page 26
Appendix B: Solutions
Save the library file. If you have not already done so, open your solution from Chapter 11 Chapter 11 Exercise 1.app (or the template Chapter 12 Template 1.app). Save it as Chapter 12 Exercise 1.app.
Step 14:
At the application level, in the Libraries tab, add a new Include Library entry. Type the file name of the include file, Chapter 12 Exercise 1.apl. (notice that the login dialog box dlgLogin is now included in your code. It appears in a different color or font, and can not be edited directly)
Step 15:
Modify the SAM_AppStartup code to use your dialog to log in rather than connecting automatically. Pass the global Sql Handle g_hSqlSelect to the dialog in the SalModalDialog() function call. This will allow the dialog to connect our global Sql Handle to the database. Remove the code that sets the system variable SqlDatabase. Replace the call to SqlConnect with a call to create the login dialog box (SalModalDialog()). The dialog was created to return TRUE, if Connect is clicked (and the database connection is successful) and to return FALSE, if Cancel is selected. This return value becomes the return value for the SalModalDialog() function. Set g_bConnected equal to this return value, and test it as you did before. Quit the application if the return is FALSE. If the return is TRUE, create the main form window, frmMain, with a call to SalCreateWindow(). Make the owner hWndNULL since this will be the first form in our application.
Page 27
Appendix B: Solutions
Modify frmMain to not be automatically created by setting the attribute Automatically Create to No. Press F7 to save the application and test it.
Page 28
Appendix B: Solutions
Step 5:
Define the following Dialog Box Window Variables. These will be used as temporary variables when processing errors locally. Sql Handle: Number: Number: hSqlError nSqlError nSqlErrorPosition
Step 6:
Modify the Click action for pbConnect to include Local Error Handler code (When SqlError). Ensure this code appears before the call to SqlConnect and at the same level of indentation.
Page 29
Appendix B: Solutions
Step 7:
The code in the Error Handler should extract the error parameters, test them against the constants defined in step 3, and display appropriate messages. If the error is one of these three, return FALSE. If it is not, do nothing (so that the error falls through to be handled by global error processing).
Step 8:
Save the changes and return to your application Chapter 12 Exercise 2.app. Re-run your application to test your new Error Handler.
Step 9:
Go back to the library Chapter 12 Exercise 2.apl and remove the maximum character length constraint in the properties of the Database data field. Click the secondary mouse button on the data field and delete the Max Data Length attribute of 8.
Step 10:
Save the library and return to the application Chapter 12 Exercise 2.app. Ensure that global error processing occurs if a database name of 9 characters or greater is used.
Step 11:
Add your own global error processing to Chapter 12 Exercise 2.app. Capture the application message SAM_SqlError, and display a message to the user, 'An unknown database error occurred. Quit the application?'. Offer the user the opportunity to choose Yes or No. If Yes is selected, quit the application Otherwise let the program fall through to default error processing.
Step 12:
Page 30
Appendix B: Solutions
To your Exit push button, code an On SAM_Click message action that makes a Call to SalQuit(). Once the design window is back in the Layout tab, right click on the "Exit" push button and choose Explore | Actions from the context menu. This will select the pbExit folder in the left pane and the Actions tab in the right pane. You can then code the message handler using the Coding Assistant and/or the outliner.
Step 6:
Add a column for the president name to your tblPresident child table window. Set the following attributes: Object Name: Object Title: Data Type: colPresName President String
Step 7:
Add a column for the state where the president was born to your tblPresident child table window. Set the following attributes: Object Name: Object Title: Data Type: colStateBorn State Born String
Step 8:
Add a column for the president's birth date to your tblPresident child table window. Set the following attributes: Object Name: Object Title: Data Type: colBirthDate Birth Date Date/Time
Step 9:
Add a column for the president's party to your tblPresident child table window. Set the following attributes: Object Name: Object Title: Data Type: colParty Party String
Step 10:
Add a column for the president's spouse to your tblPresident child table window. Set the following attributes: Object Name: Object Title: Data Type: colSpouse Spouse String
Page 31
Appendix B: Solutions
Step 11:
Add a column for the spouse's age to your tblPresident child table window. Set the following attributes: Object Name: Object Title: Data Type: colSpouseAge Spouse's Age Number
Step 12:
Add a column for the number of children to your tblPresident child table window. Set the following attributes: Object Name: Object Title: Data Type: colNumChildren # Children Number
Step 13:
Add the Chapter 12 Exercise 2.apl library file to the application. To do this, select the application folder in the left pane and select the Libraries tab in the right pane. Right click in the right pane and choose Add Next Level | File Include from the context menu. An Open dialog box will appear where you can select the library file. Once you click on Open button, it will be included in the application.
Step 14:
Select the frmPresident folder in the left pane and the Variables tab in the right pane. Add a Sql Handle variable called hSqlPres and add a Boolean variable called bConnected.
Step 15:
Select the Actions tab in the right pane and add both On SAM_Create and On SAM_Destroy message handlers. The following code fragment shows how to connect the Sql Handle using the Login dialog box on the creation of the form window and how to disconnect the Sql Handle on the closing of the form window.
Step 16:
In the Functions section of the Child Table Window, add a Populate() function which, when called, will use SalTblPopulate() to fill the Table Window with columns from the president and spouse tables, joined by pres_name.
Page 32
Appendix B: Solutions
Step 17:
Call your Populate function from an On SAM_CreateComplete action on the Child Table Window. Add the message handler code as shown:
Step 18:
Page 33
Appendix B: Solutions
Step 4: Step 5:
Add a background text item containing the word States in front of your combo box. Previously, our table populated itself on SAM_CreateComplete. We want to change our approach so that the table will be populated when we press a push button. To begin, we need to define our own PAM_Populate user message, using SAM_User, in the Constants tab of the application folder as shown:
Step 6: Step 7:
In tblPresident, change the On SAM_CreateComplete action to On PAM_Populate. In the Child Table Window's Populate function, include a reference to the combo box in the where clause of the SalTblPopulate() function. Our goal is to only fill the table with presidents born in the state selected in cmbStates.
Step 8:
Add a Query push button. Set the following attributes: Object Name: Object Title: pbQuery &Query
Step 9:
Include a SAM_Click action in pbQuery to post a PAM_Populate message to the form window.
Page 34
Appendix B: Solutions
Step 10:
Finally, add an On PAM_Populate message handler to the form window, which sends a PAM_Populate message to the form's children.
Step 11:
Page 35
Appendix B: Solutions
Step 4:
Page 36
Appendix B: Solutions
Step 3:
Your states table needs a function to add a new row. Ideally, your function should insert the row, place the focus on that row in the state column and scroll the row into view.
Step 4:
Add a delete function to toggle the ROW_MarkDeleted flag on the current row. In the example below, the current state of the ROW_MarkDeleted flag is tested and then reversed:
Step 5:
Add an ApplyChanges() function to the states table to perform DML from the table window against the states database table. Commit the transactions, and then re-populate the table window. You may want to turn the hourglass cursor on and then off before and after the following sample code:
Page 37
Appendix B: Solutions
Step 6:
Complete the message actions for the table window so that each calls the appropriate function, as follows:
Step 7:
Page 38
Appendix B: Solutions
Step 4:
What remains is to code each of the three If blocks. In each case, you should prepare a suitable SQL statement and then, using SalTblFindNextRow(), skip through each of the rows with the appropriate flags, executing the statement. Here are examples for each of the three code blocks:
Page 39
Appendix B: Solutions
Step 5:
Page 40
Appendix B: Solutions
Step 3:
Step 4:
In the SAM_CreateComplete action for the tblPresidents, set the TBL_Flag_SelectableCols table flag on.
Step 5:
In the functions section of the table, write a function to sort the table. Your function should accept a single window handle argument and sort the table by that column.
Step 6:
Add a SAM_ColumnSelectClick action to tblMaintainPresidents that calls your sort function, passing it the result after converting wParam to a window handle.
Page 41
Appendix B: Solutions
Step 7:
In the lower left corner of dlgMaintainPresidents, add a radio button. Set its properties as follows: Object Name: Object Title: rb1700 1700
Add two more radio buttons beside rb1700, named rb1800 and rb1900, and titled 1800 and 1900 respectively. Surround your radio buttons with a group box entitled Show Presidents Born After In the functions section of tblPresidents, write a function to hide the rows containing presidents born before the specified century. Your function should accept a single numeric argument (the year), and then scan through each president row, hiding the older ones and showing the ones born after the specified year. (Hint: Use SalTblQueryScroll() to get the number of rows in the table first)
Finally, call your hide function from a SAM_Click action in each radio button. Save and test your code by pressing F7.
Optional Solutions Step 13: Return to the ColumnSort() function you created in step 4. Add the following code after the SalTblSortRows() function:
Page 42
Appendix B: Solutions
Optional Solutions Step 5: In the Constants tab of the application folder, add the following user constant definition:
Step 6:
In the Actions tab of the table window, add the following message handler: The nSummaryRow variable should be defined as a variable of the child table window, not the Populate() function, so that we can use its value in the SAM_SetFocus message handler. And in the Actions tab of the table window, add the following message handler for the PAM_SetFocusToRow message
Page 43
Appendix B: Solutions
Page 44
Appendix B: Solutions
Step 5:
Step 6:
Step 7:
Page 45
Appendix B: Solutions
Step 8:
Step 9:
Click on File | Save, or select the diskette icon on the toolbar. Name your application Chapter 16 Exercise 1.app.
Page 46
Appendix B: Solutions
Set a break group on PARTY Define the report layout. Click on File | Save, or select the diskette icon on the toolbar. Name your application Chapter 16 Exercise 1.app.
Step 7: Step 9:
In your application, define a function ( OpenReport) as a global internal function. Save and test your application.
Page 47
Appendix B: Solutions
Step 5: Step 6:
Add a method with a name of Add. Add arguments Number1 and Number2 both of data type Number(VT_R4).
Step 7:
Page 48
Appendix B: Solutions
Step 8: Step 9:
Click on Next > and then click on Finish to generate the SAL Code. In the Interface for AddNumbers ( IAddNumbers) click on the function Add and in the outline add the code:
Page 49
Appendix B: Solutions
Step 3: Step 4:
Use Project | Build Server to build Chapter 18 Exercise 1.dll. Use Project | Register Server to register your server in the registry.
Page 50
Appendix B: Solutions
Step 3: Step 4:
Step 6:
Step 7:
In the Message Actions section for the Add Pushbutton, code the On SAM_Click action. This should call the Add function of the instance of the COM Proxy Class that you defined:
Step 8:
Compile and test your program. Test your program with values other than integers to verify that the correct data types are being used as parameters. The default data type is I2, which will cause 1.01 + 1.49 to return a result of 2 rather than 2.5.
Page 51
Appendix B: Solutions
Step 4:
Step 5:
Step 6:
Page 52
Appendix B: Solutions
Step 4:
In the Variables section of the dialog box dlgMaintainStates, Add a variable of the newly created (FC) data type. Make it an array by added a left [, a value (* - for dynamic) and a right ].
Step 5:
In the Actions section of the Child Table tblMaintainStates, Add the an assignment statement to populate you array.
Step 6:
In the Actions section of the dialog box dlgMaintainStates, Add the SalSerializeUDV function call.
Page 53
Appendix B: Solutions
Step 7:
Page 54
Appendix B: Solutions
Step 4:
Step 5:
Page 55
Appendix B: Solutions
Step 4:
Page 56