Skip to main content

In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

You need to set the event handled property to true.

If you want to also go to first column of next row when in last column yoiu also need to handle that.

Try something like the following:

method-id dataGridView1_KeyDown final private.
01 indexofRow binary-long.
01 indexofColumn binary-long.
procedure division using by value sender as object e as type System.Windows.Forms.KeyEventArgs.

          if NOT e::KeyCode = type System.Windows.Forms.Keys::Return
            exit method
          end-if.
          set indexOfRow to dataGridView1::CurrentCell::RowIndex.
          set indexOfColumn to dataGridView1::CurrentCell::ColumnIndex.

          if indexOfRow not = dataGridView1::NewRowIndex
             if indexofColumn = dataGridView1::Columns::Count - 1
                set indexofColumn to -1
                add 1 to indexofRow          
             end-if
             set dataGridView1::CurrentCell To dataGridView1[indexOfColumn 1, indexOfRow]
          end-if
          set e::Handled to true
      end method.


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

Hi Chris.

I've now got the code to do as I want as regards traversing the grid BUT...

Currently I have an event for 'cellValidating'.

On data entry into a cell and pressing the <RET> the code inside the 'keyDown' event DOES NOT GET processed. Only the code in the 'cellValidating' method is done.

The upshot of this is that the cursor moves one row down and does not traverse across.

Pressing the <RET> key on any cell WITHOUT entering data DOES fire up the keyDown method and the cursor behaves as expected.

How do I fix this?


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

Seems like you have to also trap the CellEndEdit event when you are also doing validation.

Add the following event handler:

method-id dataGridView1_CellEndEdit final private.
procedure division using by value sender as object e as type  System.Windows.Forms.DataGridViewCellEventArgs.

      invoke type SendKeys::Send("{TAB}")

end method.


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

Actually the only way that I have been able to get this to work successfully when editing and validating using the Enter Key as a tab is to subclass the dataGridView class and override the methods ProcessDialogKey and ProcessDataGridViewKey so that I can capture the enter and process it as a tab.

In the following example there is a second class near the bottom called CustomDataGridView in which I inherit from dataGridView and then override the two methods.

When this is compiled a new control called CustomDataGridView will appear in the Windows Forms Toolbox and then it can be selected and pasted to the form just like the standard dataGridView only the enter key will behave like a tab key.

I added the class and rebuilt a project that already used a dataGridView and I was able to modify the Designer.cbl file for the form to get it to reference the CustomDataGridView class instead of the dataGridView class in the two places where the class is used and after rebuilding it worked OK.

