The Curl® data access API provides
RecordSet and related classes to organize data into fields and
records. The GUI toolkit provides specialized controls to aid in
displaying and manipulating
RecordSet data. The abstract
base class
RecordSetDisplay defines much of the basic
functionality for displaying a
RecordSet. Both
RecordGrid, which provides a tabular display, and
RecordForm, which provides a form-type display, inherit
RecordSetDisplay. The following list discusses some of the most
important functions defined by
RecordSetDisplay.
The following figure shows the major components of
the
RecordGrid display.
The rows and columns correspond to records and fields in the
source
RecordSet. You can create columns explicitly with
RecordGridColumn, which enables you to set properties
that control column appearance and function. Columns can also be
created automatically and you only need to add a column yourself
it you want to customize the column.
RecordGrid supplies substantial functionality by default.
Use the next example to explore the capabilities listed here.
- Automatically generated columns. RecordGrid
automatically generates a column for each RecordField
in the RecordSet, unless the property RecordGrid.automatic-columns? is false. Columns have
column headings derived from data in the RecordSet. and provide appropriate formatting for the data in
the column. In this example, text fields are left aligned and
the integer field is right aligned.
- Move columns. Left-click and drag in the column
header of the column you wish to move. The cursor shape
changes to a pointing finger, and a dark vertical line
appears. The column you are dragging drops to the left of this
line when you release the mouse button. This behavior is
controlled by the option RecordGridOptions.column-movable?.
- Resize columns. Position the cursor over the line at the
right edge of the column you want to resize. The cursor shape
changes to a double-headed arrow. Left-click and drag to
resize. This behavior is controlled by
the option RecordGridOptions.column-resizable?.
- Sort records. Click on the column heading to sort by
column value. A small arrow appears that indicates the
direction of the sort. You can use the property RecordSetDisplay.sort stores the current RecordSort.
- Indicate the current record. RecordGrid
provides a column at the left of the grid, which contains an
arrow that indicates the current record. The property RecordGrid.display-record-selectors? determines whether the
grid includes record selectors.
- Focus on a cell. Click on a grid cell to focus on it. A
gray border around the field indicates that the cell has
focus. The property RecordGridOptions.cells-take-focus? controls whether a grid
cell can take focus
- Traverse the cells. From a cell with focus, tab and shift + tab traverse forward and
backward through the grid cells by row. Traversing to a cell
selects the cell contents.
- Edit data. You can edit the data displayed in a
RecordGrid cell. The property and RecordGridOptions.editable? controls whether you can edit
data in the cell. How you edit the cell contents depends on
how the data is presented.
- StandardStringCell Many types of data are
presented as strings in the cells automatically
generated by RecordGrid. In the example, the
date and time data in the columns Date and
Time are presented as strings. Edit strings by
typing in the cell. If the entire cell content is
selected, as it is if you traversed to the cell with
tab, click in the cell or press
f2 to edit the string.
- StandardDropdownCell If the user must select
from a defined set of values, the data are presented as
a drop-down list. In the example, scroll right to the
column Rank. This RecordData
presented by this column is an enumerated type. Click
on a cell in this column to activate the dropdown
control that lets you choose from possible values for
the enum.
- StandardCheckButtonCell If the RecordData presented by a column is a boolean type,
RecordGrid presents it as a check box. This
is illustrated in the example by the column Notified?.
Edits you make in the RecordGrid do not change data
in the underlying RecordSet until you commit the
changes with the Commit Changes command on the RecordGrid context menu. You can also Revert Changes. - Select one or more records. Left-click in the record
selector area to select a record. Use ctrl+left-click to add a single record to the selection, and
shift+left-click to select records in a
range. RecordGrid.record-selection-enabled? controls
whether you can select records. RecordGrid.multiple-selection-enabled? controls whether you can
select more than one record.
- Scroll bars. RecordGrid provides scroll bars
if the data display is larger than the viewable area of the
grid. Try executing the following example with different
values for width and height, and note the
effect on the scroll bars.
- Navigation panel. The navigation panel at the bottom of
the display enables you to move to the first or last record,
or up or down by one record. It also indicates the total
number of records currently displayed, and position of the
current record in the display. RecordGrid.display-navigation-panel? whether the navigation
panel is included in the grid.
In addition, right-click on a grid cell brings up a context menu
that offers the following choices:
- Copy copies the selected area of the record grid to the
clipboard, as strings. You can paste the text representation
of data in a RecordGrid from the clipboard to another
application.
- Paste pastes the content of the clipboard to the
selected area of the record grid. You can copy text from
another application and paste it into a RecordGrid.
- Freeze/Unfreeze Frame/Column/Row freezes an area of the
display so that it does not scroll; you can scroll the
remaining display area with respect to the frozen
area. Applying Freeze Column freezes all columns to the
left of the current column. Applying Freeze Row freezes
all rows above the current row. Applying Freeze Frame
freezes all rows and columns above and to the left of the
current cell. Unfreeze releases the frozen area.
- Sort Ascending and Sort Descending sort
records on the values in the column that contains the grid
cell.
- Add Filter opens a submenu with the following
choices:
- (value of cell) only displays only those
records having the same value in this column as the
selected cell.
- (value of cell) and above displays only those
records having values in this column greater than or
equal to the selected cell.
- (value of cell) and below displays only those
records having values in this column less than or
equal to the selected cell.
- not (value of cell) displays only those records
that do not have the same value in this column as the
selected cell.
If you apply a filter on another column, the effect is
cumulative. In the example, try applying the
only
filter on "Smith", then on "Jane." The display shows only
the record for Jane Smith.
RecordSetDisplay.filter stores the current
RecordFilter.
- Remove Filters removes all filters currently in effect.
- Commit Changes makes changes you have made to the
data permanent in the source RecordSet, and discards
previous values.
- Revert Changes reverts any changes made since the
last commit to their previous values.
The
Add Filter menu is available only when the cursor is
positioned over a cell in the
RecordGrid. The commands
Sort Ascending and
Sort Descending are available
when the cursor is positioned over a column. You can access the
commands
Remove Filters,
Commit Changes, and
Revert Changes when the cursor is anywhere in the
RecordGrid display.
| Example:
Default RecordGrid Behavior |
 |
{include "../../default/support/data-long.scurl"}
{RecordGrid
record-source = records,
height = 10cm,
width = 13cm
}
| |
RecordGrid provides a number of options that enable you
to modify the appearance of the grid display. These options
include:
The following example changes the appearance of the
RecordGrid display by setting several of these properties to
values other then their default.
| Example:
Modifying RecordGrid Appearance |
 |
{let people:RecordSet =
{RecordSet
{RecordFields
{RecordField "First", domain = String},
{RecordField "Last", domain = String},
{RecordField "Age", domain = int}
},
{RecordData First = "John", Last = "Smith", Age = 25},
{RecordData First = "Jane", Last = "Smith", Age = 29},
{RecordData First = "Jane", Last = "Jones", Age = 28}
}
}
{value
{RecordGrid
record-source = people,
height = 3cm,
display-column-headers? = false,
display-filler-column? = true,
alternate-row-background = "#cceecc",
grid-line-color = "#ccccff",
horizontal-grid-line-width = 2px,
vertical-grid-line-width = 4px
}
}
| |
The property
RecordGrid.row-background-spec lets you
supply a procedure that calculates the background color of each
row. The procedure is passed the record grid, the record to be
displayed, and the index of the record in
RecordGrid.records. The procedure calculates the background based
on this information. Remember that the procedure may be called
frequently, so lengthy computation in this procedure could have an
impact on performance.
The following example calculates the row background based on data
in the supplied record. The background is silver for records where
the value of the field Notified? is true. In this
case, the background color is independent of the record's position
in the grid.
| Example:
Data-driven row background |
 |
{include "../../default/support/data-long.scurl"}
{define-proc public {notified rg:RecordGrid, r:Record, i:int}:#Background
{if {r.compare-field "Notified?", true} == 0 then
{return {Background.from-string "silver"}}
else
{return null}
}
}
{RecordGrid
record-source = records,
height = 10cm,
width = 13cm,
row-background-spec = notified
}
| |
The next example uses the record index to return a colored
background for every fifth and tenth record displayed in the
grid. The background depends entirely on position, and is
independent of the data in the record.
| Example:
Position-based row background |
 |
{include "../../default/support/data-long.scurl"}
{define-proc public {notified rg:RecordGrid, r:Record, i:int}:#Background
{if ((i + 1) mod 10) == 0 then
{return {Background.from-string "#ccccff"}}
elseif ((i + 1) mod 5) == 0 then
{return {Background.from-string "#eeeeff"}}
else
{return null}
}
}
{RecordGrid
record-source = records,
height = 10cm,
width = 13cm,
row-background-spec = notified
}
| |
The custom header in the following example sets
control-actuator-color, which controls the color of the arrow in
the header cell that indicates the current sort direction.
This example also sets the
key-spec
property on the record grid to the unique field
id. Setting
key-spec enables the record grid to maintain the current
record through bulk changes, such as sorting the records. Select a
record, then sort the records by clicking on one of the column
headers. Note that the selection indicator at the left of the grid
retains its association with the record after you have sorted the
records. Try commenting this line and executing the example.
Note that the selection indicator goes to the first record
displayed in the grid when you perform a search.
| Example:
Customizing the header row |
 |
{let staff:RecordSet =
{evaluate
{url "../../default/support/data.scurl"}
}
}
{let gradient-header:RecordGridRowOptions =
{RecordGridRowOptions
background =
{LinearGradientFillPattern
{Fraction2d 0, 1},
{Fraction2d 0, 0},
{Spectrum.from-endpoints
{FillPattern.get-silver},
{FillPattern.get-white}
}
},
valign = "origin",
halign = "left",
control-actuator-color = "gray",
color = "gray",
font-size = 14pt,
font-family = "serif"
}
}
{let rg:RecordGrid =
{RecordGrid height = 10cm,
record-source = staff,
column-movable?= false,
header-options = gradient-header,
key-spec = "id",
width = 16cm
}
}
{value rg}
| |
The following example creates a custom column to display data from
two fields in the underlying data in a single column. It sets
automatic-columns? to
false to suppress automatic
column generation, and sets
RecordGrid.format-spec to a
procedure that returns a single string containing both first and
last name from the data set. The example must also explicitly
create a column for age.
| Example:
Displaying Two Fields in a Single Column |
 |
{let people:RecordSet =
{RecordSet
{RecordFields
{RecordField
"First", caption = "First Name", domain = String
},
{RecordField
"Last", caption = "Last Name", domain = String
},
{RecordField "Age", domain = int}
},
{RecordData First = "John", Last = "Smith", Age = 25},
{RecordData First = "Jane", Last = "Smith", Age = 29},
{RecordData First = "Jane", Last = "Jones", Age = 28}
}
}
{let rg:RecordGrid =
{RecordGrid
record-source = people,
height = 3cm,
automatic-columns? = false,
{RecordGridColumn
"First",
editable? = false,
format-spec =
{proc {data:any, r:Record}:String
{return r["First"] & " "&
r["Last"]}
},
header-spec = "Full Name"
},
{RecordGridColumn "Age"}
}
}
{let rg-real:RecordGrid =
{RecordGrid
record-source = people,
height = 3cm
}
}
{value rg}
| |
It also sets the background of alternating columns. Note also that
the
RecordGrid sets the option
column-movable? to
false, so you cannot reorder columns by dragging.
| Example:
Creating a custom column header |
 |
{let staff:RecordSet =
{evaluate
{url "../../default/support/data.scurl"}
}
}
{define-proc public {make-header rgc:RecordGridColumn}:Graphic
{return
{TextFlowBox
font-weight = "bold",
font-size = 12pt,
color = "green",
rgc.field.caption
}
}
}
{let rg:RecordGrid =
{RecordGrid height = 10cm,
record-source = staff,
width = 16cm,
column-movable? = false,
header-spec = make-header
}
}
{for i:int = 0 to rg.columns.size - 1 do
{if (i mod 2 == 0) then
set rg.columns[i].background = "#cceecc"
}
}
{value rg}
| |
You can use
RecordGridColumnGroup to group columns in the
RecordGrid display. You supply a caption for the group,
and list the columns in the order you want them to appear
initially in the group. The option
RecordGridOptions.enclose-header-label? determines whether
the display should include a visual separator between the group
caption and the column caption.
You can drag-and-drop columns in a group, but you cannot drag a
column into or out of a group. You also cannot drag-and-drop the
groups themselves.
Groups affect the action of the freeze frame
operation. Freeze frame can take effect only at group
boundaries. If you apply freeze frame anywhere in a group
the freeze boundary is at the right edge of the group.
| Example:
Grouping RecordGrid Columns |
 |
{RecordGrid
record-source =
{evaluate
{url "../../default/support/data.scurl"}
},
height = 10cm,
width = 13cm,
{RecordGridColumn "id"},
{RecordGridColumnGroup
"Name",
|| remove comment to remove header separator
||-- enclose-header-label? = false,
{RecordGridColumn "First"},
{RecordGridColumn "Last"}
},
{RecordGridColumnGroup
"Address",
|| remove comment to remove header separator
||-- enclose-header-label? = false,
{RecordGridColumn "City"},
{RecordGridColumn "State"}
}
}
| |
Options that modify the way
RecordGrid interacts
with end users include:
The following example sets several of these options to values
other than their default. The result is a grid that is very
unresponsive to user gestures. Try executing the example with
various combinations of these property settings and observe how
the grid behaves.
| Example:
Modifying UI Interaction |
 |
{let people:RecordSet =
{RecordSet
{RecordFields
{RecordField "First", domain = String},
{RecordField "Last", domain = String},
{RecordField "Age", domain = int}
},
{RecordData First = "John", Last = "Smith", Age = 25},
{RecordData First = "Jane", Last = "Smith", Age = 29},
{RecordData First = "Jane", Last = "Jones", Age = 28}
}
}
{value
{RecordGrid
cells-take-focus? = false,
column-movable? = false,
column-resizable? = false,
editable? = false,
display-record-selectors? = false,
display-navigation-panel? = false,
record-source = people,
height = 3cm
}
}
| |
The option
RecordGridOptions.parse-spec enables you to
control how
RecordGrid converts text entered by an end
user into a value in the
RecordSet. The following example
lets the user input a simple domain name. The
parse-spec
adds
http://www. to form a complete url.
| Example:
Using parse-spec |
 |
{let urls:RecordSet =
{RecordSet
{RecordFields
{RecordField
"Company", domain = String
},
{RecordField
"URL", domain = String
}
},
{RecordData Company = "Curl", URL = "http://www.curl.com"},
{RecordData Company = "Google", URL = "http://www.google.com"},
{RecordData Company = "EBay", URL = "http://www.ebay.com"}
}
}
{let rg:RecordGrid =
{RecordGrid
record-source = urls,
height = 3cm,
automatic-columns? = false,
{RecordGridColumn "Company"},
{RecordGridColumn "URL",
width = {make-elastic},
parse-spec =
{proc {v:String, r:Record}:any
let nv:String =
{if {v.prefix? "http://www."} then v
else "http://www." & v
}
{return nv}
}
}
}
}
{value
{VBox
rg,
{HBox
{CommandButton
width = {make-elastic}, label = "append record",
{on Action do
{urls.append {RecordData}}
}
},
{CommandButton
width = {make-elastic}, label = "commit records",
bound-command = {rg.get-command "commit"}
},
{CommandButton
width = {make-elastic}, label = "revert records",
bound-command = {rg.get-command "revert"}
}
}
}
}
| |
RecordGrid provides a freeze frame capability that
enables you to set a specified number of rows and columns to be
non-scrolling. The following
RecordGrid properties and
methods manage the number of non-scrolling rows and columns.
The offset values enable you to specify a frozen region with rows
and columns scrolled out of view at the top and left of the
display.
The following example illustrates the default behavior,
implemented by
StandardRecordGridUI. Note that the first
data record contains header information. The example uses
RecordGrid.set-frozen-region to freeze the header record and the
id column.
| Example:
Freezing a Header Row |
 |
{let staff:CsvRecordSet =
{CsvRecordSet
{url "../../default/support/data.csv"}
}
}
{let rg:RecordGrid =
{RecordGrid
record-source = staff,
display-column-headers? = false,
display-record-selectors? = false
}
}
{rg.set-frozen-region 1, 1}
{value rg}
| |
You can view sorted records in a similar way. You can sort a
single column through a context menu on the grid. You can also set
the
RecordGrid.sort property. The value you set is used
to set the
sort property of the
RecordGrid.records RecordView.
To change the sorting and filtering interactively, right-click a
cell or column heading and make a choice from the context menu
that pops up. The property
RecordGrid.filter-menu-proc
allows you to customize this menu. This example includes a simple
filter-menu-proc, which reverses the order of items in the
menu.
| Example:
Using RecordGrid.filter and
RecordGrid.sort |
 |
{let staff:RecordSet =
{evaluate
{url "../../default/support/data.scurl"}
}
}
{let rg:RecordGrid =
{RecordGrid
record-source = staff, height = 5cm, width = 16cm,
column-selection-enabled? = true,
filter-menu-proc =
{proc {array:{Array-of MenuItem}, cell:RecordGridCell}:{Array-of MenuItem}
{array.reverse}
{return array}
}
}
}
{VBox
rg,
{HBox
{CommandButton label = "Sort by City, State",
width = {make-elastic},
{on Action do
set rg.sort = "City, State"
}
},
{CommandButton
width = {make-elastic},
label = "Filter for Cambridge, MA",
{on Action do
set rg.filter =
{RecordData City = "Cambridge", State = "MA"}
}
}
}
}
| |
The next example enables the end user choose to view a subset of
the columns in a
RecordGrid.
This example uses the
RecordGrid.selection property to
delete the selected columns from the display. The
columns
property of
RecordGridSelection is an
Iterator-of
RecordGridColumn, which enables you to loop through the selected
columns, processing each one in turn. You must set
RecordGrid.automatic-columns? to
false, and generate the
initial set of columns explicitly. If
automatic-columns?
is
true, columns are automatically regenerated as soon as
they are deleted.
| Example:
Remove and Restore Columns |
 |
{let staff:RecordSet =
{evaluate
{url "../../default/support/data.scurl"}
}
}
{let rg:RecordGrid =
{RecordGrid
record-source = staff, height = 5cm, width = 16cm,
column-selection-enabled? = true
}
}
{let original-columns:{Array-of RecordGridColumn} = {rg.columns.clone}}
{VBox
rg,
{HBox
{CommandButton label = "Remove Selected Column(s)", width = 8cm,
{on Action do
{let new-columns:{Array-of RecordGridColumn} = {rg.columns.clone}}
{for col:RecordGridColumn in rg.selection.columns do
{new-columns.remove {new-columns.find col}}
}
set rg.columns = new-columns
}
},
{CommandButton label = "Restore Original Columns", width = 8cm,
{on Action do
set rg.columns = original-columns
}
}
}
}
| |
The following properties enable different types of selection.
| Example:
Using RecordGrid to Select Columns and
Records |
 |
{let staff:RecordSet =
{evaluate
{url "../../default/support/data.scurl"}
}
}
{let rg:RecordGrid =
{RecordGrid height = 10cm,
column-selection-enabled? = true,
select-current-record? = true,
cells-take-focus? = false,
record-source = staff,
width = 16cm
}
}
{let msg:VBox = {VBox}}
{VBox
rg,
{HBox
{CommandButton
width = 8cm,
label = "Process records",
{on Action do
{if rg.selection.record-count == 0 then
{popup-message "No records selected"}
else
{for i:int in rg.selection.records do
let r:Record = rg.records[i]
{msg.add {format "%s %s",
r["First"],
r["Last"]
}
}
}
{popup-message
msg
}
{msg.clear}
}
}
},
{CommandButton
width = 8cm,
label = "Process columns",
{on Action do
{if rg.selection.column-count == 0 then
{popup-message "No columns selected"}
else
{for c:RecordGridColumn in rg.selection.columns do
{msg.add c.field.name}
}
{popup-message
msg
}
{msg.clear}
}
}
}
}
}
| |
You can also click and drag to select rectangular regions made up
of columns and rows. Use the
ctrl key to select more
than one region.
RecordGrid maintains information about
selected regions in
RecordGrid.selection.
| Example:
Using RecordGrid to select Regions |
 |
{let staff:RecordSet =
{evaluate
{url "../../default/support/data.scurl"}
}
}
{let rg:RecordGrid =
{RecordGrid height = 10cm,
region-selection-enabled? = true,
record-selection-enabled? = false,
record-source = staff,
width = 16cm
}
}
{let msg:VBox = {VBox}}
{VBox
rg,
{HBox
{CommandButton
width = {make-elastic},
label = "Process regions",
{on Action do
{if rg.selection.region-count == 0 then
{popup-message "No regions selected"}
else
{msg.add "regions: " & rg.selection.region-count}
{for r:RecordGridRegion in rg.selection.regions do
{msg.add "columns: " & r.column-count
& " First column index: " & r.first-column}
{msg.add "rows: " & r.row-count
& " First row index: " & r.first-row}
{msg.add "---"}
}
{popup-message
msg
}
{msg.clear}
}
}
}
}
}
| |
RecordGrid supports copy and paste operations on selected
rows, columns, and regions through the following
Commands:
- RecordGridCopy copies the content of selected cells
to the clipboard. It calls RecordGridCell.format to
convert data in selected cells to strings, and uses
tab to separate cells, and newline
to separate rows. You can paste the copied data to a region
in a record grid with RecordGridPaste, or to another
application such as a spreadsheet or document editor.
It is enabled when the selection is one of the following:
- one or more rows
- one or more columns
- one region
- full selection, the result of a RecordGridSelectAll
command
- RecordGridPaste is enabled under the same
circumstances as RecordGridCopy. It breaks the
clipboard contents at tabs and newlines to produce a region of
strings and applies that region to the RecordGrid
starting at the active cell or the upper-left corner of the
selection. It calls RecordGridCell.update-data on
each cell.
An active selection acts as a mask for the paste region, so
that paste discards data that falls outside the selection. - RecordGridSelectAll selects all data displayed in
the record grid. It performs the selection as all rows, all
columns, and/or a single region containing all cells, depending on
the selection options set on the RecordGrid.
The standard UI makes these commands accessible through the
standard keyboard accelerators, such as ctrl + c for
copy, and through a right-click context menu.
The selection, copy, and paste commands operate on the rows and
columns displayed in the grid. If you apply filters, or remove
columns from the display, and act on only the fields and records
that remain visible.
The following example illustrates a number of these commands. Note
the following points:
- The commands select-nothing, copy, and paste are disabled when there is no active selection.
- select-all selects the entire content of the grid.
- select-nothing deselects all selected columns, rows,
or regions.
- The command buttons labeled Select Region and Deselect Region act on fixed-region, which is created
with RecordGridRegion.default.
- The commands select-nothing, copy, and paste are disabled if more than one region is selected.
- This example allows only region selection. Try removing the
line region-selection-enabled? = true and executing
the example. Note that the grid now allows no selection, and
the command select-all is disabled.
| Example:
Select, copy and paste |
 |
{let staff:RecordSet =
{evaluate
{url "../../default/support/data.scurl"}
}
}
{let rg:RecordGrid =
{RecordGrid height = 10cm,
region-selection-enabled? = true,
record-selection-enabled? = false,
select-current-record? = true,
cells-take-focus? = false,
record-source = staff,
width = 16cm
}
}
{let msg:VBox = {VBox}}
{let fixed-region:RecordGridRegion =
{RecordGridRegion
1, 1, 2, 2
}
}
{VBox
rg,
{HBox
{CommandButton
width = {make-elastic},
label = "Select All",
bound-command = {rg.get-command "select-all"}
},
{CommandButton
width = {make-elastic},
label = "Select Nothing",
bound-command = {rg.get-command "select-nothing"}
},
{CommandButton
width = {make-elastic},
label = "Select Region",
{on Action do
{rg.select-region fixed-region, additive? = true}
}
},
{CommandButton
width = {make-elastic},
label = "Deselect Region",
{on Action do
{rg.deselect-region fixed-region}
}
},
{CommandButton
width = {make-elastic},
label = "Copy Selection",
bound-command = {rg.get-command "copy"}
},
{CommandButton
width = {make-elastic},
label = "Paste",
bound-command = {rg.get-command "paste"}
}
}
}
| |
In the following example, the
RecordSet maritime-signal-flags contains a field called
flag that
contains strings that identify graphics files. Displaying these
files as a graphic image in a
RecordGrid requires a
specialized
RecordGridCell.
The example also uses
RecordGridColumn to
create columns in the grid. The column that displays the flag data
uses
FlagCell as its
cell-spec. The column also sets the width to a
value appropriate for the width of the images, and sets
column-resizable? to false, so the
user cannot change the column width and distort the images.
Note also that the
RecordGrid in this example sets the
option
editable? to
false, which makes the entire
grid display-only.
| Example:
Display a RecordSet with
RecordGrid |
 |
{let maritime-signal-flags:RecordSet =
{evaluate
{url "../../default/support/flag-data.scurl"}
}
}
{define-class public open FlagCell
{inherits StandardRecordGridCell}
field private flag:Frame =
{Frame width={make-elastic}, height={make-elastic}}
{constructor public {default}
{construct-super}
set self.height = 42px
{self.add-internal self.flag}
set self.cells-take-focus? = self.can-update?
}
{method public open {refresh-data}:void
let (data:String, valid?:bool) = {self.get-formatted-data}
{if valid? and data != "" then
set self.flag.background = {url data}
else
{unset self.flag.background}
}
}
}
{let rg:RecordGrid =
{RecordGrid
width = 14cm,
height = 14cm,
record-source = maritime-signal-flags,
editable? = false,
automatic-columns? = false,
{RecordGridColumn width = 1.3cm, "letter"},
{RecordGridColumn width = 2cm, "phonetic"},
{RecordGridColumn width = 1.3cm, "colors"},
{RecordGridColumn width = 1.3cm, "red?"},
{RecordGridColumn width = 1.3cm, "white?"},
{RecordGridColumn width = 1.3cm, "blue?"},
{RecordGridColumn width = 1.3cm, "yellow?"},
{RecordGridColumn width = 1.3cm, "black?"},
{RecordGridColumn "flag", width = 53px,
column-resizable? = false, cell-spec = FlagCell}
}
}
{value rg}
| |
The class
RecordSetDisplay is a
CommandContext
and supports a number of commands for manipulating underlying
data. Both
RecordGrid and
RecordForm inherit
these commands, as do any subclasses of
RecordSetDisplay
you create. You can use these commands to provide functionality
for menu items and controls. The following example uses the
commit and
revert commands for the buttons
commit
records and
revert records.
| Example:
Data from User |
 |
{let people:RecordSet =
{RecordSet
{RecordFields
{RecordField
"First", caption = "first name", domain = String
},
{RecordField
"Last", caption = "last name", domain = String
},
{RecordField
"Age", caption = "age", domain = int
}
},
{RecordData First = "John", Last = "Smith", Age = 25},
{RecordData First = "Jane", Last = "Smith", Age = 29},
{RecordData First = "Jane", Last = "Jones", Age = 28}
}
}
{let rg:RecordGrid =
{RecordGrid
height = 3cm, width = 9.75cm, record-source = people
}
}
{value
{VBox
rg,
{HBox
{CommandButton
width = {make-elastic}, label = "append record",
{on Action do
{people.append {RecordData}}
}
},
{CommandButton
width = {make-elastic}, label = "commit records",
bound-command = {rg.get-command "commit"}
},
{CommandButton
width = {make-elastic}, label = "revert records",
bound-command = {rg.get-command "revert"}
}
}
}
}
| |
The
RichTextArea control enables users to input and
format rich text content. There are two ways you can incorporate
the rich text provided by
RichTextArea in a
RecordGrid:
The following example adds messages to a
RecordSet. Use
the
TextArea to input a person's name, and the
RichTextArea to input a message that can include text
formatting. Click
Add Messages to add the record to a
RecordSet. Because this example does not place the
controls in a
RecordForm, you do not have a navigation
panel available to view records as you add them. Click
Show
Messages to view all the records you have added in a
RecordGrid. Note the use of
format-as-curl-source-fragment to store the message,
and the special-purpose
RecordGridCell,
CodeCell,
which displays it.
| Example:
Storing Rich Text as a Code String |
 |
{let messages:RecordSet =
{RecordSet
{RecordFields
{RecordField "Recipient", domain = String},
{RecordField "Message", domain = String}
}
}
}
{define-class public open CodeCell
{inherits StandardRecordGridCell}
{constructor public {default}
{construct-super}
{self.add-internal {TextFlowBox}}
}
{method public open {refresh-data}:void
{super.refresh-data}
let (data:String, valid?:bool) = {self.get-formatted-data}
{self.child.graphic.clear}
{if valid? then
{self.child.graphic.add
{evaluate data}
}
}
}
}
{let rg:RecordGrid =
{RecordGrid
record-source = messages,
automatic-columns? = false,
{RecordGridColumn "Recipient"},
{RecordGridColumn "Message", cell-spec = CodeCell}
}
}
{let rcp:String = ""}
{let msgstr:String = ""}
{let ta:TextArea = {TextArea height = 1cm}}
{let rta:RichTextArea = {RichTextArea height = 2cm}}
{VBox
{Table
{row-prototype "Message recipient: ", ta},
{row-prototype "Message text: ", rta}
},
{HBox
{CommandButton label = "Add Message",
{on e:Action do
set rcp = ta.value
set msgstr = {rta.format-as-curl-source-fragment}
{messages.append {RecordData Recipient = rcp, Message = msgstr}}
{e.consume}
}
},
{CommandButton label = "Show Messages",
{on e:Action do
{{View {value rg}}.show}
{e.consume}
}
}
}
}
| |
| Example:
Storing Rich Text as a RichTextString |
 |
{let messages:RecordSet =
{RecordSet
{RecordFields
{RecordField "Recipient", domain = String},
{RecordField "Message", domain = #any}
},
{RecordData Recipient = "Recipient",
Message = {RichTextString.from-string "Message"}}
}
}
{define-class public open RichTextAreaCell
{inherits StandardRecordGridCell}
{doc-next {purpose Construct this object.}}
{constructor public {default}
{construct-super}
{self.add-internal
{RichTextArea height = 2cm,
active-traversal-container = null,
display-formatting-panel? = false}
}
}
{method public open {refresh-data}:void
{super.refresh-data}
let rta:RichTextArea = self.child.graphic asa RichTextArea
let (val:any, valid?:bool) = {self.get-data}
{if valid? then
set rta.value = val
else
set rta.ui-object.control-content-background = self.control-color
}
}
}
{let rg:RecordGrid =
{RecordGrid
record-source = messages,
editable? = false,
automatic-columns? = false,
{RecordGridColumn "Recipient"},
{RecordGridColumn "Message", cell-spec = RichTextAreaCell}
}
}
{let rf:RecordForm =
{RecordForm
record-source = messages,
{VBox
{TextArea {bind value to "Recipient"}},
{RichTextArea
height = 2cm,
{bind value to "Message"}
}
}
}
}
{value
{VBox
rf,
{HBox
{CommandButton
label = "append record",
{on Action do
{messages.append
{RecordData Recipient = "Recipient",
Message = {RichTextString.from-string "Message"}}}
}
},
{CommandButton
label = "update record",
{on ac:Action do
{if-non-null {rf.update} then
{if {popup-question
{message
There were one or more errors on this form.
Continue?
}
} == Dialog.no
then
{ac.consume}
}
}
}
},
{CommandButton
label = "commit changes",
bound-command = {rf.get-command "commit"}
},
{CommandButton
label = "revert records",
bound-command = {rf.get-command "revert"}
}
,
{CommandButton
label = "show grid",
{on ac:Action do
{{View
{value
rg
}
}.show}
{ac.consume}
}
}
}
}
}
| |
Copyright © 1998-2007 Sumisho Computer Systems Corp.
All rights reserved.
Curl, the Curl logo, Surge, and the Surge logo are trademarks of Sumisho
Computer Systems Corp. that are registered in the United States. Surge
Lab, the Surge Lab logo, and the Surge Lab Visual Layout Editor (VLE)
logo are trademarks of Sumisho Computer Systems Corp.