Tag Archives: LISTBOX

ListBoxes and TreeListBoxes – “in-place” editing

One of the new features that was added to the ListBox and TreeListBox controls in version 10 was the ability to use “in-place” editing on the items in the same manner as the Windows Explorer when you press “F2” or double-click an item. If you’ve done any work with the OpenInsight Menu Designers you will have seen this capability in action.

In-place editing for an item

The READONLY property

Enabling in-place editing is as simple as setting the READONLY property to False – once you’ve done that the user can press “F2” while using the control and edit the text of the currently selected item.  Pressing “Enter” when editing will update the item text (as will losing focus or selecting another item), while pressing “Esc” will abandon the changes.  Obviously that’s a very simple take on the topic and hardly worth a blog post in and of itself, so next we’ll take a look at some of the properties, methods and events that you can use to tailor the editing process.

The EDITING property

This is a simple boolean property that returns TRUE$ if an item is being edited.

The EDITORHANDLE property

This property returns the HANDLE of the editor control if an item is being edited.

The EDITKEY property

By default, hitting “F2” on an item puts the control into “edit mode”, just like the Windows Explorer.  However, if you wish to change this then you may use the EDITKEY property to select another key instead. The edit key is a Windows virtual key code and constants for these codes can be found in the MSWIN_VIRTUALKEY_EQUATES insert record.

The EDITOPTIONS property

This property allows you to fine-tune some of the validation options for the editor:

  • TextCase – Specifies if the text entered is lower-case only, upper-case only or mixed (See the EDITLINE TEXTCASE property for more details).
  • ValidChars – Specifies which characters may be entered into the editor (See the EDITLINE VALIDCHARS property for more details).
  • MaxLimit – Specifies the maximum number of characters that may be entered into the editor (See the EDITLINE LIMIT property for more details).

At runtime this property is an @fm-delimited array – constants for use with this property can be found in the PS_LISTBOX_EQUATES insert record.

The INCLUDEEDITORTEXT property

By default getting item text from the ListBox (e.g. via the LIST property) will include the text from an item currently being edited, even if that edited text has not yet been saved.  Setting this property to FALSE$ ensures that the returned item text ignores the value in the editor instead.

The BEGINEDIT method

This method allows you to programmatically put the ListBox into edit mode, as if the user had pressed “F2” (or whatever value the EDITKEY property is set to). You may specify the index of the item to edit, otherwise it will default to the current item.

RetVal = Exec_Method( CtrlEntID, "BEGINEDIT", itemIndex )

The ENDEDIT method

This method allows you to programmatically stop the item editing process, optionally allowing any changes to be accepted as if the “Enter” key had been pressed (the default is to reject any changes as if the “Esc” key had been pressed).

RetVal = Exec_Method( CtrlEntID, "ENDEDIT", bUpdate )

The ITEMEDITING event

This event is raised when an item it put into edit mode, and passes the index of the item as a parameter:

bForward = ITEMEDITING( CtrlEntID, CtrlClassID, ItemIndex )

The ITEMCHANGED event

This event is raised when the item is updated via the editor, i.e. the user hit the “Enter” key, the control lost the focus, or the EDITEDIT method was used with the bUpdate parameter set to TRUE$. The event passes the index of the item that has changed as well as the old and new data:

bForward = ITEMCHANGED( CtrlEntID, CtrlClassID, ItemIndex, |
                                                NewData,   |
                                                PrevData )

The ITEMUNCHANGED event

This event is raised when an item leaves edit mode without being updated, i.e. the user hit the “Esc” key or the EDITEDIT method was used with the bUpdate parameter set to FALSE$. The event passes the index of the item that was being edited:

bForward = ITEMUNCHANGED( CtrlEntID, CtrlClassID, ItemIndex )

So that wraps up this short post on ListBox editing – we’re sure that you’ll find many useful ways of implementing this new feature when expanding your application’s functionality.

EditTables – Getting multi-select data the easy way

In previous versions of OpenInsight the usual way of accessing data from a multi-row select EditTable control was to get the SELPOS property and then iterate over the data pulling out the rows, e.g. something like this (not optimized, but you get the idea):

   SelPos   = Get_Property( CtrlEntID, "SELPOS" )
   DataList = Get_Property( CtrlEntID, "LIST" )
   SelList  = ""

   SelRows  = SelPos<2>
   SelCount = FieldCount( SelRows, @Vm )  
   For SelIdx = 1 To SelCount
      SelRow = SelRows<0,SelIdx>
      SelList<-1> = DataList<SelRow>
   Next