I definately don't recommend that you modify the designer.cbl file directly as it can cause problems but I was able to get it to work without having to delete the old dataGridView and replace with the new one.

      class-id testdatagrid.Form1 is partial
                inherits type System.Windows.Forms.Form.
      working-storage section.
      01 my-Table.
         03 my-Items         occurs 10.
            05 Table-Code    pic x(3).
            05 Table-Desc    pic x(20).
            05 Table-Value   pic S9(7)V99.
      01 num-items           binary-long.
      01 sub-1               binary-long.
      01 table-value-decimal decimal.

      method-id NEW.
      procedure division.
          invoke self::InitializeComponent
          invoke self::loadTable    
          goback.
      end method.

      method-id dataGridView1_CellValidating final private.
      01 rownum   binary-long.
      01 tempstring string.
      procedure division using by value sender as object e as type System.Windows.Forms.DataGridViewCellValidatingEventArgs.
          if e::ColumnIndex = 0
             set rownum to e::RowIndex
             set tempstring to e::FormattedValue
             if tempstring::CompareTo("444") > 0
                set e::Cancel to true
                set datagridview1::Rows[rownum]::ErrorText to "The value must be <= 444"
             else
                invoke dataGridView1::CommitEdit(type DataGridViewDataErrorContexts::CurrentCellChange)
                set datagridview1::Rows[rownum]::ErrorText to ""
             end-if
          end-if
      end method.

      method-id loadTable public.
      procedure division.
          move "111" to table-code(1)
          move "Table Item 1" to table-desc(1)
          move 1234.50 to table-value(1)
          move "222" to table-code(2)
          move "Table Item 2" to table-desc(2)
          move -9876.99 to table-value(2)
          move "333" to table-code(3)
          move "Table Item 3" to table-desc(3)
          move 1324.00 to table-value(3)
          move "444" to table-code(4)
          move "Table Item 4" to table-desc(4)
          move 1234.50 to table-value(4)
          move "555" to table-code(5)
          move "Table Item 5" to table-desc(5)
          move -123.75 to table-value(5)
          move 5 to num-items
          goback.
      end method.

      method-id Form1_Shown final private.
      procedure division using by value sender as object e as type System.EventArgs.
          perform varying sub-1 from 1 by 1
             until sub-1 > num-items
             invoke dataGridView1::Rows::Add
             set dataGridView1::Rows[sub-1 - 1]::Cells["CodeNum"]::Value to table-code(sub-1)
             set dataGridView1::Rows[sub-1 - 1]::Cells["Description"]::Value to table-desc(sub-1)
             move table-value(sub-1) to table-value-decimal
             set dataGridView1::Rows[sub-1 - 1]::Cells["Amount"]::Value to table-value-decimal
          end-perform  
          set dataGridView1::CurrentCell To dataGridView1[0, 0]
          invoke dataGridView1::Focus
      end method.

      method-id btnExit_Click final private.
      procedure division using by value sender as object e as type System.EventArgs.
          invoke self::Close
      end method.

      method-id btnSave_Click final private.
      procedure division using by value sender as object e as type System.EventArgs.
          move 1 to sub-1
          perform varying myRow as type DataGridViewRow thru dataGridView1::Rows
             if myRow::Cells["CodeNum"]::Value = null
                exit perform
             end-if
             move myRow::Cells["CodeNum"]::Value to table-code(sub-1)
             move myRow::Cells["Description"]::Value to table-desc(sub-1)
             set table-value(sub-1) to type System.Convert::ToDecimal(myRow::Cells["Amount"]::Value)
             add 1 to sub-1
          end-perform
      end method.
      end class.

      class-id CustomDataGridView inherits type DataGridView.
      working-storage section.

      method-id ProcessDialogKey override.
      local-storage section.
      01 keycode type Keys.
      procedure division using by value keyData as type Keys
                         returning ret-value as condition-value.
       *> Extract the key code from the key value.
           set keycode to keyData b-and type Keys::KeyCode
       *> Handle the ENTER key as if it were a tab key.  
           if keycode = type Keys::Enter
              set ret-value to self::ProcessTabKey(keyData)
           else
              set ret-value to super::ProcessDialogKey(keyData)
           end-if
           goback.          
      end method.

      method-id ProcessDataGridViewKey override.
      procedure division using by value e as type KeyEventArgs
                         returning ret-value as condition-value.
       *> Handle the ENTER key as if it were a tab key.  
          if e::KeyCode = type Keys::Enter
             set ret-value to self::ProcessTabKey(e::KeyData)
          else
             set ret-value to super::ProcessDataGridViewKey(e)
          end-if  
          goback.
      end method.      
      end class.


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

Hi Chris,

Copied your code into a test form, replaced the datagrid with the 'Custom' one.

Wouldn't compile!

Have initiated a incident (2611308). Have attached the solution to the incident.

Could you check it out please to see whats wrong?

Thanks.


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

Hi Mark,

The problem is that you changed the name of the control in the .designer.cbl file to CustomDataGridView1 but you are refererencing it in the Form program as dataGridView1.

These must have the same name as it is the same control that you are referencing in both.

It is actually not necessary to change the name of the control at all.
You simply have to change the type of the control in two places in the designer.cbl file:

