Closed abdulrehmananwar closed 3 weeks ago
Hi @abdulrehmananwar ,
Based on the details provided, we have modified the sample to meet your expectations. In the updated sample, when you press the up or down arrow keys, the focus remains on the DataGrid, and scrolling occurs according to the current selection. Additionally, the TextField has been implemented to facilitate filtering within the DataGrid.
We’ve included a modified sample for your reference. Please review it for further details.
Regards, Abinesh P
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart';
void main() { runApp(const MaterialApp( home: MyHomePage(), )); }
class MyHomePage extends StatelessWidget { const MyHomePage({super.key});
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Dialog with DataGrid'), ), body: Center( child: ElevatedButton( onPressed: () { showDialog( context: context, builder: (context) { return const DataGridDialog(); }, ); }, child: const Text('Open Dialog'), ), ), ); } }
class DataGridDialog extends StatefulWidget { const DataGridDialog({super.key});
@override _DataGridDialogState createState() => _DataGridDialogState(); }
class _DataGridDialogState extends State
@override void initState() { super.initState(); _employees = getEmployees(); employeeDataSource = EmployeeDataSource(_employees);
// Set default selected index and focus on the DataGrid and TextField when dialog opens.
WidgetsBinding.instance.addPostFrameCallback((_) {
_dataGridController.selectedIndex = _currentSelectedIndex;
_dataGridController.scrollToRow(_currentSelectedIndex.toDouble());
_textFieldFocusNode.requestFocus(); // Focus on the TextField
});
}
@override void dispose() { _textController.dispose(); _dataGridFocusNode.dispose(); _textFieldFocusNode.dispose(); _dataGridController.dispose(); super.dispose(); }
void _handleKeyEvent(RawKeyEvent event) { if (event is RawKeyDownEvent) { // Only intercept arrow keys while TextField is focused if (_textFieldFocusNode.hasFocus) { if (event.logicalKey == LogicalKeyboardKey.arrowDown) { _moveSelection(1); } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) { // Move the cursor to the end of the TextField when up arrow is pressed print('going cursor to last'); // Move the cursor to the end of the TextField when up arrow is pressed Future.delayed(Duration(milliseconds: 5), () { _textController.selection = TextSelection.fromPosition( TextPosition(offset: _textController.text.length), ); }); _moveSelection(-1); } } } }
void _moveSelection(int offset) { setState(() { _currentSelectedIndex += offset; _currentSelectedIndex = _currentSelectedIndex.clamp(0, _employees.length - 1); _dataGridController.selectedIndex = _currentSelectedIndex; _dataGridController.scrollToRow(_currentSelectedIndex.toDouble()); }); }
@override Widget build(BuildContext context) { return AlertDialog( title: const Text('DataGrid Dialog'), content: SizedBox( width: 600, height: 400, child: RawKeyboardListener( focusNode: _dataGridFocusNode, onKey: _handleKeyEvent, child: Column( children: [ Padding( padding: const EdgeInsets.all(8.0), child: TextField( controller: _textController, focusNode: _textFieldFocusNode, decoration: const InputDecoration(labelText: 'Type to filter...'), onChanged: (value) { // Apply filtering to the name column. employeeDataSource.clearFilters(columnName: 'name'); if (value.isNotEmpty) { employeeDataSource.addFilter( 'name', FilterCondition( type: FilterType.contains, filterBehavior: FilterBehavior.stringDataType, value: value)); } // To refresh the DataGrid. employeeDataSource.updateDataGriDataSource(); // Clear selection. _dataGridController.selectedIndex = -1; // Reset to the first filtered row. _currentSelectedIndex = 0; _dataGridController.selectedIndex = _currentSelectedIndex; _dataGridController.scrollToRow(_currentSelectedIndex.toDouble()); }, inputFormatters: [ FilteringTextInputFormatter.deny(RegExp("[\n\r]")), ], ), ), Expanded( child: SfDataGrid( source: employeeDataSource, controller: _dataGridController, selectionMode: SelectionMode.single, columnWidthMode: ColumnWidthMode.fill, columns: [ GridColumn( columnName: 'id', label: Container( padding: const EdgeInsets.all(8.0), alignment: Alignment.center, child: const Text('ID'), ), ), GridColumn( columnName: 'name', label: Container( padding: const EdgeInsets.all(8.0), alignment: Alignment.center, child: const Text('Name'), ), ), GridColumn( columnName: 'designation', label: Container( padding: const EdgeInsets.all(8.0), alignment: Alignment.center, child: const Text('Designation'), ), ), ], ), ), ], ), ), ), actions: [ TextButton( onPressed: () { Navigator.of(context).pop(); }, child: const Text('Close'), ), ], ); } }
// Data model for the Employee class Employee { Employee(this.id, this.name, this.designation); final int id; final String name; final String designation; }
// DataSource class for DataGrid class EmployeeDataSource extends DataGridSource { EmployeeDataSource(this.employees) { dataGridRows = employees .map((e) => DataGridRow(cells: [ DataGridCell(columnName: 'id', value: e.id), DataGridCell(columnName: 'name', value: e.name), DataGridCell(columnName: 'designation', value: e.designation), ])) .toList(); }
List
@override
List
@override DataGridRowAdapter buildRow(DataGridRow row) { return DataGridRowAdapter( cells: row.getCells().map((dataGridCell) { return Container( alignment: Alignment.center, padding: const EdgeInsets.all(8.0), child: Text(dataGridCell.value.toString()), ); }).toList(), ); }
void updateDataGriDataSource() { notifyListeners(); } }
// Sample data for employees (30 rows)
List
I have made significant improvements to the code you provided. However, there’s one remaining issue: when I press the down arrow key, the grid scrolls each time, causing the previous row to become invisible. The scrolling should only occur when the selection reaches the last row, similar to how a standard focused GridView behaves.
Hi @abdulrehmananwar ,
Based on the information provided, we have modified the sample to meet your requirements. In the SfDataGrid, you can obtain the starting and ending indices of the visible rows using the DataGridController.getVisibleRowStartIndex and DataGridController.getVisibleRowEndIndex methods, respectively, by specifying the required RowRegion. We have restricted scrolling when the down arrow key is pressed, so scrolling will only occur when the selection reaches the last visible row. We have included a sample for your reference. Please review it for further details.
Regards, Abinesh P
Thanks for sharing the sample code. However, I'm using this in a Windows app, and when I press the up or down key once, it navigates twice instead of once. Can you help me fix this?
https://github.com/user-attachments/assets/ef8c488a-df62-4ed5-8982-8b6a898e6a2d
I noticed an issue: when I press the arrow key once, it behaves as if I've pressed it twice.
Hi @abdulrehmananwar ,
The issue you're encountering, where pressing the down arrow key triggers two actions instead of one, may be due to the KeyboardListener responding to both the key down and key up events. In Flutter, a single key press can generate multiple events: one when the key is pressed down and another when it's released. To address this, modify the event handler to check the type of key event being received, and ensure that you only respond to the key down event.
However, note that the KeyDownEvent does not fire continuously when a key is held down. Flutter triggers the KeyDownEvent only once for a single press. To detect continuous key presses, you also need to handle both KeyDownEvent and KeyRepeatEvent. We have included a sample for your reference. Please review it for further details.
Regards, Abinesh P
Hi @abdulrehmananwar,
We suspect that the reported issue has been resolved at your end. Hence, we are closing this issue. If you need any further assistance, please reopen this. We are always happy to help.
Regards, Ashok K
Use case
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart';
class TextFieldAndDataGrid extends StatefulWidget { @override _TextFieldAndDataGridState createState() => _TextFieldAndDataGridState(); }
class _TextFieldAndDataGridState extends State {
final TextEditingController _textController = TextEditingController();
final FocusNode _dataGridFocusNode = FocusNode(); // FocusNode for DataGrid
final DataGridController _dataGridController = DataGridController();
List _employees = [];
int _currentSelectedIndex = 0;
@override void initState() { super.initState();
}
@override void dispose() { _textController.dispose(); _dataGridFocusNode.dispose(); _dataGridController.dispose(); super.dispose(); }
@override Widget build(BuildContext context) { return Scaffold( body: RawKeyboardListener( focusNode: _dataGridFocusNode, // Focus on DataGrid for keyboard events onKey: (RawKeyEvent event) { if (event is RawKeyDownEvent) { if (event.logicalKey == LogicalKeyboardKey.arrowDown) { // Move to the next row if possible if (_currentSelectedIndex < _employees.length - 1) { _currentSelectedIndex++; _dataGridController.selectedIndex = _currentSelectedIndex; _dataGridController.scrollToRow(_currentSelectedIndex.toDouble()); _updateTextField('ArrowDown'); // Reflect keypress in TextField } } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) { // Move to the previous row if possible if (_currentSelectedIndex > 0) { _currentSelectedIndex--; _dataGridController.selectedIndex = _currentSelectedIndex; _dataGridController.scrollToRow(_currentSelectedIndex.toDouble()); _updateTextField('ArrowUp'); // Reflect keypress in TextField } } else { // For any other key pressed, reflect the key in the TextField _updateTextField(event.logicalKey.keyLabel); } } }, child: Column( children: [ Padding( padding: const EdgeInsets.all(8.0), child: TextField( controller: _textController, decoration: InputDecoration(labelText: 'Keypresses will show here'), readOnly: true, // Make the TextField read-only so we control input ), ), Expanded( child: SfDataGrid( source: EmployeeDataSource(_employees), controller: _dataGridController, selectionMode: SelectionMode.single, columns:[
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.all(8.0),
alignment: Alignment.center,
child: Text('ID'),
),
),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.all(8.0),
alignment: Alignment.center,
child: Text('Name'),
),
),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.all(8.0),
alignment: Alignment.center,
child: Text('Designation'),
),
),
],
),
),
],
),
),
);
}
// Update the TextField with the key pressed void _updateTextField(String key) { setState(() { _textController.text = key; }); } }
// Data model for the Employee class Employee { Employee(this.id, this.name, this.designation); final int id; final String name; final String designation; }
// DataSource class for DataGrid class EmployeeDataSource extends DataGridSource { EmployeeDataSource(this.employees) { dataGridRows = employees .map((e) => DataGridRow(cells: [
DataGridCell(columnName: 'id', value: e.id),
DataGridCell(columnName: 'name', value: e.name),
DataGridCell(columnName: 'designation', value: e.designation),
]))
.toList();
}
List dataGridRows = [];
List employees = [];
@override List get rows => dataGridRows;
@override DataGridRowAdapter buildRow(DataGridRow row) { return DataGridRowAdapter( cells: row.getCells().map((dataGridCell) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(8.0),
child: Text(dataGridCell.value.toString()),
);
}).toList(),
);
}
}
// Sample data for employees (30 rows) List getEmployees() {
return List.generate(30, (index) => Employee(index + 1, 'Employee $index', 'Designation $index'));
}
Proposal
https://github.com/user-attachments/assets/e1db6017-63bc-4446-877e-b7a6b3838fb5
i want basically same pattren like when dialog is open there is one textfield and one gridview what is want is 1- when dialog open default datagridview first row selected. also which key i press it inputing the data into textfield 2- when i click arrow up or arrow down same time my datagridview row focus is moving 3- it also scrolling if arrow is going doing and same time if i press any keyboard keyword same time its also typing and filtering.