Searching for Records in Developer Express QuantumGrid

Applies to TestComplete 14.40, last modified on April 22, 2021

To simulate user actions over the QuantumGrid control, you may need to locate the row that contains the data that you are going to work with. This topic describes several approaches that can be used to locate records in the QuantumGrid control.

You can locate the desired record using any of the approaches described below in this topic. At the end of the topic we will also compare these approaches.

In order for TestComplete to be able to perform these actions, the following conditions must be met: Note also, that the compiler can exclude methods and properties that are not called in the application’s source code from the application’s binary code, so these methods and properties are unavailable to TestComplete (see Object Properties, Fields and Methods That Are Unavailable to TestComplete). To solve the problem, make sure that the desired methods and properties are used in the application’s source code. For instance, you can add a virtual method to your application that calls the desired methods and properties (the compiler does not exclude virtual methods).

When testing Developer Express QuantumGrid controls, use specific methods and properties of the corresponding DevExpressQuantumGrid object. You can call these methods and properties from your keyword tests, as well as from scripts. This topic describes how to work with an object’s properties and methods from your scripts. However, when testing a QuantumGrid control from your keyword test, you can use the same methods and properties calling them from keyword test operations. For more information, see Keyword Tests Basic Operations.

Searching by Iterating Through Grid Rows

A general approach for searching within the grid control implies that you iterate through the grid rows in a loop and on each iteration check whether the row meets the specified condition, for example, if it holds a specific value in a particular column. The following example demonstrates how you can locate a particular row by iterating through the grid rows:

Example

View description

JavaScript

function Main ()
{
  var p, Grid, ColumnName, ColumnValue, RowIndex;

  // Obtain the grid object
  p = Sys.Process("MySampleApp");
  Grid = p.VCLObject("FormName").VCLObject("GridName");

  // Locate a row
  ColumnName = "MyColumn";
  ColumnValue = "MyValue";
  RowIndex = FindRow (Grid, ColumnName, ColumnValue);

  // Check if the row was found
  if (RowIndex != -1)
  {
    Grid.ClickCell(RowIndex, ColumnName);
    Log.Message("Row index: " + RowIndex);
  }
  else
    Log.Error("Row was not found.");
}

function FindRow (Level, ColumnId, Value, ViewId)
{
  // If the ViewId parameter is not specified,
  // initialize it with the default value
  if (strictEqual(ViewId, undefined))
    ViewId = 0;

  // Iterate through the rows
  for (let i=0; i<Level.wRowCount(ViewId); i++)
    // Check the cell value in the specified column
    if (equal(Level.wValue(i, ColumnId, ViewId), Value))
      return i; // Row is found

  return -1; // Row is not found
}

JScript

function Main ()
{
  var p, Grid, ColumnName, ColumnValue, RowIndex;

  // Obtain the grid object
  p = Sys.Process("MySampleApp");
  Grid = p.VCLObject("FormName").VCLObject("GridName");

  // Locate a row
  ColumnName = "MyColumn";
  ColumnValue = "MyValue";
  RowIndex = FindRow (Grid, ColumnName, ColumnValue);

  // Check if the row was found
  if (RowIndex != -1)
  {
    Grid.ClickCell(RowIndex, ColumnName);
    Log.Message("Row index: " + RowIndex);
  }
  else
    Log.Error("Row was not found.");
}

function FindRow (Level, ColumnId, Value, ViewId)
{
  // If the ViewId parameter is not specified,
  // initialize it with the default value
  if (typeof(ViewId) == "undefined")
    ViewId = 0;

  // Iterate through the rows
  for (var i=0; i<Level.wRowCount(ViewId); i++)
    // Check the cell value in the specified column
    if (Level.wValue(i, ColumnId, ViewId) == Value)
      return i; // Row is found

  return -1; // Row is not found
}

Python

def Main ():

  # Obtain the grid object
  p = Sys.Process("MySampleApp")
  Grid = p.VCLObject("FormName").VCLObject("GridName")

  # Locate a row
  ColumnName = "MyColumn"
  ColumnValue = "MyValue"
  RowIndex = FindRow (Grid, ColumnName, ColumnValue)

  # Check if the row was found
  if (RowIndex != -1):
    Grid.ClickCell(RowIndex, ColumnName)
    Log.Message("Row index: " + RowIndex)
  else:
    Log.Error("Row was not found.")