The line where the object reference is defined:

01 dataGridView1 type CustomDataGridView.

and the line where it is instantiated:

set dataGridView1 to new CustomDataGridView

I gave you these instructions just to convert any of your existing forms that already have the dataGridView defined.

If you are creating a new dataGridView then just drag the new CustomDataGridView control from the toolbox instead of the original dataGridView and then you do not have to make any modifications at all.

Thanks.


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

Ok...we're getting there!!!

One final piece of the puzzle....

My table is 4 cols wide (0...3).

Cols 0 & 1 are information columns (Description & Default Value). Cols 2 & 3 are where the user will 'edit' the values.

I have code which tracks the <tab> and <enter> keys so that:

1) On form entry the cursor positions on Col 2 Row 0 by way of...

      method-id Form1_Shown final private.

      procedure division using by value sender as object e as type System.EventArgs.

              invoke mydata::Focus()

              set noOfDataRows to mydata::RowCount()

              subtract 1 from noOfDataRows              

              set mydata::CurrentCell To mydata[2 0]

      end method.

2) As the user clicks on the <tab> or entry key WITHOUT changing the data already inthe cell I have code which positions the cursor on the next grid position like so...

      method-id mydata_CellEndEdit final private.

      procedure division using by value sender as object e as type System.Windows.Forms.DataGridViewCellEventArgs.

          invoke type SendKeys::Send("{TAB}")

      end method.

&&

      method-id mydata_KeyDown final private.

      procedure division using by value sender as object e as type System.Windows.Forms.KeyEventArgs.

          if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

             exit method

          end-if.

          set indexOfRow to mydata::CurrentCell::RowIndex.

          set indexOfColumn to mydata::CurrentCell::ColumnIndex  

          if indexofColumn = 3                                                  *>> Last column of data

             if indexOfRow = noOfDataRows                                       *>> Last row of data

                set mydata::CurrentCell To mydata[2 0]                          *>> Go back round

             else

                add 1 to indexofRow

                set mydata::CurrentCell To mydata[2, indexOfRow]

             end-if  

          else

             if indexOfRow not = mydata::NewRowIndex

                if indexofColumn = mydata::Columns::Count - 1

                   set indexofColumn to -1

                   add 1 to indexofRow          

                end-if

                set mydata::CurrentCell To mydata[indexOfColumn 1, indexOfRow]

              end-if

           end-if.  

          set e::Handled to true.

      end method.

This stuff all now works great EXCEPT....

On pressing the <RET> key in Col 3 (last column) AFTER editing data IN COL 4 the cursor shoots back to COL 0 of the next row and NOT COL 2.

How can I force it to COL 2 if I've edited data in COL3 in the previous row??


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

Apologies...

The text...

On pressing the <RET> key in Col 3 (last column) AFTER editing data IN COL 4 the cursor shoots back to COL 0 of the next row and NOT COL 2.

should read as...

On pressing the <RET> key in Col 3 (last column) AFTER editing data IN COL 3 the cursor shoots back to COL 0 of the next row and NOT COL 2.


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

You don't like to make things easy, do you Mark?

