多行编辑表格 Flutter

huangapple go评论150阅读模式
英文:

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() =&gt; _EditableTableState();
}

class _EditableTableState extends State&lt;EditableTable&gt; {
  List&lt;DataRow&gt; rows = [];
  final ScrollController _scrollController = ScrollController();
  List&lt;int&gt; selectedLignes = [];
  bool tableauModifie = false;
  late List&lt;Map&lt;String, dynamic&gt;&gt; _tableau;

  void saveTable(List&lt;Map&lt;String, dynamic&gt;&gt; newTable, int rapportIndex) async {
    try {
      final String rapportId = globals.gRapportEnCours![rapportIndex][&#39;id&#39;];
      await FirebaseFirestore.instance
          .collection(&quot;rapports&quot;)
          .doc(rapportId)
          .update({
        &#39;tableau&#39;: newTable,
        &#39;date_modification&#39;: DateTime.now(),
      });

      globals.gRapportEnCours![rapportIndex][&#39;tableau&#39;] = newTable;
    } catch (e) {
      print(&quot;Erreur lors de la sauvegarde du tableau: $e&quot;);
    }
  }

  @override
  void initState() {
    super.initState();
    _tableau = List&lt;Map&lt;String, dynamic&gt;&gt;.from(widget.rapport[&#39;tableau&#39;]);
    rows = _tableau.asMap().entries.map&lt;DataRow&gt;((entry) {
      int index = entry.key;
      Map&lt;String, dynamic&gt; ligne = entry.value;

      return DataRow(cells: [
        DataCell(Text(ligne[&#39;N&#176; trou&#39;].toString())),
        DataCell(TextFormField(
          readOnly: widget.rapport[&#39;is_valid&#39;],
          initialValue: ligne[&#39;Profondeur&#39;],
          onChanged: (value) {
            setState(() {
              _tableau[index][&#39;Profondeur&#39;] = value;
              tableauModifie = true;
            });
            saveTable(_tableau, widget.rapportIndex);
          },
        )),
        DataCell(TextFormField(
          readOnly: widget.rapport[&#39;is_valid&#39;],
          initialValue: ligne[&#39;Inclinaison&#39;],
          onChanged: (value) {
            setState(() {
              _tableau[index][&#39;Inclinaison&#39;] = value;
              tableauModifie = true;
            });
            saveTable(_tableau, widget.rapportIndex);
          },
        )),
        DataCell(TextFormField(
          readOnly: widget.rapport[&#39;is_valid&#39;],
          initialValue: ligne[&#39;N&#176; taillant&#39;],
          onChanged: (value) {
            setState(() {
              _tableau[index][&#39;N&#176; taillant&#39;] = value;
              tableauModifie = true;
            });
            saveTable(_tableau, widget.rapportIndex);
          },
        )),
        DataCell(
          TextFormField(
            readOnly: widget.rapport[&#39;is_valid&#39;],
            initialValue: ligne[&#39;Observation&#39;],
            onChanged: (value) {
              setState(() {
                _tableau[index][&#39;Observation&#39;] = 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(&#39;N&#176; trou&#39;),
                        ),
                        DataColumn(
                          label: Text(&#39;Profondeur&#39;),
                        ),
                        DataColumn(
                          label: Text(&#39;Inclinaison&#39;),
                        ),
                        DataColumn(
                          label: Text(&#39;N&#176; taillant&#39;),
                        ),
                        DataColumn(
                          label: Text(&#39;Observation&#39;),
                        ),
                      ],
                      rows: rows.map&lt;DataRow&gt;((row) {
                        final index = rows.indexOf(row);
                        return DataRow(
                          selected: widget.rapport[&#39;is_valid&#39;]
                              ? false
                              : selectedLignes.contains(index),
                          onSelectChanged: widget.rapport[&#39;is_valid&#39;]
                              ? null
                              : (value) {
                                  setState(() {
                                    if (value!) {
                                      selectedLignes.add(index);
                                    } else {
                                      selectedLignes.remove(index);
                                    }
                                  });
                                },
                          cells: row.cells,
                        );
                      }).toList(),
                    ),
                    if (!widget.rapport[&#39;is_valid&#39;])
                      ElevatedButton(
                        onPressed: () =&gt; setState(() {
                          int newNumTrou = widget.rapport[&#39;tableau&#39;]
                                      [widget.rapport[&#39;tableau&#39;].length - 1]
                                  [&#39;N&#176; trou&#39;] +
                              1;
                          widget.rapport[&#39;tableau&#39;].add({
                            &#39;N&#176; trou&#39;: newNumTrou,
                            &#39;Profondeur&#39;: &#39;&#39;,
                            &#39;Inclinaison&#39;: &#39;&#39;,
                            &#39;N&#176; taillant&#39;: &#39;&#39;,
                            &#39;Observation&#39;: &#39;&#39;,
                          });
                          rows.add(
                            DataRow(
                              cells: List.generate(
                                5,
                                (index) =&gt; DataCell(
                                  index == 0
                                      ? Text(&#39;$newNumTrou&#39;)
                                      : TextFormField(
                                          readOnly: widget.rapport[&#39;is_valid&#39;],
                                          initialValue: &#39;&#39;,
                                        ),
                                ),
                              ),
                            ),
                          );
                        }),
                        child: Text(&#39;Ajouter une ligne&#39;),
                      ),
                  ]),
                ),
              ),
            ],
          ),
        ),
        if (!widget.rapport[&#39;is_valid&#39;])
          Positioned(
            right: 5.0,
            child: FloatingActionButton(
              onPressed: selectedLignes.isEmpty ? null : editSelectedLignes,
              child: Icon(Icons.edit),
            ),
          ),
      ],
    );
  }

  Map&lt;String, dynamic&gt; getCommonValues(List&lt;int&gt; selectedLignes) {
    Map&lt;String, dynamic&gt; commonValues =
        Map.from(_tableau[selectedLignes.first]);

    for (int i = 1; i &lt; selectedLignes.length; i++) {
      Map&lt;String, dynamic&gt; currentLigne = _tableau[selectedLignes[i]];

      for (String key in commonValues.keys.toList()) {
        if (commonValues[key] != currentLigne[key]) {
          commonValues[key] = &#39;Valeurs multiples&#39;;
        }
      }
    }

    return commonValues;
  }

  void editSelectedLignes() {
    // V&#233;rifie si des lignes sont s&#233;lectionn&#233;es
    if (selectedLignes.isEmpty) {
      showDialog(
        context: context,
        builder: (context) =&gt; AlertDialog(
          title: Text(&#39;Aucune ligne s&#233;lectionn&#233;e&#39;),
          content: Text(&#39;Veuillez s&#233;lectionner au moins une ligne &#224; &#233;diter.&#39;),
          actions: [
            ElevatedButton(
              onPressed: () =&gt; Navigator.pop(context),
              child: Text(&#39;OK&#39;),
            ),
          ],
        ),
      );
    } else {
      Map&lt;String, dynamic&gt; commonValues = getCommonValues(selectedLignes) ??
          {
            &#39;Profondeur&#39;: &#39;&#39;,
            &#39;Inclinaison&#39;: &#39;&#39;,
            &#39;N&#176; taillant&#39;: &#39;&#39;,
            &#39;Observation&#39;: &#39;&#39;,
          };

      // Ouvre la pop-up d&#39;&#233;dition
      showDialog(
        context: context,
        builder: (context) =&gt; EditLignesDialog(
          selectedLignes: selectedLignes,
          tableau: _tableau,
          saveTable: saveTable,
          selectedLigneValues: commonValues,
          rapportIndex: widget.rapportIndex,
        ),
      ).then((value) {
        if (value != null &amp;&amp; value) {
          // V&#233;rifiez si &#39;value&#39; est &#39;true&#39;
          setState(() {
            updateRows();
          });
        }
      });
    }
  }

  void updateRows() {
    rows = List&lt;DataRow&gt;.generate(
      _tableau.length,
      (index) {
        Map&lt;String, dynamic&gt; ligne = _tableau[index];
        return DataRow(
          cells: [
            DataCell(
              Text(&#39;${ligne[&#39;N&#176; trou&#39;]}&#39;),
            ),
            DataCell(TextField(
                enabled: !widget.rapport[&#39;is_valid&#39;],
                controller:
                    TextEditingController(text: &#39;${ligne[&#39;Profondeur&#39;]}&#39;),
                onChanged: (value) =&gt; ligne[&#39;Profondeur&#39;] = value)),
            DataCell(TextField(
                enabled: !widget.rapport[&#39;is_valid&#39;],
                controller:
                    TextEditingController(text: &#39;${ligne[&#39;Inclinaison&#39;]}&#39;),
                onChanged: (value) =&gt; ligne[&#39;Inclinaison&#39;] = value)),
            DataCell(TextField(
                enabled: !widget.rapport[&#39;is_valid&#39;],
                controller:
                    TextEditingController(text: &#39;${ligne[&#39;N&#176; taillant&#39;]}&#39;),
                onChanged: (value) =&gt; ligne[&#39;N&#176; taillant&#39;] = value)),
            DataCell(TextField(
                enabled: !widget.rapport[&#39;is_valid&#39;],
                controller:
                    TextEditingController(text: &#39;${ligne[&#39;Observation&#39;]}&#39;),
                onChanged: (value) =&gt; ligne[&#39;Observation&#39;] = value)),
          ],
          onSelectChanged: (bool? value) {
            setState(() {
              selectedLignes.contains(index)
                  ? selectedLignes.remove(index)
                  : selectedLignes.add(index);
            });
          },
        );
      },
    );
  }
}

class EditLignesDialog extends StatefulWidget {
  final List&lt;int&gt; selectedLignes;
  final List&lt;Map&lt;String, dynamic&gt;&gt; tableau;
  final Function(List&lt;Map&lt;String, dynamic&gt;&gt;, int) saveTable;
  final Map&lt;String, dynamic&gt; selectedLigneValues;
  final int rapportIndex;

  EditLignesDialog({
    required this.selectedLignes,
    required this.tableau,
    required this.saveTable,
    required this.selectedLigneValues,
    required this.rapportIndex,
  });

  @override
  _EditLignesDialogState createState() =&gt; _EditLignesDialogState();
}

class _EditLignesDialogState extends State&lt;EditLignesDialog&gt; {
  final _formKey = GlobalKey&lt;FormState&gt;();

  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[&#39;Profondeur&#39;] == &#39;Valeurs multiples&#39;
            ? &#39;&#39;
            : widget.selectedLigneValues[&#39;Profondeur&#39;]);
    inclinaisonController = TextEditingController(
        text: widget.selectedLigneValues[&#39;Inclinaison&#39;] == &#39;Valeurs multiples&#39;
            ? &#39;&#39;
            : widget.selectedLigneValues[&#39;Inclinaison&#39;]);
    numTaillantController = TextEditingController(
        text: widget.selectedLigneValues[&#39;N&#176; taillant&#39;] == &#39;Valeurs multiples&#39;
            ? &#39;&#39;
            : widget.selectedLigneValues[&#39;N&#176; taillant&#39;]);
    observationController = TextEditingController(
        text: widget.selectedLigneValues[&#39;Observation&#39;] == &#39;Valeurs multiples&#39;
            ? &#39;&#39;
            : widget.selectedLigneValues[&#39;Observation&#39;]);

    profondeurMultipleValues = hasMultipleValues(&quot;Profondeur&quot;);
    inclinaisonMultipleValues = hasMultipleValues(&quot;Inclinaison&quot;);
    numTaillantMultipleValues = hasMultipleValues(&quot;N&#176; taillant&quot;);
    observationMultipleValues = hasMultipleValues(&quot;Observation&quot;);
  }

  bool hasMultipleValues(String key) {
    String? firstValue;
    for (int index in widget.selectedLignes) {
      Map&lt;String, dynamic&gt; 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(&#39;Editer Ligne&#39;),
      content: SingleChildScrollView(
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              TextFormField(
                controller: profondeurController,
                decoration: InputDecoration(
                  labelText: &#39;Profondeur&#39;,
                  hintText: widget.selectedLigneValues[&#39;Profondeur&#39;] ==
                          &#39;Valeurs multiples&#39;
                      ? &#39;Valeurs multiples&#39;
                      : null,
                ),
                validator: (value) {
                  if (!profondeurMultipleValues &amp;&amp; (value == null)) {
                    return &#39;Merci de rentrer une profondeur&#39;;
                  }
                  return null;
                },
              ),
              TextFormField(
                controller: inclinaisonController,
                decoration: InputDecoration(
                  labelText: &#39;Inclinaison&#39;,
                  hintText: widget.selectedLigneValues[&#39;Inclinaison&#39;] ==
                          &#39;Valeurs multiples&#39;
                      ? &#39;Valeurs multiples&#39;
                      : null,
                ),
                validator: (value) {
                  if (!inclinaisonMultipleValues &amp;&amp; (value == null)) {
                    return &#39;Merci d\&#39;entrer une inclinaison&#39;;
                  }
                  return null;
                },
              ),
              TextFormField(
                controller: numTaillantController,
                decoration: InputDecoration(
                  labelText: &#39;N&#176; taillant&#39;,
                  hintText: widget.selectedLigneValues[&#39;N&#176; taillant&#39;] ==
                          &#39;Valeurs multiples&#39;
                      ? &#39;Valeurs multiples&#39;
                      : null,
                ),
                validator: (value) {
                  if (!numTaillantMultipleValues &amp;&amp; (value == null)) {
                    return &#39;Merci d\&#39;entrer un num&#233;ro de taillant&#39;;
                  }
                  return null;
                },
              ),
              TextFormField(
                controller: observationController,
                decoration: InputDecoration(
                  labelText: &#39;Observation&#39;,
                  hintText: widget.selectedLigneValues[&#39;Observation&#39;] ==
                          &#39;Valeurs multiples&#39;
                      ? &#39;Valeurs multiples&#39;
                      : null,
                ),
                validator: (value) {
                  if (!observationMultipleValues &amp;&amp; (value == null)) {
                    return &#39;Merci de rentrer une observation&#39;;
                  }
                  return null;
                },
              ),
            ],
          ),
        ),
      ),
      actions: [
        TextButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text(&#39;Annuler&#39;),
        ),
        ElevatedButton(
          onPressed: () {
            if (_formKey.currentState!.validate()) {
              bool updated = editLignes();
              Navigator.pop(context,
                  updated); // Renvoie &#39;true&#39; si les modifications ont &#233;t&#233; effectu&#233;es
            }
          },
          child: Text(&#39;Sauvegarder&#39;),
        ),
      ],
    );
  }

  bool editLignes() {
    for (int index in widget.selectedLignes) {
      Map&lt;String, dynamic&gt; ligne = widget.tableau[index];
      ligne[&#39;Profondeur&#39;] =
          profondeurMultipleValues &amp;&amp; profondeurController.text.isEmpty
              ? ligne[&#39;Profondeur&#39;]
              : profondeurController.text;
      ligne[&#39;Inclinaison&#39;] =
          inclinaisonMultipleValues &amp;&amp; inclinaisonController.text.isEmpty
              ? ligne[&#39;Inclinaison&#39;]
              : inclinaisonController.text;
      ligne[&#39;N&#176; taillant&#39;] =
          numTaillantMultipleValues &amp;&amp; numTaillantController.text.isEmpty
              ? ligne[&#39;N&#176; taillant&#39;]
              : numTaillantController.text;
      ligne[&#39;Observation&#39;] =
          observationMultipleValues &amp;&amp; observationController.text.isEmpty
              ? ligne[&#39;Observation&#39;]
              : observationController.text;
    }
    widget.saveTable(widget.tableau, widget.rapportIndex);
    return true; // Retourne &#39;true&#39; pour indiquer que les modifications ont &#233;t&#233; effectu&#233;es
  }
}

huangapple
  • 本文由 发表于 2023年3月3日 17:50:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75625514.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定