def FindRow (Level, ColumnId, Value, ViewId):
  # If the ViewId parameter is not specified,
  # initialize it with the default value
  if (typeof(ViewId) == "undefined"):
    ViewId = 0

  # Iterate through the rows
  for i in range(0, Level.wRowCount(ViewId)-1):
    # Check the cell value in the specified column 
    if (Level.wValue(i, ColumnId, ViewId) == Value):
      return i # Row is found

  return -1 # Row is not found

VBScript

Sub Main
  Dim p, Grid, ColumnName, ColumnValue, RowIndex

  ' Obtain the grid object
  Set p = Sys.Process("MySampleApp")
  Set Grid = p.VCLObject("FormName").VCLObject("GridName")

  ' Locate a row
  ColumnName = "MyColumn"
  ColumnValue = "MyValue"
  RowIndex = FindRow (Grid, ColumnName, ColumnValue, 0)

  ' Check if the row was found
  If RowIndex <> -1 Then
    Call Grid.ClickCell(RowIndex, ColumnName)
    Log.Message("Row index: " & RowIndex)
  Else
    Log.Error("Row was not found.")
  End If
End Sub

Function FindRow (Level, ColumnId, Value, ViewId)
  Dim i
  ' Iterate through the rows
  For i = 0 to Level.wRowCount(ViewId)-1
    ' Check the cell value in the specified column
    If Level.wValue(i, ColumnId, ViewId) = Value Then
      FindRow = i ' Row is found
      Exit Function
    End If
  Next

  FindRow = -1 ' Row is not found
End Function

DelphiScript

function FindRow (Level, ColumnId, Value, ViewId : OleVariant = 0);
var i : OleVariant;
begin
  // Iterate through the rows
  for i := 0 to Level.wRowCount[ViewId]-1 do
    // Check the cell value in the specified column
    if Level.wValue[i, ColumnId, ViewId] = Value then
    begin
      Result := i; // Row is found
      Exit;
    end;

  Result := -1; // Row is not found
end;

procedure Main;
var p, Grid, ColumnName, ColumnValue, RowIndex : OleVariant;
begin
  // Obtain the grid object
  p := Sys.Process('MySampleApp');
  Grid := p.VCLObject('FormName').VCLObject('GridName');

  // Locate a row
  ColumnName := 'MyColumn';
  ColumnValue := 'MyValue';
  RowIndex := FindRow (Grid, ColumnName, ColumnValue);

  // Check if the row was found
  if RowIndex <> -1 then
  begin
    Grid.ClickCell(RowIndex, ColumnName);
    Log.Message('Row index: ' + aqConvert.VarToStr(RowIndex));
  end
  else
    Log.Error('Row was not found.');
end;

C++Script, C#Script

function Main ()
{
  var p, Grid, ColumnName, ColumnValue, RowIndex;

  // Obtain the grid object
  p = Sys["Process"]("MySampleApp");
  Grid = p["VCLObject"]("FormName")["VCLObject"]("GridName");

  // Locate a row
  ColumnName = "MyColumn";
  ColumnValue = "MyValue";
  RowIndex = SearchCellWithIncremental (Grid, null, ColumnName, ColumnValue);
  
  // Check if the row was found
  if (RowIndex != -1)
    Log["Message"]("Row index: " + RowIndex);
  else
    Log["Error"]("Row was not found.");
}