You can make the enter key skip over columns that are defined with the ReadOnly property by modifying the CustomDataGrid class as follows:

      class-id CustomDataGridView inherits type DataGridView.
      working-storage section.

      method-id ProcessDialogKey override.
      local-storage section.
      01 keycode type Keys.
      01 col1 binary-long.
      01 row1 binary-long.
      procedure division using by value keyData as type Keys
                         returning ret-value as condition-value.
       *> Extract the key code from the key value.
           set keycode to keyData b-and type Keys::KeyCode
       *> Handle the ENTER key as if it were a Tab key.  
          if keycode = type Keys::Tab or keycode = type Keys::Enter
              set col1 to self::CurrentCell::ColumnIndex 1
              perform varying col1 from col1 by 1
                 until col1 >= self::Columns::Count
                 if not self::Columns[col1]::ReadOnly
                    exit perform
                 end-if
              end-perform
              if col1 < self::Columns::Count
                 set row1 to self::CurrentCell::RowIndex
                 set self::CurrentCell to self::Rows[row1]::Cells[col1]
              else
                 if self::CurrentCell::RowIndex not = self::Rows::Count - 1
                    perform varying col1 from 0 by 1
                       until col1 > self::CurrentCell::ColumnIndex
                       if not self::Columns[col1]::ReadOnly
                          exit perform
                       end-if
                    end-perform
                    if col1 <= self::CurrentCell::ColumnIndex
                       set row1 to self::CurrentCell::RowIndex
                       set self::CurrentCell to self::Rows[row1 1]::Cells[col1]
                    end-if
                 end-if
              end-if
             *> set ret-value to self::ProcessTabKey(keyData)
               set ret-value to true
           else
              set ret-value to super::ProcessDialogKey(keyData)
           end-if
           goback.          
      end method.

      method-id ProcessDataGridViewKey override.
      01 col1 binary-long.
      01 row1 binary-long.
      procedure division using by value e as type KeyEventArgs
                         returning ret-value as condition-value.
       *> Handle the ENTER key as if it were a Tab key.  
          if e::KeyCode = type Keys::Tab or e::KeyCode = type Keys::Enter
              set col1 to self::CurrentCell::ColumnIndex 1
              perform varying col1 from col1 by 1
                 until col1 >= self::Columns::Count
                 if not self::Columns[col1]::ReadOnly
                    exit perform
                 end-if
              end-perform
              if col1 < self::Columns::Count
                 set row1 to self::CurrentCell::RowIndex
                 set self::CurrentCell to self::Rows[row1]::Cells[col1]
              else
                 if self::CurrentCell::RowIndex not = self::Rows::Count - 1
                    perform varying col1 from 0 by 1
                       until col1 > self::CurrentCell::ColumnIndex
                       if not self::Columns[col1]::ReadOnly
                          exit perform
                       end-if
                    end-perform
                    if col1 <= self::CurrentCell::ColumnIndex
                       set row1 to self::CurrentCell::RowIndex
                       set self::CurrentCell to self::Rows[row1 1]::Cells[col1]
                    end-if
                 end-if
              end-if
              set ret-value to true
           else
              set ret-value to super::ProcessDataGridViewKey(e)
           end-if    
          goback.
      end method.      
      end class.


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

