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.