Managing Window Instances

About this chapter

This chapter describes how to manage several instances of the same window.

About window instances

When you build an application, you may want to display several windows that are identical in structure but have different data values.

For example, you may have a w_employee window and want to display information for two or more employees at the same time by opening multiple copies (instances) of the w_employee window.

You can do that, but you need to understand how PowerBuilder stores window definitions.

How PowerBuilder stores window definitions

When you save a window, PowerBuilder actually generates two entities in the library:

  • A new datatype

    The name of the datatype is the same as the name of the window.

    For example, when you save a window named w_employee, PowerBuilder internally creates a datatype named w_employee.

  • A new global variable of the new datatype

    The name of the global variable is the same as the name of the window.

    For example, when you save the w_employee window, you are also implicitly defining a global variable named w_employee of type w_employee.

    It is as if you had made the following declaration:

    Figure: Variable declaration

By duplicating the name of the datatype and variable, PowerBuilder allows new users to access windows easily through their variables while ignoring the concept of datatype.

What happens when you open a window

To open a window, you use the Open function, such as:

Open(w_employee)

This actually creates an instance of the datatype w_employee and assigns it a reference to the global variable, also named w_employee.

As you have probably noticed, when you open a window that is already open, PowerBuilder simply activates the existing window; it does not open a new window. For example, consider this script for a CommandButton's Clicked event:

Open(w_employee)

No matter how many times this button is clicked, there is still only one window w_employee. It is pointed to by the global variable w_employee.

To open multiple instances of a window, you declare variables of the window's type.

Declaring instances of windows

Because a window is actually a datatype, you can declare variables of that datatype, just as you can declare integers, strings, and so on. You can then refer to those variables in code.

For example:

w_employee mywin

declares a variable named mywin of type w_employee.

Limitation of using variables

When you declare a window instance, you cannot reference it from another window. For example, if there are three windows open, you cannot explicitly refer to the first one from the second or third. There is no global handle for windows opened using reference variables. To maintain references to window instances using a script, see Using window arrays.

Opening an instance

To open a window instance, you refer to the window variable in the Open function:

w_employee mywin
Open(mywin)

Here the Open function determines that the datatype of the variable mywin is w_employee. It then creates an instance of w_employee and assigns a reference to the mywin variable.

If you code the above script for the Clicked event for a CommandButton, each time the button is clicked, a new instance of w_employee is created. In other words, a new window is opened each time the button is clicked.

By creating variables whose datatype is the name of a window, you can open multiple instances of a window. This is easy and straightforward. PowerBuilder manages the windows for you for example, freeing memory when you close the windows.

Closing an instance

A common way to close the instances of a window is to put a CommandButton in the window with this script for the Clicked event:

Close(Parent)

This script closes the parent of the button (the window in which the button displays). Continuing the example above, if you put a CommandButton in w_employee, the script closes the current instance of w_employee. If you click the CommandButton in the mywin instance of w_employee, mywin closes.

Using window arrays

To create an array of windows, declare an array of the datatype of the window. For example, the following statement declares an array named myarray, which contains five instances of the window w_employee:

w_employee myarray[5]

You can also create unbounded arrays of windows if the number of windows to be opened is not known at compile time.

Opening an instance using an array

To open an instance of a window in an array, use the Open function and pass it the array index. Continuing the example above, the following statements open the first and second instances of the window w_employee:

Open(myarray[1])         // Opens the first instance
                         // of the window w_employee.
Open(myarray[2])         // Opens the second instance.

Moving first instance opened

The statements in this example open the second instance of the window at the same screen location as the first instance. Therefore, you should call the Move function in the script to relocate the first instance before the second Open function call.

Manipulating arrays

Using arrays of windows, you can manipulate particular instances by using the array index. For example, the following statement hides the second window in the array:

myarray[2].Hide()

You can also reference controls in windows by using the array index, such as:

myarray[2].st_count.text = "2"

Opening many windows

When you open or close a large number of instances of a window, you may want to use a FOR...NEXT control structure in the main window to open or close the instances. For example:

w_employee myarray[5]
for i = 1 to 5
   Open(myarray[i])
next

Creating mixed arrays

In the previous example, all windows in the array are the same type. You can also create arrays of mixed type. Before you can understand this technique, you need to know one more thing about window inheritance: all windows you define are actually descendants of the built-in datatype window.

Suppose you have a window w_employee that is defined from scratch, and w_customer that inherits from w_employee. The complete inheritance hierarchy is the following:

Figure: Window inheritance hierarchy

The system-defined object named window is the ancestor of all windows you define in PowerBuilder. The built-in object named window defines properties that are used in all windows (such as X, Y, and Title).

If you declare a variable of type window, you can reference any type of window in the application. This is because all user-defined windows are a kind of window.

The following code creates an array of three windows. The array is named newarray. The array can reference any type of window, because all user-defined windows are derived from the window datatype:

window newarray[3]
string win[3]
int iwin[1] = "w_employee"
win[2] = "w_customer"
win[3] = "w_sales"

for i = 1 to 3
   Open(newarray[i], win[i])
next

The code uses this form of the Open function:

Open ( windowVariable, windowType )

where windowVariable is a variable of type window (or a descendant of window) and windowType is a string that specifies the type of window.

The preceding code opens three windows: an instance of w_employee, an instance of w_customer, and an instance of w_sales.

Using arrays versus reference variables

The following table shows when you use reference variables and when you use arrays to manipulate window instances.

Item

Advantages

Disadvantages

Arrays

You can refer to particular instances.

Arrays are more difficult to use. For example, if the user closes the second window in an array, then wants to open a new window, your code must determine whether to add a window to the end of the array (thereby using more memory than needed) or find an empty slot in the existing array for the new window.

Reference variables

Easy to use PowerBuilder manages them automatically.

You cannot manipulate particular instances of windows created using reference variables.


Suppose you use w_employee to provide or modify data for individual employees. You may want to prevent a second instance of w_employee opening for the same employee, or to determine for which employees an instance of w_employee is open. To do this kind of management, you must use an array. If you do not need to manage specific window instances, use reference variables instead to take advantage of their ease of use.

Referencing entities in descendants

When you declare a variable whose datatype is a kind of object, such as a window, you can use the variable to reference any entity defined in the object, but not in one of its descendants. Consider the following code:

w_customer mycust

Open(mycust)
// The following statement is legal if
// w_customer window has a st_name control.
mycust.st_name.text = "Joe"

mycust is declared as a variable of type w_customer (mycust is a w_customer window). If w_customer contains a StaticText control named st_name, then the last statement shown above is legal.

However, consider the following case:

window newwin
string winname = "w_customer"
Open(newwin, winname)
// Illegal because objects of type Window
// do not have a StaticText control st_name
newwin.st_name.text = "Joe"

Here, newwin is defined as a variable of type window. PowerBuilder rejects the above code because the compiler uses what is called strong type checking: the PowerBuilder compiler does not allow you to reference any entity for an object that is not explicitly part of the variable's compile-time datatype.

Because objects of type window do not contain a st_name control, the statement is not allowed. You would need to do one of the following:

  • Change the declaration of newwin to be a w_customer (or an ancestor window that also contains a st_name control), such as:

    w_customer newwin
    string winname = "w_customer"
    
    Open(newwin, winname)
    // Legal now
    newwin.st_name.text = "Joe"
  • Define another variable, of type w_customer, and assign it to newwin, such as:

    window newwin
    w_customer custwin
    string winname = "w_customer"
    
    Open(newwin, winname)
    custwin = newwin
    // Legal now
    custwin.st_name.text = "Joe"