From: <os...@us...> - 2012-03-31 10:48:53
|
Revision: 7715 http://oorexx.svn.sourceforge.net/oorexx/?rev=7715&view=rev Author: osims Date: 2012-03-31 10:48:45 +0000 (Sat, 31 Mar 2012) Log Message: ----------- Almost completed (with Mark's recent mods included). Modified Paths: -------------- docs/trunk/oodguide/Chapter06.xml Modified: docs/trunk/oodguide/Chapter06.xml =================================================================== --- docs/trunk/oodguide/Chapter06.xml 2012-03-31 02:49:14 UTC (rev 7714) +++ docs/trunk/oodguide/Chapter06.xml 2012-03-31 10:48:45 UTC (rev 7715) @@ -38,13 +38,14 @@ ######################################################################### --> -<!-- Chapter06 - List Views, Re-Sizing, and PopUps v00-04 ??Feb12 +<!-- Chapter06 - List Views, Re-Sizing, and PopUps v00-05 31Mar12 Changes: v00-01 25Aug11: First version v00-02 03Dec11: Second version. v00-03 03Feb12: Sorted out structure; added text. v00-04 ??Feb12 + v00-05 31Mar12: Almost completed. 6 "An Application Workplace" chapSix 6.1 Program Structure chap06-struc @@ -65,6 +66,10 @@ 6.5 Creating and Using Icons chap06-icons 6.6 Utility Dialogs chap06-utildlgs + Questions: + - - - - - - + 1. Is OrderMgr vs OrderMgrBaseView handled properly? + 2. Show an example of ReportView with small icons in Ex 7. Have say 3 different ones in a single bitmap. --> <!-- is the following useful?? - the OrderManagerView @@ -112,8 +117,6 @@ <para><link linkend="chap06-utildlgs" endterm="utildlgs.title"></link></para> </listitem> </itemizedlist> - Test of xref only: 1: blah <xref linkend="chapFour"/> blah. 2: blah <xref linkend="chapFour"> - blah. 3: blah <xref linkend="chapFour"> blah. </para> <section id="chap06-struc"><title id="progstruc.title">Program Structure</title> <!-- Section 6.1 --> @@ -370,14 +373,13 @@ to the specific instance of <computeroutput>ProductView</computeroutput> from which it is launched; other instances of <computeroutput>ProductView</computeroutput> are unaffected, as are other dialogs.) </para> - <para>So, for a dialog to be "popped up as child", there has to be a parent dialog that was surfaced - with either <emphasis role="italic">~popup</emphasis> or <emphasis role="italic">~execute</emphasis>. - This presents a problem for stand-alone testing. The solution adopted in the sample Order Management - application is illustrated in the following code fragment, taken from - <computeroutput>CustomerListView</computeroutput>'s - <emphasis role="italic">activate></emphasis> method (which is called from its - <emphasis role="italic">newInstance</emphasis> class method): - <programlisting> + <para>So, for a dialog to be "popped up as child", there has to be a parent dialog that was + surfaced with either <emphasis role="italic">~popup</emphasis> or <emphasis role="italic" + >~execute</emphasis>. This presents a problem for stand-alone testing. The solution + adopted in the sample Order Management application is illustrated in the following code + fragment, taken from <computeroutput>CustomerListView</computeroutput>'s <emphasis + role="italic">activate></emphasis> method (which is called from its <emphasis + role="italic">newInstance</emphasis> class method): <programlisting> <![CDATA[ ::METHOD activate UNGUARDED expose rootDlg @@ -389,21 +391,20 @@ else self~popupAsChild(rootDlg, "SHOWTOP", ,"IDI_CUSTLIST_DLGICON") return ]]> - </programlisting> - This code illustrates the two ways of starting a dialog. For stand-alone testing (see - <xref linkend="apx-satesting"/>), the dialog is started using - <emphasis role="italic">self~execute()</emphasis>. In normal operation, however, it is started by - <emphasis role="italic">self~popupAsChild(...)</emphasis>. Notice that the first parameter of - <emphasis role="italic">~popupAsChild(rootDlg, ...)</emphasis> is the <computeroutput>OrderMgrView</computeroutput> - dialog, which is passed to the <emphasis role="italic">newInstance</emphasis> - class method and thence as the parameter <emphasis role="italic">rootDlg</emphasis> to the - <emphasis role="italic">activate</emphasis> method. This dialog, the - <computeroutput>CustomerListView</computeroutput> class, is both a child of the - <computeroutput>OrderMgr</computeroutput> and parent of the - <computeroutput>Customer</computeroutput> class. Later in - <computeroutput>CustomerListView</computeroutput>, a Customer is displayed by the user - double-clicking on an item in the List View. The event handler method (<emphasis role="italic">showCustomer</emphasis>) - that surfaces the Customer is as follows: + </programlisting>This code illustrates the two ways of starting a dialog. For + stand-alone testing (see <xref linkend="apx-satesting"/>), the dialog is started using + <emphasis role="italic">self~execute()</emphasis>. In normal operation, however, it is + started by <emphasis role="italic">self~popupAsChild(...)</emphasis>. Notice that the + first parameter of <emphasis role="italic">~popupAsChild(rootDlg, ...)</emphasis> is the + <computeroutput>OrderMgrView</computeroutput> dialog, which is passed to the <emphasis + role="italic">newInstance</emphasis> class method and thence as the parameter <emphasis + role="italic">rootDlg</emphasis> to the <emphasis role="italic">activate</emphasis> + method. This dialog, the <computeroutput>CustomerListView</computeroutput> class, is both + a child of the <computeroutput>OrderMgr</computeroutput> and parent of the + <computeroutput>Customer</computeroutput> class. Later in + <computeroutput>CustomerListView</computeroutput>, a Customer is displayed by the user + double-clicking on an item in the List View. The event handler method (<emphasis + role="italic">showCustomer</emphasis>) that surfaces the Customer is as follows: <programlisting> <![CDATA[ ::METHOD showCustomer UNGUARDED @@ -428,83 +429,110 @@ ]]> </programlisting> The list of customers is shown in a ListView control (see <link linkend="lviews.title">Icons and Lists</link> below). - The <emphasis role="italic">showCustomer</emphasis> method is invoked when the user double-clicks - on an item in the list. This item is identified by the - statement <emphasis role="italic">item = lvCustomers~selected</emphasis>, the proxy object for the - list control being <emphasis role="italic">lvCustomers</emphasis>. If no item is selected, an error message - is displayed, and the method returns. The data in the selected row is then placed in a directory - (with an error check in case <emphasis role="italic">~getItemInfo</emphasis> returns - <computeroutput>.false</computeroutput>). The next statements (<emphasis role="italic">.local~my...</emphasis>) - create instances of the <computeroutput>CustomerModel</computeroutput> and <computeroutput>CustomerData</computeroutput> - classes that are required by <computeroutput>CustomerView</computeroutput> (see <link linkend="chap03-cplg">Reducing - Coupling</link>. Then an instance of <computeroutput>CustomerView</computeroutput> is created by the - statement <emphasis role="italic">.CustomerView~newInstance(rootDlg,"CU003")</emphasis>. Finally, the "Show - Customer" pushbutton is disabled. - </para> + The <emphasis role="italic">showCustomer</emphasis> + method is invoked when the user double-clicks on an item in the list. This item is + identified by the statement <emphasis role="italic">item = + lvCustomers~selected</emphasis>, the proxy object for the list control being <emphasis + role="italic">lvCustomers</emphasis>. If no item is selected, an error message is + displayed, and the method returns. The data in the selected row is then placed in a + directory (with an error check in case <emphasis role="italic">~getItemInfo</emphasis> + returns <computeroutput>.false</computeroutput>). The next statements (<emphasis + role="italic">.local~my...</emphasis>) create instances of the + <computeroutput>CustomerModel</computeroutput> and + <computeroutput>CustomerData</computeroutput> classes that are required by + <computeroutput>CustomerView</computeroutput> (see <link linkend="chap03-cplg">Reducing + Coupling</link>. Then + an instance of <computeroutput>CustomerView</computeroutput> is created by the statement + <emphasis role="italic">.CustomerView~newInstance(rootDlg,"CU003")</emphasis>. The second + parameter is the Customer Number, which is ignored in Exercise 6 (but which will be used in Exercise 7). + Finally, the "Show Customer" pushbutton is disabled. </para> <para> The approach to establishing the model and data objects shown here is not ideal. Indeed, the above code merely satisfies the requirement for a <computeroutput>CustomerView</computeroutput> object to have access to a <computeroutput>CustomerModel</computeroutput> instance which in turn needs access to an instance of - <computeroutput>CustomerView</computeroutput>. Indeed, in this exercise, the data is all hard-coded. The - next exercise will illustrate a much better way of doing this - but with data being read from a disk file + <computeroutput>CustomerView</computeroutput>. And, in this exercise, the data is all hard-coded. The + next exercise will illustrate a much better way of doing this, with data being read from a disk file (a notional "data base"). </para> </section> <!-- End of Section 6.2.1 --> <section id="chap06-popups-offset"><title>Offsetting Dialogs</title> <!-- Section 6.2.2 --> - <para>When creating a resource file for a dialog, it is unusual to define the position of the dialog - on the screen, Instead, the option to center the dialog in the screen us often used. - However, when a number of different dialogs are all - <!-- How get pop-up to pop up away (offset) from parent? Answer - have to code it yourself. + <para>When creating a resource file for a dialog, it is unusual to define the position of the + dialog on the screen. Instead, the option to center the dialog in the screen is often + used. This is the option applied in Exercise 6. However, when a number of different dialogs + are all surfaced in the same place they + tend to overlap each other, so making things difficult for the user who has + to continually move dialogs away from the center. A better approach is to offset + newly-surfaced dialogs from existing ones such that the new dialog pops up in the best + place from a user point of view. This is possible with ooDialog, but is not simple. + </para> + <para> + However, ooDialog also provides a half-way house, where simple code produces a + useful result. This simpler code, which will be used in Exercise 7, is discussed in + <xref linkend="apx-satesting"/>, section <link linkend="apx-satesting-offsets" endterm="offsetting.title"></link>. + The following code illustrates the key functions: + <programlisting> + <![CDATA[ + -- In 'parent' dialog: + ::METHOD getPopupPos + popupPos = self~getRealPos + popupPos~incr(100,100) + return popupPos - Test in ...\Ancillary\Tests\DragDrop: - - In DMHarness: - - ::METHOD startSourceDlg UNGUARDED - parentPos = self~getRealPos /* ooDialog Ref 4.4.22 */ - .DMSource~newInstance(self,parentPos) - - In DMSource: - - ::method newInstance class - use arg parent, parentPos - dlg = self~new - dlg~activate(parent,parentPos) - return - - ::method initDialog - expose ... parentpos - ... - parentPos~incr(100,100) /* ooDialog Ref 9.11.7 */ - self~moveTo(parentPos, 'SHOWWINDOW') /* ooDialog Ref 4.4.35 */ - self~ensureVisible /* ooDialog Ref 3.15.7 */ - - --> - + -- In 'child' dialog: + ::METHOD offset + use arg popupPos + self~moveTo(popupPos, 'SHOWWINDOW') + self~ensureVisible() + ]]> + </programlisting> + The "parent" dialog finds its own position on the screen with + <emphasis role="italic">parentPos=self~getRealPos</emphasis> (where + <emphasis role="italic">parentPos</emphasis> is an instance of the <computeroutput>Point</computeroutput> + class). It then + increments the point's <emphasis role="italic">x</emphasis> and <emphasis role="italic">y</emphasis> + coordinates using the point's <emphasis role="italic">incr</emphasis> method. The result is the child dialog's + desired position. When the parent dialog pops up a "child" dialog, it passes this desired position to + the child dialog. From the child dialog's <emphasis role="italic">initDialog</emphasis> method, either in-line + or with a method call, the instruction <emphasis role="italic">self~moveTo(popupPos,...)</emphasis> moves + the child dialog to the desired position. Finally, the instruction + <emphasis role="italic">self~ensureVisible()</emphasis> ensures that the child dialog is wholly on the screen + and not partly invisible. </para> </section> <!-- End of Section 6.2.2 --> <section id="chap06-popups-interpret"><title>Use of Interpret</title> <!-- Section 6.2.3 --> - <!-- - Starting a dialog from a dialog (incl interpret statement - pointer to later) - Use of "interpret", better would be to have a class object - but later we'll need interpret (won't we?) for the ObjectMgr. - Leave "interpret" in but mention it - say class object would be better - show how can be fixed in later exercise - where - this will be moved to a support class (ObjectMgr). - --> + <para>When an icon in the Order Management dialog is double-clicked, a child dialog is surfaced. + This is handled by two methods in the <computeroutput>OrderMgrView</computeroutput> class. + First, the event-handling method <emphasis>onDoubleClick</emphasis> catches the double-click, + works out which icon (or "record" - see <xref linkend="chap06-lviews"/> below) was double-clicked, + and then calls the <emphasis role="italic">showModel</emphasis> method. + This method uses an + <emphasis role="italic">interpret</emphasis> instruction to launch a view of the + component represented by chosen icon, as follows: + <programlisting> + <![CDATA[ + use arg record + className = record~ID + viewClassName = className||"View" + interpret "."||viewClassName||"~newInstance(self)" + ]]> + </programlisting> + Thus in principle icons for additional components can be added + without changing the code. An arguably better approach could have been to hold the + class object in the record, and to invoke + <emphasis role="italic">newInstance</emphasis> directly on the class object. + However, in the next exercise, the mechanics of invoking the various components will be moved + to a support class called <computeroutput>ObjectMgr</computeroutput>, where use of + <emphasis>interpret</emphasis> will not be optional. + </para> <para> - <!-- Fragment: -->However, the code in the <computeroutput>OrderMgmtView</computeroutput> class uses an - <emphasis role="italic">interpret</emphasis> instruction to launch views of the - components represented by icons. Thus in principle, additional components can be added - without changing the code in the <computeroutput>OrdermgmtView</computeroutput> class. To - support this, a separate file - <computeroutput>RequiresList.rex</computeroutput> - - contains the set of <emphasis role="italic">::requires</emphasis> statements corresponding + Finally, a separate file - <computeroutput>RequiresList.rex</computeroutput> - is used + to contains the set of <emphasis role="italic">::requires</emphasis> statements corresponding to the components that might be surfaced. This is why the first executable statement in - the file <computeroutput>OrderMgmtView.rex</computeroutput> is - <emphasis role="italic">call "OrderMgmt\RequiresList.rex"</emphasis>. + the file <computeroutput>OrderMgrView.rex</computeroutput> is + <emphasis role="italic">call "OrderMgr\RequiresList.rex"</emphasis>. </para> - - </section> <!-- End of Section 6.2.3 --> </section> <!-- End of Section 6.2 --> @@ -514,12 +542,12 @@ <indexterm><primary>Controls</primary><secondary>ListView</secondary></indexterm> <indexterm><primary>Icons</primary><secondary>in a ListView</secondary></indexterm> - <para>The <computeroutput>ListView</computeroutput> should not be confused with <computeroutput>ListBox</computeroutput>; - a ListView (see ooDialog Reference chapter 20) is a souped-up ListBox with lots of additional features. In particular: + <para>A <computeroutput>ListView</computeroutput> should not be confused with a <computeroutput>ListBox</computeroutput>: + a ListView is a souped-up ListBox with lots of additional features. In particular: <itemizedlist> <listitem><para>An item in a ListView can be a complex structure or "record" containing multiple fields. One of these fields is termed the "label" of the item.</para></listitem> - <listitem><para>ListView items can be displayed in four different modes: + <listitem><para>ListView items can be displayed in four different styles (or modes): <itemizedlist> <listitem><para>Icon view - each item appears as a full-sized icon with a label below it. Items can be dragged around the ListView.</para></listitem> @@ -533,10 +561,13 @@ located in the <computeroutput>ooRexx\samples\oodialog</computeroutput> folder.</para></listitem> </itemizedlist> </para> - <para>In the Order Management application, the ListView control provides the main area of the Order Management dialog - where draggable icons (icon view) represent the various components of the application. - It also provides the tabular lists (report views) in the CustomerList, ProductList, and OrderList dialogs. - </para> + <para>In the Order Management application, a ListView control in the "icon" style provides the main area + of the Order Management dialog where draggable icons represent the various components of the application. + The ListView control in the "report" style is used to provide the tabular lists for + <computeroutput>CustomerList</computeroutput>, + <computeroutput>ProductListView</computeroutput>, and <computeroutput>OrderListView</computeroutput> dialogs. + Indeed, the code in these three dialogs is extremely similar, suggesting that a superclass could be useful. + </para> <section id="chap06-lviews-icon"><title>The Icon View</title> <!-- Section 6.3.1 --> <!-- @@ -547,70 +578,32 @@ --> <para> - -<!-- - OMBV -1 ::attribute lv - - OMV -2 ::method init - expose records - self~createIconList 3 - records = self~initRecords 4 - -5 ::method initDialog - expose iconList records - self~lv~newListView(..) - self~lv~setImageList(..) - /*- Add icons (i.e. records) to the ListView: (actually used two hyphens at start - but oXygen doesn't like this.)*/ - do i=1 to records~items - self~lv~addRow(, i-1, records[i]~name) - end - -3 ::method createIconList - expose iconList - imgCustList = .Image~getImage( filename ) - ... - iconList = .ImageList~create(...) - iconList~add(imgCustList) /* item 0 in the list */ - ... - -4 ::method initRecords - expose records - records = .array~new() - rec = .directory~new - rec~ID = "CustomerList" - rec~name = "Customer List" - records[1] = rec - ... - return records - -6 ::method onDoubleClick - expose records - index = self~lv~focused /* lv is an attribute of OBMBV */ ---> - - The OrderManagement dialog uses the Icon View option of the ListView control. Five things are needed to produce an - icon view: first, create (or obtain) some icons; second, specify the <computeroutput>ICON</computeroutput> style for the ListView - control; third, create an ImageList from the icons (required by the ListView control); fourth, create a set of records - (one record per icon) to be loaded into the ListView; and fifth, load the icons and records into the ListView. - </para> + The Order Management dialog is provided by two classes: <computeroutput>OrderMgrBaseView</computeroutput> + and <computeroutput>OrderMgrView</computeroutput>. The former handles re-sizing, and to do this it needs + to know about the ListView control. The latter also needs to know about the ListView control. To provide + for both requirements, the proxy for the ListView control is stored in + <computeroutput>OrderMgrBaseView</computeroutput> as a private attribute named + <emphasis role="italic">lv</emphasis>. + </para> + <para> + Five things are needed to produce an + icon view: first, create (or obtain) some icons; second, specify the <computeroutput>ICON</computeroutput> + style for the ListView control; third, create an ImageList from the icons (required by the ListView control); + fourth, create a set of records (one record per icon) to be loaded into the ListView; and fifth, load the + icons and records into the ListView. + </para> <orderedlist numeration="arabic"> - <listitem> <!-- One --> <para><emphasis role="bold"><emphasis role="italic">Produce the Icons</emphasis></emphasis></para> - <para>First, the large "icons" in the ListView are actually bitmaps. Icons and bitmaps have different formats, and different uses, - and there are a number of differences between them. The icons themselves - are in the folders of the relevant business components, so the icon for the Customer List, for example, is - <computeroutput>Exercise06\Customer\bmp\CustList.bmp</computeroutput>. (The <computeroutput>*.ico</computeroutput> - files are the dialog icons.) - A number of tools are available for creating and editing images, icons, bitmaps etc., - some of them providing conversion and re-sizing capabilities. One such is GIMP (GNU Image Manipulation Program) from - http://www.gimp.org. - <indexterm><primary>Bitmap Editor</primary></indexterm><indexterm><primary>Icon editor</primary></indexterm> + <para>The large "icons" in the ListView are actually bitmaps. Icons and bitmaps have different + formats, and different uses, + and there are a number of differences between them. The bitmaps themselves + are in the folders of the relevant business components, so the "icon" for the Customer List, for example, + is <computeroutput>Exercise06\Customer\bmp\CustList.bmp</computeroutput> (the + <computeroutput>*.ico</computeroutput> files are the dialog icons). See <xref linkend="chap06-icons"/> + for further information. </para> </listitem> - <listitem> <!-- Two --> <para><emphasis role="bold"><emphasis role="italic">Specify the ICON Style</emphasis></emphasis></para> <para>The icon style for a ListView control is specified either in the @@ -626,9 +619,9 @@ <listitem> <!-- 3 --> <para><emphasis role="bold"><emphasis role="italic">Create an ImageList</emphasis></emphasis></para> <para>The ListView documentation provides several ways to load icons. Probably the easiest is to create an - object of type <computeroutput>ImageList</computeroutput> (see ooDialog Reference - section 26.3) which is loaded into the ListView. In <computeroutput>OrderMgmtView</computeroutput>, this - is done in the <emphasis role="italic">createIconList</emphasis> method + instance of the <computeroutput>ImageList</computeroutput> class + which is then loaded into the ListView. In <computeroutput>OrderMgrView</computeroutput>, this + is done in the <emphasis role="italic">createIconList</emphasis> method (invoked from the <emphasis role="italic">init</emphasis> method) as follows: <programlisting> <![CDATA[ @@ -651,21 +644,22 @@ return ]]> </programlisting> - For each icon, only two statements are required: create an Image from file then copy it to the ImageList (and a third, if you're - a polite programmer and try to clean up afterwards, release the image). + For each icon, only two statements are required: create an Image from file then copy it to the ImageList + (and a third, if you're a polite programmer, clean up afterwards by releasing the image). </para> </listitem> <listitem> <!-- 4 --> <para><emphasis role="bold"></emphasis>Create Records</para> - <para>Records are typically created in the <emphasis role="italic">init</emphasis> method (or in a method invoked from there). - In <computeroutput>OrderMgmgtView</computeroutput> the records are created in the <emphasis role="italic">initRecords</emphasis>) - method which is invoked from <emphasis role="italic">init</emphasis>. Each record has two fields: the text to appear beneath - the icon, and the class name of the dialog to be surfaced when a user double-clicks on an icon. The design choice for these records - is that each record will be a directory, and each directory will stored in an array. The array index of a record is equivalent - to the position of its icon in the ImageList (remembering that arrays are 1-based while ImageLists are 0-based). The code for loading - the record array is - as follows (showing only the Sales Orders item for brevity): + <para>Records are typically created in the <emphasis role="italic">init</emphasis> method (or in a method + invoked from there). In <computeroutput>OrderMgrView</computeroutput> the records are created in the + <emphasis role="italic">initRecords</emphasis>) method which is invoked from + <emphasis role="italic">init</emphasis>. Each record has two fields: the class name of the dialog to be + surfaced when a user double-clicks on an icon, and the text to appear beneath the icon. + The design choice for these records is that each record is a directory, and each directory is to be + stored in an array. The array index of a record is equivalent to the position of its icon in the + ImageList (remembering that arrays are 1-based while ImageLists are 0-based). The code for creating + the record array is as follows (showing only the Sales Orders item for brevity): <programlisting> <![CDATA[ ::METHOD initRecords PRIVATE @@ -673,8 +667,8 @@ records = .array~new() ... rec = .directory~new - rec~ID = "OrderList" - rec~name = "Sales Orders" + rec~ID = "OrderList" -- Class Name + rec~name = "Sales Orders" -- Text to display under the icon records[3] = rec ... return records @@ -684,9 +678,11 @@ </listitem> <listitem> <!-- 5 --> <para><emphasis role="bold">Load the ImageList and the Records</emphasis></para> - <para>Loading icon images and records into the ListView is done in the - <emphasis role="italic">initDialog</emphasis>method: - <programlisting><![CDATA[ + <para>Loading icon images and records into the ListView is done in + <computeroutput>OrderMgrView</computeroutput>'s + <emphasis role="italic">initDialog</emphasis>method: + <programlisting> + <![CDATA[ ::METHOD initDialog expose records iconList self~initDialog:super @@ -696,20 +692,21 @@ end ]]> </programlisting> - After invoking the superclass, the icons in the ImageList are applied to the ListView control - using its <emphasis role="italic">setImageList</emphasis> method. The second parameter of this method - specifies the size of the icons by invoking - the Image class' <emphasis role="italic">toID</emphasis> method with the parameter <emphasis role="italic">LVSIL_NORMAL</emphasis> - (the flag for the icon view). The Image class is used to work with and manipulate images, - and is described in section 26.2 of the ooDialog Reference. The variable - <emphasis role="italic">self~lv</emphasis> is the list view proxy, <emphasis role="italic">lv</emphasis> being an - attribute of the <computeroutput>OrderMgmtBaseView</computeroutput> superclass. - The icons having been set, the records are then added - using the ListView's <emphasis role="italic">addRow</emphasis> method. The first parameter is the index of the list item - - if omitted, the record is added after the last. The second parameter is the index of the icon to be used with this record, and - the last parameter is the label for the list item - the string "Customer List" in the case of the first item added to the ListView in - <computeroutput>OrderMgmtView</computeroutput>. - </para> + After invoking the superclass, the icons in the ImageList are all applied to the ListView control in the + single statement, <emphasis role="italic">self~lv~setImageList(..)</emphasis>. The second parameter of + the <emphasis role="italic">setImageList</emphasis> method specifies the size of the icons by invoking + the Image class' <emphasis role="italic">toID</emphasis> method with the parameter + <emphasis role="italic">LVSIL_NORMAL</emphasis> which is the flag for the icon view as opposed to + the list, report, and small icon views. The Image class is used to work with and manipulate images. + The variable <emphasis role="italic">self~lv</emphasis> is the list view proxy, + <emphasis role="italic">lv</emphasis> + being an attribute of the <computeroutput>OrderMgrBaseView</computeroutput> superclass. + The icons having been set, the records are then added using the ListView's + <emphasis role="italic">addRow</emphasis> method. The first parameter is the index of the list + item - if omitted, the record is added after the last. The second parameter is the index of the icon to + be used with this record, and the last parameter is the label for the list item - the string + "Customer List" in the case of the first item added. + </para> </listitem> </orderedlist> @@ -717,17 +714,155 @@ <section id="chap06-listview-report"><title>The Report View</title> <!-- Section 6.3.2 --> <!-- - 6.3.2. The Report View - - Looking at the two list views, almost begs for a superclass. - - how do different fonts for the listView items + - how do different fonts for the listView items + Answer: in initDialog: + font = self~createFontEx("Ariel", 12) + lvCustomers~setFont(font) + - Explain the surfacing of an instance in the listview dialogs - check the showModel method. --> - <para>Three of the icons in the Order Management dialog surface a list when double-clicked - Customers, Products, and Orders. - These three components are technically very similar - to the extent that a "list superclass" could perhaps be created. - For the meantime, however, this is not done, and each list is quite separate. However, their similarity means that discussing one - list - the Customer List - effectively addresses all. + <para>Three of the icons in the Order Management dialog surface a list when double-clicked - the Customer List, + Product List, and Order List. These three components are technically very similar - so that a + "list superclass" could perhaps be useful. However, in Exercise 6 this is not done, and each + list is quite separate. Nevertheless, their similarity means that discussing one list - the Customer List + - effectively addresses all three. </para> - <para></para> + <para>A list view with the "Report View" style provides for a variable number of columns, each item + appearing on a separate line with information arranged in columns. Each line may have a small icon at + the left of each line. Note that the fields in a ListView must be defined in code, since a Windows + resource file does not support the definition of columns within the list view.</para> + <para> + The following code fragment from the <computeroutput>CustomerListView</computeroutput> class + shows how the List View (without small icons) is defined: + <programlisting> + <![CDATA[ + ::METHOD initDialog + expose menuBar lvCustomers btnShowCustomer + ... + lvCustomers = self~newListView("IDC_CUSTLIST_LIST"); + lvCustomers~addExtendedStyle(GRIDLINES FULLROWSELECT) + lvCustomers~insertColumnPX(0,"Number",60,"LEFT") + lvCustomers~insertColumnPX(1,"Name",220,"LEFT") + lvCustomers~insertColumnPX(2,"Zip",80,"LEFT") + self~connectListViewEvent("IDC_CUSTLIST_LIST","CLICK",itemSelected) -- Single click + self~connectListViewEvent("IDC_CUSTLIST_LIST","ACTIVATE",openItem) -- Double-click + self~connectButtonEvent("IDC_CUSTLIST_SHOWCUST","CLICKED",showCustomer) + self~loadList + ]]> + </programlisting> + First, a proxy, <emphasis role="italic">lvCustomers</emphasis>, is created. Then, + in the second statement, the list view + is formatted using "extended styles" (of which there are around twenty). Extended styles are + defined by Microsoft, and can only be added after the underlying Windows control has been created + - that is, (normally) in + the <emphasis role="italic">initDialog</emphasis> method. In the above code, only two extended + styles are applied: GRIDLINES and FULLROWSELECT. Both apply only to the Report View. The former + draws gridlines around all items; the latter defines that, + when a row is selected by the user, the whole row is highlighted rather than just + the first column. Then there are three <emphasis role="italic">~insertColumnPX</emphasis> statements, + each adding a + column to the list view - "Number", "Name", and "Zip". Following these are two + <emphasis role="italic">~connectListViewEvent</emphasis> statements that define event handler methods + for single click and a double-click - <emphasis role="italic">itemSelected</emphasis> and + <emphasis role="italic">openItem</emphasis>. The latter merely invokes the + <emphasis role="italic">showCustomer</emphasis> method, as does the second-to-last statement + <emphasis role="italic">~connectButtonEvent</emphasis> which defines the event handler method for the + pushbutton. + </para> + <para> + The last statement in the above invokes the <emphasis role="italic">loadList</emphasis> method, which + loads the list view with data, as follows: + <programlisting> + <![CDATA[ + ::METHOD loadList + expose lvCustomers + lvCustomers~addRow( , ,"CU001", "ABC Inc.", "TX 20152") + lvCustomers~addRow( , ,"CU002", "Frith Inc.", "CA 30543") + lvCustomers~addRow( , ,"CU003", "LMN & Co", "NY 47290-1201") + lvCustomers~addRow( , ,"CU005", "EJ Smith", "NJ 12345") + lvCustomers~addRow( , ,"CU010", "Red-On Inc.","AZ 12345") + lvCustomers~addRow( , ,"AB15784", "Joe Bloggs & Co Ltd","LB7 4EJ") + lvCustomers~setColumnWidth(1) + ]]> + </programlisting> + The <emphasis role="italic">~addRow</emphasis> method adds a row of data into the list view. + As can be seen, the data in the list is hard-coded. This will be fixed in Exercise 7. The first parameter + is the 0-based index of the item, and defaults to the index of the last item added plus 1 (if no items + already in the list view, this defaults to 0). Note however that the last item appears first not last. + This is because the *.rc file has the style <computeroutput>LVS_SORTASCENDING</computeroutput>. + The second parameter is the index (in an ImageList) of the iter's icon should that be required. + Finally, the last statement sets the width of the second column to that of the longest text entry. + Note that loading the list view with data could have been done in the + <emphasis role="italic">initDialog</emphasis> method. However, the separation of concerns principle + points strongly to separating the formatting of the list view from loading data into the list view. + </para> + <para>Surfacing a Customer from the Customer List is done in one of two ways: either double click on an item, + or select the item and then press the "Show Customer" button. Both invoke the + <emphasis role="italic">showCustomer</emphasis> method. These two approaches are implemented by the + following code (error-handling code omitted): + <programlisting> + <![CDATA[ + -- 1. Double-Click: + + ::METHOD initDialog + ... + self~connectListViewEvent("IDC_CUSTLIST_LIST","ACTIVATE",openItem) -- Double-click + ... + + ::METHOD openItem UNGUARDED + self~showCustomer + + + -- 2. Select (single click) then press button: + + ::METHOD initDialog + ... + self~connectListViewEvent("IDC_CUSTLIST_LIST","CLICK",itemSelected) -- Single click + self~connectButtonEvent("IDC_CUSTLIST_SHOWCUST","CLICKED",showCustomer) + ... + + ::METHOD itemSelected UNGUARDED + use arg id, itemIndex, columnIndex, keyState + if itemIndex > -1 then self~enableControl("IDC_CUSTLIST_SHOWCUST") + else self~disableControl("IDC_CUSTLIST_SHOWCUST") + ]]> + </programlisting> + In the first approach, If the user double-clicks on a row, and the row is empty, the second + click of the double-click is ignored, else the double-click method (<emphasis role="italic">openItem</emphasis> + is invoked. This is turn invokes <emphasis role="italic">showCustomer</emphasis>. + In the second approach, the <emphasis role="italic">itemSelected</emphasis> method is fired when + the user clicks on a row in the ListView. If the user clicks on an empty row, then + <emphasis role="italic">itemIndex</emphasis> is set to -1, else it is set to the 0-based row number. + As can be seen, both approaches invoke the <emphasis role="italic">showCustomer</emphasis> method, which + is as follows (where <emphasis role="italic">lvCustomers</emphasis> is + the proxy for the List View control): + <programlisting> + <![CDATA[ + ::METHOD showCustomer UNGUARDED + expose lvCustomers rootDlg + item = lvCustomers~selected + info=.Directory~new + lvCustomers~getItemInfo(item, info) + .local~my.idCustomerData = .CustomerData~new -- create CustomerData instance + .local~my.idCustomerModel = .CustomerModel~new -- create CustomerModel instance + .local~my.idCustomerData~activate + .local~my.idCustomerModel~activate + .CustomerView~newInstance(rootDlg,"CU003") + self~disableControl("IDC_CUSTLIST_SHOWCUST") + ]]> + </programlisting> + First, the relevant row (<emphasis role="italic">item</emphasis>)is found using the + <emphasis role="italic">~selected</emphasis> method of the List View. Then a directory + is created, and the data from the selected row is placed into the directory by the List View's + <emphasis role="italic">getItemInfo</emphasis> method. Thirdly, the Customer Data and Model objects + are instantiated, and then the CustomerView is instantiated + (<computeroutput>CustomerView</computeroutput> depends on <computeroutput>CustomerModel</computeroutput> + being available). As can be seen, in this version of <computeroutput>CustomerListView</computeroutput> + the data from the ListView is ignored, and the same Customer is surfaced regardless. This is also true + for the other List Views. In Exercise 7 this will be fixed so that instantiation of the Model and Data + objects will be handled elsewhere. + </para> + </section> <!-- End of section 6.3.2 --> </section> <!-- End of section 6.3 --> @@ -747,47 +882,114 @@ of these three samples. </para> <para> - The re-sizing function is provided by two ooDialog classes: <computeroutput>dlgAreaU</computeroutput> - and <computeroutput>dlgArea</computeroutput> (see ooDialog Reference sections 10.14 and 10.15). + The re-sizing function is provided by two ooDialog-provided classes: <computeroutput>dlgAreaU</computeroutput> + and <computeroutput>dlgArea</computeroutput>. An important constraint is that, because <computeroutput>dlgAreaU</computeroutput> parses the source code of the <emphasis role="italic">defineDialog</emphasis> method in order to handle re-sizing, it will only work with <computeroutput>UserDialog</computeroutput>, where the dialog template is created through explicit control creation statements. In addition, since the source code is required at run-time, it will not work if the source code is tokenized using <emphasis role="italic">rexxc</emphasis>. </para> -<para> - Essentially, the dialog is first split into a number of areas - two areas for the - OrderManagement dialog. ears for . dilaog defines the A re-sizeable dialog - an excellent sample dialog - - </para> </section> <!-- End of section 6.4 --> - -<section id="chap06-icons"><title id="icons.title">Creating and Using Icons</title> <!-- Section 6.5 --> +<section id="chap06-icons"><title id="icons.title">Creating Icons</title> <!-- Section 6.5 --> <!-- 6.5 Creating and Using Icons - Icons - making them, getting 'em into the program. - - (1) Does the icon have to be a certain size, or will it get automatically shrunk? - (2) If it has to be a certain size, what's the size, and are there any restrictions as to the palette (I'm no expert, but using GIMP I'm given the option of saving as 16-bit, 24-bit or 32-bit color (or I think it's color!)). - (3) In the ~execute statement, I need to provide an ID. Does this mean I must have a *.rc file? Or can I invent an ID programmatically somehow - perhaps along the same lines as creating an ImageList? - (4) I want to assign my own icon as the dialog icon (that is, the icon at the extreme top left of a dialog). This is done (I understand) in the ~execute(..., <icon_ID> ) method (ooDialog Reference section 3.10.3). + (3) In the ~execute statement, I need to provide an ID. Does this mean I must have a *.rc file? + Or can I invent an ID programmatically somehow - perhaps along the same lines as creating an ImageList? + (4) I want to assign my own icon as the dialog icon (that is, the icon at the extreme top left of a dialog). + This is done (I understand) in the ~execute(..., <icon_ID> ) method (ooDialog Reference section 3.10.3). --> - <para>- Icons - making them, getting 'em into the program. - GIMP (GNU Image Manipulation Program) from - http://www.gimp.org -</para> + <para>Various questions arise when creating icons for the first time - especially since the + whole area of images in Windows is not, on first glance, simple. + This section lists some of the main points about creating icons.</para> + <para>First, it's important to establish whether what's required is an icon (file type .ico) + or a bitmap (file type *.bmp). The "icons" in the Order Management dialog are actually bitmaps. But a + "dialog icon" (the icon displayed in the left hand corner of the title bar of a dialog) is an icon, + not a bitmap. + A number of tools are available for creating and editing images, icons, bitmaps etc., + some of them providing conversion and re-sizing capabilities. One such is GIMP (GNU Image Manipulation + Program), a freely distributed piece of software, from http://www.gimp.org. + <indexterm><primary>Bitmap Editor</primary></indexterm> + <indexterm><primary>Icon editor</primary></indexterm> + </para> + <para>Second, the size of a dialog icon is variable. That is, an icon larger than the space available + will be shrunk to fit. The dialog icons in Exercise 6 are all 64x64 in size, and are automatically + shrunk to fit. For resource dialogs, the dialog icon is specified in the resource file, + and its ID in the resource file is specified in the <emphasis role="italic">self~execute(...)</emphasis> + method. For UserDialog dialogs, the dialog icon is loaded by the + <emphasis role="italic">addIconResource</emphasis> method. The two arguments to this method are a + resource ID and the file name of the icon, for example: + <emphasis role="italic">dlg~addIconResource(105,"MyPicture.ico")</emphasis>. The resource ID is then + specified in the <emphasis role="italic">dlg~execute("SHOWTOP, 105)</emphasis> statement. + </para> + <para>Finally, the "icons" in the Order Management dialog are bitmaps of size 64x64. These are not shrunk; + a smaller icon will look smaller. These bitmaps are loaded into the ListView programmatically. + (As mentioned above, the ListView control is created in the <computeroutput>OrderMgrBaseView</computeroutput> + class and is stored as an attribute of that class; its name is <emphasis role="italic">lv</emphasis>. + The cod that loads the bitmaps into the ListView is as follows. + <programlisting> + <![CDATA[ + ::METHOD createIconList PRIVATE + -- called from init. + expose iconList + ... + imgProdList = .Image~getImage("product\res\ProdList.bmp") + ... + + iconList = .ImageList~create(.Size~new(64, 64), .Image~toID(ILC_COLOR4), 4, 0) + + iconList~add(imgCustList) -- item 0 in iconList (item 1 in records) + iconList~add(imgProdList) -- item 1 in iconList (item 2 in records) + iconList~add(imgOrderList) -- item 2 in iconList (item 3 in records) + iconList~add(imgOrderForm) -- item 3 in iconList (item 4 in records) + imgCustList~release + imgProdList~release + imgOrderList~release + imgOrderForm~release + return + + ::METHOD initRecords PRIVATE + -- Called from init - This method simulates getting the "data" for the OrderMgr view. + expose records + records = .array~new() + ... + rec = .directory~new + rec~ID = "ProductList" + rec~name = "Product List" + records[2] = rec + ... + return records + + + ::METHOD initDialog + expose records iconList + self~initDialog:super + -- Add the Image List to the ListView: + self~lv~setImageList(iconList, .Image~toID(LVSIL_NORMAL)) + -- Add icons (i.e. records) to the ListView: + do i=1 to records~items + self~lv~addRow(, i-1, records[i]~name) + end + ]]> + </programlisting> + First, each bitmap is loaded + from disk into an instance of the <computeroutput>.Image</computeroutput> class using the + <emphasis role="italic">getImage</emphasis> method. . Then an instance of the + <computeroutput>ImageList</computeroutput> class is created, with the . each instance is Imagethe icon data is loaded + into an ImageList, 'iconList' which is an 'ImageList' as + -- required by the ListView control. + </para> </section> <!-- End of section 6.5 --> <section id="chap06-utildlgs"><title id="utildlgs.title">Utility Dialogs</title> <!-- Section 6.6 --> <indexterm><primary>Password dialog</primary></indexterm> <indexterm><primary>Utility routine</primary><secondary>PasswordBox</secondary></indexterm> - <!-- - 6.6 Utility Dialogs - <- ??? <What's this??> (Is this the layer - process-entity-utility? Or just useful "canned" dialogs?) - - Mention password on startup to illustrate ooDialog use in otherwise non-ooDialog rexx programs. - "startup enterPW" - password is "Password". - --> <para>A subject not yet mentioned is the use of ooDialog utility classes and routines in non-ooDialog ooRexx programs. - These are documented in Chapter 9 of the ooDialog Reference. The routines are very simple, and are often one-liners. - As an example, the Exercise06 startup program - provides for entry of a password using the (one-line) PasswordBox routine. + These are documented in Chapter 25 of the ooDialog Reference. The routines are very simple, and are often one-liners. + As an example, the Exercise 6 startup program + provides for entry of a password using the (one-line) <computeroutput>PasswordBox</computeroutput> routine. Invoking <emphasis role="italic">startup enterPW</emphasis> produces a password box that will accept the password "Password". If you get the password wrong, the startup routine will silently end. The code is as follows: <programlisting> @@ -801,8 +1003,8 @@ ::REQUIRES "OrderMgmt\OrderMgmtView.rex" ]]> </programlisting> - - </para> + </para> </section> <!-- End of section 6.6 --> </chapter> + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |