英文:
Multi-row editing table Flutter
问题
我在Flutter中尝试进行表格的多行编辑,找到了我需要的内容,但是它是用Javascript写的。我想知道在Flutter中是否有一种“简单”的方法来实现相同的功能。
我的Javascript示例:https://editor.datatables.net/examples/simple/multiRow
英文:
I'm struggling to do a multi row edit on a table in flutter, I found exactly what I need, but it's in Javascript. I wonder if there is an "easy" way to do the same thing in Flutter.
My example in Javascript: https://editor.datatables.net/examples/simple/multiRow
答案1
得分: 1
这是一个可编辑的表格小部件的代码。以下是代码的主要部分的翻译:
class EditableTable extends StatefulWidget {
EditableTable({
required this.rapport,
required this.rapportIndex,
});
final rapport;
final rapportIndex;
@override
_EditableTableState createState() => _EditableTableState();
}
class _EditableTableState extends State<EditableTable> {
List<DataRow> rows = [];
final ScrollController _scrollController = ScrollController();
List<int> selectedLignes = [];
bool tableauModifie = false;
late List<Map<String, dynamic>> _tableau;
void saveTable(List<Map<String, dynamic>> newTable, int rapportIndex) async {
// 保存表格数据到 Firestore
}
@override
void initState() {
// 初始化表格数据
}
@override
Widget build(BuildContext context) {
// 构建用户界面
}
// 其他方法和小部件在这里...
}
这段代码是一个可编辑的表格小部件,可以用于显示和编辑表格数据。它包括了初始化数据、保存数据到 Firestore 和构建用户界面的部分。如果您需要进一步了解代码的具体功能,请随时提出问题。
英文:
I have made this code and this is working :), I don't know if it's ugly or not, but is that can help someone. I give no details but if someone have a question I'l try to awnser it :
class EditableTable extends StatefulWidget {
EditableTable({
required this.rapport,
required this.rapportIndex,
});
final rapport;
final rapportIndex;
@override
_EditableTableState createState() => _EditableTableState();
}
class _EditableTableState extends State<EditableTable> {
List<DataRow> rows = [];
final ScrollController _scrollController = ScrollController();
List<int> selectedLignes = [];
bool tableauModifie = false;
late List<Map<String, dynamic>> _tableau;
void saveTable(List<Map<String, dynamic>> newTable, int rapportIndex) async {
try {
final String rapportId = globals.gRapportEnCours![rapportIndex]['id'];
await FirebaseFirestore.instance
.collection("rapports")
.doc(rapportId)
.update({
'tableau': newTable,
'date_modification': DateTime.now(),
});
globals.gRapportEnCours![rapportIndex]['tableau'] = newTable;
} catch (e) {
print("Erreur lors de la sauvegarde du tableau: $e");
}
}
@override
void initState() {
super.initState();
_tableau = List<Map<String, dynamic>>.from(widget.rapport['tableau']);
rows = _tableau.asMap().entries.map<DataRow>((entry) {
int index = entry.key;
Map<String, dynamic> ligne = entry.value;
return DataRow(cells: [
DataCell(Text(ligne['N° trou'].toString())),
DataCell(TextFormField(
readOnly: widget.rapport['is_valid'],
initialValue: ligne['Profondeur'],
onChanged: (value) {
setState(() {
_tableau[index]['Profondeur'] = value;
tableauModifie = true;
});
saveTable(_tableau, widget.rapportIndex);
},
)),
DataCell(TextFormField(
readOnly: widget.rapport['is_valid'],
initialValue: ligne['Inclinaison'],
onChanged: (value) {
setState(() {
_tableau[index]['Inclinaison'] = value;
tableauModifie = true;
});
saveTable(_tableau, widget.rapportIndex);
},
)),
DataCell(TextFormField(
readOnly: widget.rapport['is_valid'],
initialValue: ligne['N° taillant'],
onChanged: (value) {
setState(() {
_tableau[index]['N° taillant'] = value;
tableauModifie = true;
});
saveTable(_tableau, widget.rapportIndex);
},
)),
DataCell(
TextFormField(
readOnly: widget.rapport['is_valid'],
initialValue: ligne['Observation'],
onChanged: (value) {
setState(() {
_tableau[index]['Observation'] = value;
tableauModifie = true;
});
saveTable(_tableau, widget.rapportIndex);
},
),
),
]);
}).toList();
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
SingleChildScrollView(
controller: _scrollController,
child: Column(
children: [
SizedBox(
width: 800,
height: 540,
child: SingleChildScrollView(
child: Column(children: [
DataTable(
columns: [
DataColumn(
label: Text('N° trou'),
),
DataColumn(
label: Text('Profondeur'),
),
DataColumn(
label: Text('Inclinaison'),
),
DataColumn(
label: Text('N° taillant'),
),
DataColumn(
label: Text('Observation'),
),
],
rows: rows.map<DataRow>((row) {
final index = rows.indexOf(row);
return DataRow(
selected: widget.rapport['is_valid']
? false
: selectedLignes.contains(index),
onSelectChanged: widget.rapport['is_valid']
? null
: (value) {
setState(() {
if (value!) {
selectedLignes.add(index);
} else {
selectedLignes.remove(index);
}
});
},
cells: row.cells,
);
}).toList(),
),
if (!widget.rapport['is_valid'])
ElevatedButton(
onPressed: () => setState(() {
int newNumTrou = widget.rapport['tableau']
[widget.rapport['tableau'].length - 1]
['N° trou'] +
1;
widget.rapport['tableau'].add({
'N° trou': newNumTrou,
'Profondeur': '',
'Inclinaison': '',
'N° taillant': '',
'Observation': '',
});
rows.add(
DataRow(
cells: List.generate(
5,
(index) => DataCell(
index == 0
? Text('$newNumTrou')
: TextFormField(
readOnly: widget.rapport['is_valid'],
initialValue: '',
),
),
),
),
);
}),
child: Text('Ajouter une ligne'),
),
]),
),
),
],
),
),
if (!widget.rapport['is_valid'])
Positioned(
right: 5.0,
child: FloatingActionButton(
onPressed: selectedLignes.isEmpty ? null : editSelectedLignes,
child: Icon(Icons.edit),
),
),
],
);
}
Map<String, dynamic> getCommonValues(List<int> selectedLignes) {
Map<String, dynamic> commonValues =
Map.from(_tableau[selectedLignes.first]);
for (int i = 1; i < selectedLignes.length; i++) {
Map<String, dynamic> currentLigne = _tableau[selectedLignes[i]];
for (String key in commonValues.keys.toList()) {
if (commonValues[key] != currentLigne[key]) {
commonValues[key] = 'Valeurs multiples';
}
}
}
return commonValues;
}
void editSelectedLignes() {
// Vérifie si des lignes sont sélectionnées
if (selectedLignes.isEmpty) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Aucune ligne sélectionnée'),
content: Text('Veuillez sélectionner au moins une ligne à éditer.'),
actions: [
ElevatedButton(
onPressed: () => Navigator.pop(context),
child: Text('OK'),
),
],
),
);
} else {
Map<String, dynamic> commonValues = getCommonValues(selectedLignes) ??
{
'Profondeur': '',
'Inclinaison': '',
'N° taillant': '',
'Observation': '',
};
// Ouvre la pop-up d'édition
showDialog(
context: context,
builder: (context) => EditLignesDialog(
selectedLignes: selectedLignes,
tableau: _tableau,
saveTable: saveTable,
selectedLigneValues: commonValues,
rapportIndex: widget.rapportIndex,
),
).then((value) {
if (value != null && value) {
// Vérifiez si 'value' est 'true'
setState(() {
updateRows();
});
}
});
}
}
void updateRows() {
rows = List<DataRow>.generate(
_tableau.length,
(index) {
Map<String, dynamic> ligne = _tableau[index];
return DataRow(
cells: [
DataCell(
Text('${ligne['N° trou']}'),
),
DataCell(TextField(
enabled: !widget.rapport['is_valid'],
controller:
TextEditingController(text: '${ligne['Profondeur']}'),
onChanged: (value) => ligne['Profondeur'] = value)),
DataCell(TextField(
enabled: !widget.rapport['is_valid'],
controller:
TextEditingController(text: '${ligne['Inclinaison']}'),
onChanged: (value) => ligne['Inclinaison'] = value)),
DataCell(TextField(
enabled: !widget.rapport['is_valid'],
controller:
TextEditingController(text: '${ligne['N° taillant']}'),
onChanged: (value) => ligne['N° taillant'] = value)),
DataCell(TextField(
enabled: !widget.rapport['is_valid'],
controller:
TextEditingController(text: '${ligne['Observation']}'),
onChanged: (value) => ligne['Observation'] = value)),
],
onSelectChanged: (bool? value) {
setState(() {
selectedLignes.contains(index)
? selectedLignes.remove(index)
: selectedLignes.add(index);
});
},
);
},
);
}
}
class EditLignesDialog extends StatefulWidget {
final List<int> selectedLignes;
final List<Map<String, dynamic>> tableau;
final Function(List<Map<String, dynamic>>, int) saveTable;
final Map<String, dynamic> selectedLigneValues;
final int rapportIndex;
EditLignesDialog({
required this.selectedLignes,
required this.tableau,
required this.saveTable,
required this.selectedLigneValues,
required this.rapportIndex,
});
@override
_EditLignesDialogState createState() => _EditLignesDialogState();
}
class _EditLignesDialogState extends State<EditLignesDialog> {
final _formKey = GlobalKey<FormState>();
late TextEditingController profondeurController;
late TextEditingController inclinaisonController;
late TextEditingController numTaillantController;
late TextEditingController observationController;
bool profondeurMultipleValues = false;
bool inclinaisonMultipleValues = false;
bool numTaillantMultipleValues = false;
bool observationMultipleValues = false;
@override
void initState() {
super.initState();
profondeurController = TextEditingController(
text: widget.selectedLigneValues['Profondeur'] == 'Valeurs multiples'
? ''
: widget.selectedLigneValues['Profondeur']);
inclinaisonController = TextEditingController(
text: widget.selectedLigneValues['Inclinaison'] == 'Valeurs multiples'
? ''
: widget.selectedLigneValues['Inclinaison']);
numTaillantController = TextEditingController(
text: widget.selectedLigneValues['N° taillant'] == 'Valeurs multiples'
? ''
: widget.selectedLigneValues['N° taillant']);
observationController = TextEditingController(
text: widget.selectedLigneValues['Observation'] == 'Valeurs multiples'
? ''
: widget.selectedLigneValues['Observation']);
profondeurMultipleValues = hasMultipleValues("Profondeur");
inclinaisonMultipleValues = hasMultipleValues("Inclinaison");
numTaillantMultipleValues = hasMultipleValues("N° taillant");
observationMultipleValues = hasMultipleValues("Observation");
}
bool hasMultipleValues(String key) {
String? firstValue;
for (int index in widget.selectedLignes) {
Map<String, dynamic> ligne = widget.tableau[index];
if (firstValue == null) {
firstValue = ligne[key];
} else if (ligne[key] != firstValue) {
return true;
}
}
return false;
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Editer Ligne'),
content: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: profondeurController,
decoration: InputDecoration(
labelText: 'Profondeur',
hintText: widget.selectedLigneValues['Profondeur'] ==
'Valeurs multiples'
? 'Valeurs multiples'
: null,
),
validator: (value) {
if (!profondeurMultipleValues && (value == null)) {
return 'Merci de rentrer une profondeur';
}
return null;
},
),
TextFormField(
controller: inclinaisonController,
decoration: InputDecoration(
labelText: 'Inclinaison',
hintText: widget.selectedLigneValues['Inclinaison'] ==
'Valeurs multiples'
? 'Valeurs multiples'
: null,
),
validator: (value) {
if (!inclinaisonMultipleValues && (value == null)) {
return 'Merci d\'entrer une inclinaison';
}
return null;
},
),
TextFormField(
controller: numTaillantController,
decoration: InputDecoration(
labelText: 'N° taillant',
hintText: widget.selectedLigneValues['N° taillant'] ==
'Valeurs multiples'
? 'Valeurs multiples'
: null,
),
validator: (value) {
if (!numTaillantMultipleValues && (value == null)) {
return 'Merci d\'entrer un numéro de taillant';
}
return null;
},
),
TextFormField(
controller: observationController,
decoration: InputDecoration(
labelText: 'Observation',
hintText: widget.selectedLigneValues['Observation'] ==
'Valeurs multiples'
? 'Valeurs multiples'
: null,
),
validator: (value) {
if (!observationMultipleValues && (value == null)) {
return 'Merci de rentrer une observation';
}
return null;
},
),
],
),
),
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Annuler'),
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
bool updated = editLignes();
Navigator.pop(context,
updated); // Renvoie 'true' si les modifications ont été effectuées
}
},
child: Text('Sauvegarder'),
),
],
);
}
bool editLignes() {
for (int index in widget.selectedLignes) {
Map<String, dynamic> ligne = widget.tableau[index];
ligne['Profondeur'] =
profondeurMultipleValues && profondeurController.text.isEmpty
? ligne['Profondeur']
: profondeurController.text;
ligne['Inclinaison'] =
inclinaisonMultipleValues && inclinaisonController.text.isEmpty
? ligne['Inclinaison']
: inclinaisonController.text;
ligne['N° taillant'] =
numTaillantMultipleValues && numTaillantController.text.isEmpty
? ligne['N° taillant']
: numTaillantController.text;
ligne['Observation'] =
observationMultipleValues && observationController.text.isEmpty
? ligne['Observation']
: observationController.text;
}
widget.saveTable(widget.tableau, widget.rapportIndex);
return true; // Retourne 'true' pour indiquer que les modifications ont été effectuées
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论