// Searches for the row using the incremental search functionality
function SearchCellWithIncremental (Grid, View, ColumnId, SearchString)
{
  var Column, RowIndex;

  // Obtain the view object
  if (View == null)
    View = Grid["ActiveView"];

  // Get the column object
  Column = GetColumn (Grid, View, ColumnId);

  // Activate the first row
  View["DataController"]["GotoFirst"]();
  // Search using the incremental search
  View["DataController"]["Search"]["Locate"](Column["Index"], SearchString);
  // Cancel the incremental search mode
  View["DataController"]["Search"]["Cancel"]();

  // Check if the search was successful
  RowIndex = View["DataController"]["FocusedRowIndex"];
  if (View["ViewData"]["Rows"](RowIndex)["DisplayTexts"](Column.Index) == SearchString)
  {
    // The cell was found; select it and return its row index
    Column["Focused"] = true;
    return RowIndex
  }
  else
    return -1; // Row was not found
}

// Returns the column object by its caption or index
function GetColumn (Grid, View, ColumnId)
{
  // Obtain the view object
  if (View == null)
    View = Grid["ActiveView"];

  // Check type of the columnId parameter
  if (aqObject["GetVarType"](ColumnId) == varOleStr)
  {
    // If ColumnId is a string,
    // then search for the column by its caption
    for (var i = 0; i < View["ColumnCount"]; i++)
      if (View["GetColumn"](i)["Caption"] == ColumnId)
        return View["GetColumn"](i); // Column is found

    return null; // Column is not found
  }
  else
    // If ColumnId is an integer,
    // then search for column by its index
    return View["GetColumn"](ColumnId);
}

Searching by Using the Incremental Search Feature

QuantumGrid controls include the incremental search functionality. When it is active, you can search for a row by focusing the desired column and typing the desired text. The grid will automatically locate the row containing the text you entered.

If the tested grid supports incremental search, then to search for a record, you can simulate user actions that will focus the desired column and then simulate keystrokes over the grid. The sample below demonstrates this approach.

Note: The incremental search feature is activated by the OptionsBehavior.IncSearch property of a grid view. To enable the incremental search for a view, set the ViewObj.OptionsBehavior.IncSearch to True. If the tested grid only contains one level, you can use the GridObj.ActiveView.OptionsBehavior.IncSearch property.
Example

View description

JavaScript

function Main ()
{
  var p, Grid, ColumnName, ColumnValue, RowIndex;

  // Obtain the grid object
  p = Sys.Process("MySampleApp");
  Grid = p.VCLObject("FormName").VCLObject("GridName");

  // Locate a row
  ColumnName = "MyColumn";
  ColumnValue = "MyValue";
  RowIndex = SearchCellWithIncremental (Grid, null, ColumnName, ColumnValue);

  // Check if the row was found
  if (RowIndex != -1)
    Log.Message ("Row index: " + RowIndex);
  else
    Log.Error ("Row was not found.");
}

// Searches for the row using the incremental search functionality
function SearchCellWithIncremental (Grid, View, ColumnId, SearchString)
{
  var Column, RowIndex;

  // Obtain the view object
  if (strictEqual(View, null))
    View = Grid.ActiveView;

  // Get the column object
  Column = GetColumn (Grid, View, ColumnId);

  // Activate the first row
  View.DataController.GotoFirst();
  // Search using the incremental search
  View.DataController.Search.Locate(Column.Index, SearchString);
  // Cancel the incremental search mode
  View.DataController.Search.Cancel();

  // Check if the search was successful
  RowIndex = View.DataController.FocusedRowIndex;
  if (equal(View.ViewData.Rows(RowIndex).DisplayTexts(Column.Index), SearchString))
  {
    // The cell was found; select it and return its row index
    Column.Focused = true;
    return RowIndex
  }
  else
    return -1; // Row was not found
}

// Returns the column object by its caption or index
function GetColumn (Grid, View, ColumnId)
{
  // Obtain the view object
  if (strictEqual(View, null))
    View = Grid.ActiveView;

  // Check type of the columnId parameter
  if (equal(aqObject.GetVarType(ColumnId), varOleStr))
  {
    // If ColumnId is a string,
    // then search for the column by its caption
    for (let i = 0; i < View.ColumnCount; i++)
      if (equal(View.GetColumn(i).Caption, ColumnId))
        return View.GetColumn(i); // Column is found

    return null; // Column is not found
  }
  else
    // If ColumnId is an integer,
    // then search for column by its index
    return View.GetColumn(ColumnId);
}

JScript