Looking good.....however :(

On entering a NON NUMERIC value into any of the cells in cols 2 & 3 and pressing the <Tab> or <Enter> key I get a box error stating...

'Operation did not succeed because the program cannot commit or quit a cell value change'

I'm sure we're getting there!!


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

This is caused by the cell validation failing and e::Cancel being set.
It won't let you change the CurrentCell if the validation fails.

You can get around this by adding a try/catch block in the ProcessDialogKey method in CustomDataGridView around the code that tries to set the CurrentCell (two places)

      method-id ProcessDialogKey override.
      local-storage section.
      01 keycode type Keys.
      01 col1 binary-long.
      01 row1 binary-long.
      procedure division using by value keyData as type Keys
                         returning ret-value as condition-value.
       *> Extract the key code from the key value.
           set keycode to keyData b-and type Keys::KeyCode
       *> Handle the ENTER key as if it were a Tab key.  
          if keycode = type Keys::Tab or keycode = type Keys::Enter
              set col1 to self::CurrentCell::ColumnIndex 1
              perform varying col1 from col1 by 1
                 until col1 >= self::Columns::Count
                 if not self::Columns[col1]::ReadOnly
                    exit perform
                 end-if
              end-perform
              if col1 < self::Columns::Count
                 set row1 to self::CurrentCell::RowIndex
                 try
                    set self::CurrentCell to self::Rows[row1]::Cells[col1]
                 catch ex as type Exception
                 end-try  
              else
                 if self::CurrentCell::RowIndex not = self::Rows::Count - 1
                    perform varying col1 from 0 by 1
                       until col1 > self::CurrentCell::ColumnIndex
                       if not self::Columns[col1]::ReadOnly
                          exit perform
                       end-if
                    end-perform
                    if col1 <= self::CurrentCell::ColumnIndex
                       set row1 to self::CurrentCell::RowIndex
                       try
                          set self::CurrentCell to self::Rows[row1 1]::Cells[col1]
                       catch ex as type Exception
                       end-try  
                    end-if
                 end-if
              end-if
             *> set ret-value to self::ProcessTabKey(keyData)
               set ret-value to true
           else
              set ret-value to super::ProcessDialogKey(keyData)
           end-if
           goback.          
      end method.


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

Cool....one more thing....

I'm assuming that the KeyDown event is being superceded by the code in the new class? Can this code be removed?

Also I'm finding that once I'm on the LAST viable cell (Row 4 col 3) and press the <RET> or <TAB> key the cursor continues onto the NEXT row down instead of looping back to Row 0 COL 2.

Without wishing to mess up the code you've written where does the check code go to force the cursor back to the first viable cell?


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

Yes, you can get rid of the KeyDown event.

Remember to remove the event itself in the Form Designer so it will not look for the event handler and then you can remove the method from the class.

I got it to wrap around from the last column of the grid control to the first non-read-only column by adding an else condition to the two overridding methods as follows:

(You should also set the AllowUserToAddRows property to false so it will not show the new row)

     class-id CustomDataGridView inherits type DataGridView.
      working-storage section.
      method-id ProcessDialogKey override.
      local-storage section.
      01 keycode type Keys.
      01 col1 binary-long.
      01 row1 binary-long.
      procedure division using by value keyData as type Keys
                         returning ret-value as condition-value.
       *> Extract the key code from the key value.
           set keycode to keyData b-and type Keys::KeyCode
       *> Handle the ENTER key as if it were a Tab key.  
          if keycode = type Keys::Tab or keycode = type Keys::Enter
              set col1 to self::CurrentCell::ColumnIndex 1
              perform varying col1 from col1 by 1
                 until col1 >= self::Columns::Count
                 if not self::Columns[col1]::ReadOnly
                    exit perform
                 end-if
              end-perform
              if col1 < self::Columns::Count
                 set row1 to self::CurrentCell::RowIndex
                 try
                    set self::CurrentCell to self::Rows[row1]::Cells[col1]
                 catch ex as type Exception
                 end-try  
              else
                 if self::CurrentCell::RowIndex not = self::Rows::Count - 1
                    perform varying col1 from 0 by 1
                       until col1 > self::CurrentCell::ColumnIndex
                       if not self::Columns[col1]::ReadOnly
                          exit perform
                       end-if
                    end-perform
                    if col1 <= self::CurrentCell::ColumnIndex
                       set row1 to self::CurrentCell::RowIndex
                       try
                          set self::CurrentCell to self::Rows[row1 1]::Cells[col1]
                       catch ex as type Exception
                       end-try  
                    end-if
                 else
                    perform varying col1 from 0 by 1
                       until col1 > self::CurrentCell::ColumnIndex
                       if not self::Columns[col1]::ReadOnly
                          exit perform
                       end-if
                    end-perform
                    if col1 <= self::CurrentCell::ColumnIndex
                       try
                          set self::CurrentCell to self::Rows[0]::Cells[col1]
                       catch ex as type Exception
                       end-try  
                    end-if
                 end-if  
              end-if
             *> set ret-value to self::ProcessTabKey(keyData)
               set ret-value to true
           else
              set ret-value to super::ProcessDialogKey(keyData)
           end-if
           goback.          
      end method.
      method-id ProcessDataGridViewKey override.
      01 col1 binary-long.
      01 row1 binary-long.
      procedure division using by value e as type KeyEventArgs
                         returning ret-value as condition-value.
       *> Handle the ENTER key as if it were a Tab key.  
          if e::KeyCode = type Keys::Tab or e::KeyCode = type Keys::Enter
              set col1 to self::CurrentCell::ColumnIndex 1
              perform varying col1 from col1 by 1
                 until col1 >= self::Columns::Count
                 if not self::Columns[col1]::ReadOnly
                    exit perform
                 end-if
              end-perform
              if col1 < self::Columns::Count
                 set row1 to self::CurrentCell::RowIndex
                 try
                    set self::CurrentCell to self::Rows[row1]::Cells[col1]
                 catch ex as type Exception
                 end-try  
              else
                 if self::CurrentCell::RowIndex not = self::Rows::Count - 1
                    perform varying col1 from 0 by 1
                       until col1 > self::CurrentCell::ColumnIndex
                       if not self::Columns[col1]::ReadOnly
                          exit perform
                       end-if
                    end-perform
                    if col1 <= self::CurrentCell::ColumnIndex
                       set row1 to self::CurrentCell::RowIndex
                       try
                          set self::CurrentCell to self::Rows[row1 1]::Cells[col1]
                       catch ex as type Exception
                       end-try  
                    end-if
                 else
                    perform varying col1 from 0 by 1
                       until col1 > self::CurrentCell::ColumnIndex
                       if not self::Columns[col1]::ReadOnly
                          exit perform
                       end-if
                    end-perform
                    if col1 <= self::CurrentCell::ColumnIndex
                       try
                          set self::CurrentCell to self::Rows[0]::Cells[col1]
                       catch ex as type Exception
                       end-try  
                    end-if
                 end-if
              end-if
              set ret-value to true
           else
              set ret-value to super::ProcessDataGridViewKey(e)
           end-if    
          goback.
      end method.      
      end class.


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

Ok...really excellent...I have ONE final thing that needs solving....(and you thought it was over :) :))