However, in OpenInsight 10 we added a couple of new properties that allow you to access data in a multi-row select EditTable in a faster and more efficient way. These are:

  • The SELLIST property
  • The SELARRAY property

Both of these return data in the familiar LIST and ARRAY formats, but they only return data from the selected rows, thereby saving you the step of accessing SELPOS and iterating over the data yourself. So, to rewrite the example above we can now do this:

   SelList = Get_Property( CtrlEntID, "SELLIST" )

Likewise, to return the data in ARRAY format we would use the SELARRAY property like so:

   SelArray = Get_Property( CtrlEntID, "SELARRAY" )

Ergo, when asked the other day “What’s the fastest way of getting data from a specific column from the selected rows”, the answer was:

   SelData = Get_Property( CtrlEntID, "SELARRAY" )<colNum>

(And this question is also what led me to write this post…)

Bonus Trivia

The LISTBOX control also supports the SELLIST property.

Reordering tabs with the AllowDragReorder property

The next release of OpenInsight includes a new TABCONTROL property called ALLOWDRAGREORDER, which allows you to drag a tab to a new position within the control. It’s a simple boolean property, and when set to True tabs may be dragged and reordered with the mouse – an image of the tab is moved with the cursor, and a pair of arrows are displayed to mark the potential insertion point.

Here’s an example of a tab being dragged in the IDE:

Shows a image of the IDE with a tab being dragged by a cursor, along with the drag0image and the insertion marker arrows.

Bonus trivia

  • The tabs may be scrolled while dragging by hovering outside either edge of the control.
  • This property is not supported for:
    • MultiLine tab controls
    • Vertically-aligned tab controls
  • The LISTBOX control also supports this property for reordering its items – see the “Order Tabs” dialog in the Form Designer for an example, or the list of types in the IDE’s “Open Entity” dialog.

The EDITSTATECHANGED event

One of the requirements we needed when developing the new IDE was the ability to detect when the state of a control changed in such a fashion that might affect the operations that could be performed on it.

A classic example of this is highlighting text in an edit control so that it can be cut or copied, or perhaps replaced with a paste operation: At this point an item like a Cut or a Paste button might need enabling so the UI is in sync with the state of the control.

To enable this functionality several controls now support a new event called EDITSTATECHANGED, which is fired when the “edit state” is changed.  The edit state is defined as one of the following operations:

  • Undo
  • Redo
  • Cut
  • Copy
  • Paste
  • Select All

So, if a user takes an action in the control that enables or disables one of these options you can respond to it via the EDITSTATECHANGED event.

The EDITSTATECHANGED event passes a single parameter called “EditState“, which is a dynamic array of Boolean flags with the following structure:

<1> CanUndo      : TRUE$ if the control allows an UNDO operation
<2> CanRedo      : TRUE$ if the control allows a REDO operation
<3> CanCut       : TRUE$ if the control allows a CUT operation
<4> CanCopy      : TRUE$ if the control allows a COPY operation
<5> CanPaste     : TRUE$ if the control allows a PASTE operation
<6> CanSelectAll : TRUE$ if the control allows a SELECTALL 
                 : operation

(You may notice that these flags closely follow the items in a standard “Edit” menu).

Here’s a simple example to set the state of some Cut/Copy/Paste buttons:

   objxArray =        @window : ".BTN_CUT"
   propArray =        "ENABLED"
   dataArray =        editState<0,3>

   objxArray := @rm : @window : ".BTN_COPY"
   propArray := @rm : "ENABLED"
   dataArray := @rm : editState<0,4>
   
   objxArray := @rm : @window : ".BTN_PASTE"
   propArray := @rm : "ENABLED"
   dataArray := @rm : editState<0,5>

   call Set_Property_Only( objxArray, propArray, dataArray )

The following controls support the EDITSTATECHANGED event:

  • COMBOBOX
  • EDITLINE
  • EDITBOX
  • EDITTABLE
  • LISTBOX
  • PROPERTYGRID

(Disclaimer: This article is based on preliminary information and may be subject to change in the final release version of OpenInsight 10).

(EDIT: 8th May 2018 – Variable name changed from NewEditState to EditState to match released version)

Listboxes and ToolTips

Following on from our previous post on the new TOOLTIP property, this time we’re going to look at the new tooltip functionality added to Listbox controls, namely tracking and in-place item tooltips.

Tracking tooltips are small popup windows that appear when a user hovers over a partially obscured item in the control: they display the full item text string instead, and thereby avoid the need for horizontal scrolling, which is always a preferable user experience.