function Main ()
{
  var p, Grid, ColumnName, ColumnValue, RowIndex;

  // Obtain the grid object
  p = Sys.Process("MySampleApp");
  Grid = p.VCLObject("FormName").VCLObject("GridName");

  // Locate a row
  ColumnName = "MyColumn";
  ColumnValue = "MyValue";
  RowIndex = SearchCellWithIncremental (Grid, null, ColumnName, ColumnValue);

  // Check if the row was found
  if (RowIndex != -1)
    Log.Message ("Row index: " + RowIndex);
  else
    Log.Error ("Row was not found.");
}

// Searches for the row using the incremental search functionality
function SearchCellWithIncremental (Grid, View, ColumnId, SearchString)
{
  var Column, RowIndex;

  // Obtain the view object
  if (View == null)
    View = Grid.ActiveView;

  // Get the column object
  Column = GetColumn (Grid, View, ColumnId);

  // Activate the first row
  View.DataController.GotoFirst();
  // Search using the incremental search
  View.DataController.Search.Locate(Column.Index, SearchString);
  // Cancel the incremental search mode
  View.DataController.Search.Cancel();

  // Check if the search was successful
  RowIndex = View.DataController.FocusedRowIndex;
  if (View.ViewData.Rows(RowIndex).DisplayTexts(Column.Index) == SearchString)
  {
    // The cell was found; select it and return its row index
    Column.Focused = true;
    return RowIndex
  }
  else
    return -1; // Row was not found
}

// Returns the column object by its caption or index
function GetColumn (Grid, View, ColumnId)
{
  // Obtain the view object
  if (View == null)
    View = Grid.ActiveView;

  // Check type of the columnId parameter
  if (aqObject.GetVarType(ColumnId) == varOleStr)
  {
    // If ColumnId is a string,
    // then search for the column by its caption
    for (var i = 0; i < View.ColumnCount; i++)
      if (View.GetColumn(i).Caption == ColumnId)
        return View.GetColumn(i); // Column is found

    return null; // Column is not found
  }
  else
    // If ColumnId is an integer,
    // then search for column by its index
    return View.GetColumn(ColumnId);
}

Python

def Main ():

  # Obtain the grid object
  p = Sys.Process("MySampleApp")
  Grid = p.VCLObject("FormName").VCLObject("GridName")

  # Locate a row
  ColumnName = "MyColumn"
  ColumnValue = "MyValue"
  RowIndex = SearchCellWithIncremental (Grid, None, ColumnName, ColumnValue)

  # Check if the row was found
  if (RowIndex != -1):
    Log.Message ("Row index: " + RowIndex)
  else:
    Log.Error ("Row was not found.")

# Searches for the row using the incremental search functionality
def SearchCellWithIncremental (Grid, View, ColumnId, SearchString):

  # Obtain the view object 
  if (View == None):
    View = Grid.ActiveView

  # Get the column object 
  Column = GetColumn (Grid, View, ColumnId)

  # Activate the first row
  View.DataController.GotoFirst()
  # Search using the incremental search
  View.DataController.Search.Locate(Column.Index, SearchString)
  # Cancel the incremental search mode
  View.DataController.Search.Cancel()

  # Check if the search was successful
  RowIndex = View.DataController.FocusedRowIndex
  if (View.ViewData.Rows(RowIndex).DisplayTexts(Column.Index) == SearchString):
    # The cell was found select it and return its row index
    Column.Focused = True
    return RowIndex
  else:
    return -1 # Row was not found

# Returns the column object by its caption or index
def GetColumn (Grid, View, ColumnId):
  # Obtain the view object 
  if (View == None):
    View = Grid.ActiveView

  # Check type of the columnId parameter 
  if (aqObject.GetVarType(ColumnId) == varOleStr):
    # If ColumnId is a string,
    # then search for the column by its caption
    for i in range(0, View.ColumnCount-1):
      if (View.GetColumn(i).Caption == ColumnId):
        return View.GetColumn(i) # Column is found

    return None # Column is not found
  else:
    # If ColumnId is an integer,
    # then search for column by its index
    return View.GetColumn(ColumnId)