The table presented to the user contains both descriptive data (cols 0 & 1) and editible data (cols 2 & 3).

There is a flag in my data table which tells the system WHICH of cols 2 or 3 can be edited as they relate to either one type of variable or another.

I noticed that you're using the READONLY property to see if you can traverse to any given cell so I've now populated my table like so...

              invoke self::Controls::Add(mydata)

              invoke mydata::Rows::Clear()

              perform varying indexOfRow from 0 by 1 until indexOfRow > noOfDataRows     *>5

                   move zero to indexOfColumn

                   add 1 to indexOfRow giving xx

                   invoke mydata::Rows::Add("" 0.0 0.0 0.0)

                   String PAYINPUT-PAY-CODE(xx) delimited by size

                   " "                   delimited by size

                   PAYINPUT-PAY-DESC(xx) delimited by "  "

                   into   PayDesc

                   set mydata::Rows[indexOfRow]::Cells[indexOfColumn]::Value To PayDesc

                   add 1 to indexOfColumn

                   move PAYINPUT-PAY-DEF(xx)  to PayDef-S

                   set mydata::Rows[indexOfRow]::Cells[indexOfColumn]::Value To PayDef

                   add 1 to indexOfColumn

                   move PAYINPUT-HOURS(xx)    to PayHours-S

                   set mydata::Rows[indexOfRow]::Cells[indexOfColumn]::Value To PayHours

                   if PAYINPUT-PAY-TYPE(xx) = "V"

                      set mydata::Rows[indexOfRow]::Cells[indexOfColumn]::ReadOnly to True

                   else

                      set mydata::Rows[indexOfRow]::Cells[indexOfColumn]::ReadOnly to False

                   end-if

                   add 1 to indexOfColumn

                   move PAYINPUT-PAY(xx)      to PayVal-S

                   set mydata::Rows[indexOfRow]::Cells[indexOfColumn]::Value To PayVal

                   if PAYINPUT-PAY-TYPE(xx) = "F"

                      set mydata::Rows[indexOfRow]::Cells[indexOfColumn]::ReadOnly to True

                   else

                      set mydata::Rows[indexOfRow]::Cells[indexOfColumn]::ReadOnly to False

                   end-if

               end-perform.