listbox_tracking_tooltips

Offset tracking tooltip

In-place tooltips operate in a similar manner, but rather than appearing at an offset to the cursor position they actually appear over the item itself, hence the term “in-place”:

listbox_inplace_tooltips

In-place tracking tooltip

This behaviour is controlled by the new SHOWITEMTOOLTIPS property which can be set to one of the following values:

  "0" - Disabled : Item tooltips are not displayed
  "1" - Offset   : Item tooltips are displayed at an offset to the cursor
  "2" - In-place : Item tooltips are displayed over the item itself.

When set to “1” (Offset) or “2” (In-place) the SHOWITEMTOOLTIPS property overrides the normal TOOLTIP property, so a “normal” tooltip will not be displayed.

Displaying alternative item text

Sometimes it is desirable to display a different text string in the tooltip rather than the item text itself.  In this case you can set the new SHOWVALUESASTOOLTIPS property to specify that the tooltip should display the contents of the item’s VALUE property instead.

SHOWVALUESASTOOLTIPS is a simple boolean property of TRUE$ or FALSE$.

listbox_tracking_value_tooltips

Displaying the Value property as a tooltip

Note in this case the tooltip is always displayed at an offset, and is triggered regardess of whether or not the item is clipped.

 

Combobox and TreeListbox controls

Both new properties described here also apply to simple Combobox and TreeListbox controls.

(Disclaimer: This article is based on preliminary information and may be subject to change in the final release version of OpenInsight 10).

 

The VALUES and VALUE properties

When working with ListBox and ComboBox controls it can sometimes be a chore to derive an “internal” value from list of visible items.  In many cases this involves creating an associated array of internal values, storing them in the MISC property (or a custom “@” property), and then extracting this array and the SELPOS property at runtime to arrive at the required data.

For example:

// Set up a LIST and internal items
colorNames = "Red"    : @fm : "Green"  : @fm : "Blue"
colorVals  = 0x0000FF : @fm : 0x00FF00 : @fm : 0xFF0000

call set_Property_Only( @window : ".LIST_1", "LIST", colorNames )
call set_Property_Only( @window : ".LIST_1", "MISC", colorVals )

... 

// Then at runtime to access the currently selected internal value
colorVals = get_Property( @window : ".LIST_1", "MISC" )
selPos    = get_Property( @window : ".LIST_1", "SELPOS" )

colorVal  = colorVals<selPos>

...

// Or even more long-winded, find an internal value from the external one:
colorNames = get_Property( @window : ".LIST_1", "LIST" )
colorVals  = get_Property( @window : ".LIST_1", "MISC" )

locate "Green" in colorNames using @fm setting pos then
   greenVal = colorVals<pos>
end

...

// or perhaps setting the currently selected item from an internal code:
colorNames = get_Property( @window : ".LIST_1", "LIST" )
colorVals  = get_Property( @window : ".LIST_1", "MISC" )

locate 0x00FF00 in colorVals using @fm setting pos then
   greenName = colorNames<pos>
   call set_Property_Only( @window : ".LIST_1", "TEXT", greenName )
end

To make this style of coding somewhat cleaner, OpenInsight 10 introduces the new VALUES property, which allows you to set an “internal” value for each item in the control, along with property indexing support.  There is also a new VALUE property, which is the counterpart to the standard TEXT property, and provides access to the currently selected item via it’s internal value.

Here’s the above examples rewritten to use VALUES and VALUE instead:

// Set up a LIST and internal items
colorNames = "Red"    : @fm : "Green"  : @fm : "Blue"
colorVals  = 0x0000FF : @fm : 0x00FF00 : @fm : 0xFF0000

call set_Property_Only( @window : ".LIST_1", "LIST", colorNames )
call set_Property_Only( @window : ".LIST_1", "VALUES", colorVals )

... 

// Then at runtime to access the currently selected internal value
colorVal = get_Property( @window : ".LIST_1", "VALUE" )
...

// Find an internal value from the external one:
greenVal = get_Property( @window : ".LIST_1", "VALUES", "Green" )

// or by position
greenVal = get_Property( @window : ".LIST_1", "VALUES", 2 )

...

// or perhaps setting the currently selected item from an internal code:
call set_Property_Only( @window : ".LIST_1", "VALUE", 0x00FF00 )

VALUES and VALUE apply to both ListBox and ComboBox controls.

(Disclaimer: This article is based on preliminary information and may be subject to change in the final release version of OpenInsight 10).