VBScript

Sub Main_SearchByIncremental
  Dim p, Grid, ColumnName, ColumnValue, RowIndex

  ' Obtain the grid object
  Set p = Sys.Process("MySampleApp")
  Set Grid = p.VCLObject("FormName").VCLObject("GridName")

  ' Locate a row
  ColumnName = "MyColumn"
  ColumnValue = "MyValue"
  RowIndex = SearchCellWithIncremental (Grid, Nothing, ColumnName, ColumnValue)

  ' Check if the row was found
  If RowIndex <> -1 Then
    Log.Message("Row index: " & RowIndex)
  Else
    Log.Error ("Row was not found.")
  End If
End Sub

' Searches for the row using the incremental search functionality
Function SearchCellWithIncremental (Grid, View, ColumnId, SearchString)
  Dim Column, RowIndex

  ' Obtain the view object
  If View Is Nothing Then
    Set View = Grid.ActiveView
  End If

  ' Get the column object
  Set Column = GetColumn (Grid, View, ColumnId)

  ' Activate the first row
  View.DataController.GotoFirst
  ' Search using the incremental search
  Call View.DataController.Search.Locate(Column.Index, SearchString)
  ' Cancel the incremental search mode
  View.DataController.Search.Cancel

  ' Check if the search was successful
  RowIndex = View.DataController.FocusedRowIndex
  If View.ViewData.Rows(RowIndex).DisplayTexts(Column.Index) = SearchString Then
    ' The cell was found. Select it and return its row index
    Column.Focused = True
    SearchCellWithIncremental = RowIndex
  Else
    SearchCellWithIncremental = -1 ' Row was not found
  End If
End Function

' Returns the column object by its caption or index
Function GetColumn (Grid, View, ColumnId)
  Dim i

  ' Obtain the view object
  If View Is Nothing Then
    Set View = Grid.ActiveView
  End If

  ' Check type of the columnId parameter
  If aqObject.GetVarType(ColumnId) = varOleStr Then
    ' If ColumnId is a string, search for the column by its caption
    For i = 0 to View.ColumnCount-1
      If View.GetColumn(i).Caption = ColumnId Then
        Set GetColumn = View.GetColumn(i) ' Column id found
        Exit Function
      End If
    Next

    Set GetColumn = Nothing' Column is not found
  Else
    ' If ColumnId is an integer, search for column by its index
    Set GetColumn = View.GetColumn(ColumnId)
  End If
End Function

DelphiScript

function SearchCellWithIncremental (Grid, View, ColumnId, SearchString); forward;
function GetColumn (Grid, View, ColumnId); forward;

procedure Main;
var p, Grid, ColumnName, ColumnValue, RowIndex : OleVariant;
begin
  // Obtain the grid object
  p := Sys.Process('MySampleApp');
  Grid := p.VCLObject('FormName').VCLObject('GridName');

  // Locate a row
  ColumnName := 'MyColumn';
  ColumnValue := 'MyValue';
  RowIndex := SearchCellWithIncremental (Grid, nil, ColumnName, ColumnValue);

  // Check if the row was found
  if RowIndex <> -1 then
    Log.Message('Row index: ' + aqConvert.VarToStr(RowIndex))
  else
    Log.Error ('Row was not found.');
end;

// Searches for the row using the incremental search functionality
function SearchCellWithIncremental (Grid, View, ColumnId, SearchString);
var Column, RowIndex;
begin
  // Obtain the view object
  if View = nil then
    View := Grid.ActiveView;

  // Get the column object
  Column := GetColumn (Grid, View, ColumnId);

  // Activate the first row
  View.DataController.GotoFirst;
  // Search using the incremental search
  View.DataController.Search.Locate(Column.Index, SearchString);
  // Cancel the incremental search mode
  View.DataController.Search.Cancel;

  // Check if the search was successful
  RowIndex := View.DataController.FocusedRowIndex;
  if View.ViewData.Rows[RowIndex].DisplayTexts[Column.Index] = SearchString then
  begin
    // The cell was found; select it and return its row index
    Column.Focused := true;
    Result := RowIndex
  end
  else
    Result := -1; // Row was not found