This works perfectly and I'm now unable to edit the cells that have been marked as READONLY.

The only problem is is that when traversing the datagrid BOTH cols 2 & 3 in any given row are 'entered' and I'd like the cursor to simply traverse to the next EDITABLE cell so rather than use the Columns property to determine if a cell is READONLY or not can we make the above code reference the cell itself to determine the 'editability' of the cell?

Once I've got all this done I'll be more than happy to add a WIKI for you to detail what we've done here as I'm sure it'll help a great number of people who are new to Vis Cobol like myself!


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

Heres the rest of my WORKING STORAGE if it helps...

      01 PE1 Pic X(42) value "001Basic Salary                       1VXX".

      01 PE2 Pic X(42) value "002Big Salary                         1VXX".

      01 PE3 Pic X(42) value "003Enormous Salary                    1FXX".

      01 PE4 Pic X(42) value "004Juicy Salary                       1FXX".

      01 PE5 Pic X(42) value "005Normal Salary                      1VXX".

and the bit BEFORE I populate my datagrid as described above...

          move PE1 to PAYINPUT-PAYMENTS-ITEM(1)

          move PE2 to PAYINPUT-PAYMENTS-ITEM(2).

          move PE3 to PAYINPUT-PAYMENTS-ITEM(3).

          move PE4 to PAYINPUT-PAYMENTS-ITEM(4).

          move PE5 to PAYINPUT-PAYMENTS-ITEM(5).

          move 12345.6700 to PAYINPUT-HOURS(1), PAYINPUT-HOURS(2), PAYINPUT-HOURS(3),

                             PAYINPUT-HOURS(4), PAYINPUT-HOURS(5)

          move 1234567.99 to PAYINPUT-PAY-DEF(1), PAYINPUT-PAY-DEF(2), PAYINPUT-PAY-DEF(3),

                             PAYINPUT-PAY-DEF(4), PAYINPUT-PAY-DEF(5)

          move 1234567.99 to PAYINPUT-PAY(1), PAYINPUT-PAY(2), PAYINPUT-PAY(3),

                             PAYINPUT-PAY(4), PAYINPUT-PAY(5),

          move 5 to PAYINPUT-PAY-COUNT.

          subtract 1 from PAYINPUT-PAY-COUNT giving noOfDataRows

           move 0 to indexOfRow, indexOfColumn, xx.


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

One question, will there ever be the condition where all cells in a row will be set to read-only or will there always be an editable cell in the next row?


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

One question, will there ever be the condition where all cells in a row will be set to read-only or will there always be an editable cell in the next row?

There will ALWAYS be a SINGLE editible cell within any given row.

Cols 0, 1 & 2 will ALWAYS be read only.

Cols 3 or 4 will be editable depending on the value described earlier ('F' or 'V').

Thanks.


In setting up a datagrid I have a grid containing 5 rows and 4 colums.

I've set my first cell to be 0,0 (no problem)

Tabbing will move in an orderly function from left to right. (no problem)

I wish the <return> key to behave like the <tab> key but the <return> key currently moves DOWN the grid rather than across.

I've added code for the 'keydown' event on the grid which states....

if NOT e::KeyCode = type "System.Windows.Forms.Keys"::Return

    exit method

end-if.

set indexOfRow to mydata::CurrentCell::RowIndex.

set indexOfColumn to mydata::CurrentCell::ColumnIndex.

set mydata::CurrentCell To mydata[indexOfColumn 1 indexOfRow]