end;

// Returns the column object by its caption or index
function GetColumn (Grid, View, ColumnId);
var i : OleVariant;
begin
  // Obtain the view object
  if View = nil then
    View := Grid.ActiveView;

  // Check type of the columnId parameter
  if aqObject.GetVarType(ColumnId) = varOleStr then
  begin
    // If ColumnId is a string,
    // then search for the column by its caption
    for i := 0 to View.ColumnCount-1 do
      if View.GetColumn(i).Caption = ColumnId then
      begin
        Result := View.GetColumn(i); // Column id found
        Exit;
      end;

    Result := nil; // Column is not found
  end
  else
    // If ColumnId is an integer,
    // then search for column by its index
    Result := View.GetColumn(ColumnId);
end;

C++Script, C#Script

function Main ()
{
  var p, Grid, ColumnName, ColumnValue, RowIndex;

  // Obtain the grid object
  p = Sys["Process"]("MySampleApp");
  Grid = p["VCLObject"]("FormName")["VCLObject"]("GridName");

  // Locate a row
  ColumnName = "MyColumn";
  ColumnValue = "MyValue";
  RowIndex = SearchCellWithIncremental (Grid, null, ColumnName, ColumnValue);
  
  // Check if the row was found
  if (RowIndex != -1)
    Log["Message"]("Row index: " + RowIndex);
  else
    Log["Error"]("Row was not found.");
}

// Searches for the row using the incremental search functionality
function SearchCellWithIncremental (Grid, View, ColumnId, SearchString)
{
  var Column, RowIndex;

  // Obtain the view object
  if (View == null)
    View = Grid["ActiveView"];

  // Get the column object
  Column = GetColumn (Grid, View, ColumnId);

  // Activate the first row
  View["DataController"]["GotoFirst"]();
  // Search using the incremental search
  View["DataController"]["Search"]["Locate"](Column["Index"], SearchString);
  // Cancel the incremental search mode
  View["DataController"]["Search"]["Cancel"]();

  // Check if the search was successful
  RowIndex = View["DataController"]["FocusedRowIndex"];
  if (View["ViewData"]["Rows"](RowIndex)["DisplayTexts"](Column.Index) == SearchString)
  {
    // The cell was found; select it and return its row index
    Column["Focused"] = true;
    return RowIndex
  }
  else
    return -1; // Row was not found
}

// Returns the column object by its caption or index
function GetColumn (Grid, View, ColumnId)
{
  // Obtain the view object
  if (View == null)
    View = Grid["ActiveView"];

  // Check type of the columnId parameter
  if (aqObject["GetVarType"](ColumnId) == varOleStr)
  {
    // If ColumnId is a string,
    // then search for the column by its caption
    for (var i = 0; i < View["ColumnCount"]; i++)
      if (View["GetColumn"](i)["Caption"] == ColumnId)
        return View["GetColumn"](i); // Column is found

    return null; // Column is not found
  }
  else
    // If ColumnId is an integer,
    // then search for column by its index
    return View["GetColumn"](ColumnId);
}

Which Approach to Choose

In the previous sections, we have described two variants of the searching procedure. One of these variants iterates through the rows of the grid and the other uses the incremental search functionality.

In general, incremental search provides a faster search. Since the search uses the cell’s display text, you do not have to be aware of the actual data type of grid cells; instead, you specify the text dispalyed in the desired cell. However, this kind of search cannot determine whether it has succeded or failed (in our example, we check this manually by analyzing the text in the row that became focused after the search). You can use the incremental search, for example, if you are sure that the grid contains a row with the sought-for text.

The approach that implies iterating through grid rows requires you to know the grid cells’s data types, because it analyzes cell values rather than their display text. This approach functions much slower than the incremental search, especially if the grid contains a large number of records. If you need better performance, you can implement a more effective search algorithm, for example, a binary search.

See Also

Working With Developer Express QuantumGrid
Iterating Through Rows in Developer Express QuantumGrid
Obtaining and Setting Cell Values in Developer Express QuantumGrid

Highlight search results