Despite this code the cursor now moves ONE cell across and ONE LINE down.

What am I missing?

 

OK, I have changed the overidden methods to search for the next non read-only cell either on the current row, the next row or the first row if wrapparound is required.

Please be aware that this only handles the case of moving forward through the grid as back-tab will not move you backwards using the same path.

Also, users can still click in a read-only cell or position to a read-only cell using the arrow keys, but they will not be able to modify the data.

Here is the new code:

      class-id CustomDataGridView inherits type DataGridView.
      working-storage section.

      method-id ProcessDialogKey override.
      local-storage section.
      01 keycode type Keys.
      01 col1 binary-long.
      01 row1 binary-long.
      procedure division using by value keyData as type Keys
                         returning ret-value as condition-value.
       *> Extract the key code from the key value.
          set keycode to keyData b-and type Keys::KeyCode
       *> Handle the ENTER key as if it were a Tab key.  
          if keycode = type Keys::Tab or keycode = type Keys::Enter
              set col1 to self::CurrentCell::ColumnIndex 1
              set row1 to self::CurrentCell::RowIndex
             *> check current row for next no read-only cell
              perform varying col1 from col1 by 1
                 until col1 >= self::Columns::Count
                 if not self::Rows[row1]::Cells[col1]::ReadOnly
                    exit perform
                 end-if
              end-perform
             *> If following true then next column is in same row
              if col1 < self::Columns::Count
                 try
                    set self::CurrentCell to self::Rows[row1]::Cells[col1]
                 catch ex as type Exception
                 end-try  
              else
                 *> check if last row
                 if self::CurrentCell::RowIndex not = self::Rows::Count - 1
                    add 1 to row1
                 else
                    move 0 to row1
                 end-if
                 *> search next row or first row for next non read-only cell
                 perform varying col1 from 0 by 1
                    until col1 > self::Columns::Count
                    if not self::Rows[row1]::Cells[col1]::ReadOnly
                       exit perform
                    end-if
                 end-perform
                 try
                    set self::CurrentCell to self::Rows[row1]::Cells[col1]
                 catch ex as type Exception
                 end-try  
              end-if
              set ret-value to true
           else    
              set ret-value to super::ProcessDialogKey(keyData)
           end-if
           goback.          
      end method.

      method-id ProcessDataGridViewKey override.
      01 col1 binary-long.
      01 row1 binary-long.
      procedure division using by value e as type KeyEventArgs
                         returning ret-value as condition-value.
       *> Handle the ENTER key as if it were a Tab key.  
          if e::KeyCode = type Keys::Tab or e::KeyCode = type Keys::Enter
              set col1 to self::CurrentCell::ColumnIndex 1
              set row1 to self::CurrentCell::RowIndex
             *> check current row for next no read-only cell
              perform varying col1 from col1 by 1
                 until col1 >= self::Columns::Count
                 if not self::Rows[row1]::Cells[col1]::ReadOnly
                    exit perform
                 end-if
              end-perform
             *> If following true then next column is in same row
              if col1 < self::Columns::Count
                 try
                    set self::CurrentCell to self::Rows[row1]::Cells[col1]
                 catch ex as type Exception
                 end-try  
              else
                 *> check if last row
                 if self::CurrentCell::RowIndex not = self::Rows::Count - 1
                    add 1 to row1
                 else
                    move 0 to row1
                 end-if
                 *> search next row or first row for next non read-only cell
                 perform varying col1 from 0 by 1
                    until col1 > self::Columns::Count
                    if not self::Rows[row1]::Cells[col1]::ReadOnly
                       exit perform
                    end-if
                 end-perform
                 try
                    set self::CurrentCell to self::Rows[row1]::Cells[col1]
                 catch ex as type Exception
                 end-try  
              end-if
              set ret-value to true
           else
              set ret-value to super::ProcessDataGridViewKey(e)
           end-if    
          goback.
      end method.      
      end class.