<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>Hello Tobias,</p>
    <p>interesting problem, because in "multiline-text-fields" (Qt:
      QPlainTextEdit rsp. QTextBrowser) the Tab-Key always has the
      function to insert a tab, what else... :) </p>
    <p>The workaround-script below handles edits in
      "multiline-text-fields", if the user inserts a tab, it will
      instead switch the focus to the next form-element. By using this,
      the user won't be able to insert any tabs at all.</p>
    <p>It has to be registered as init-code for the forms of your layer,
      see below.</p>
    <p>Surprisingly complicated, perhaps there's a simpler solution...</p>
    <p>Incidentally, Shift-Tab has no special function in multi-line
      text fields and simply moves the focus to the previous element.</p>
    <p><font face="monospace">from qgis.PyQt.QtWidgets import
QDialog,QWidget,QPlainTextEdit,QTextBrowser,QCheckBox,QDateTimeEdit,QFrame<br>
        from qgis.PyQt.QtCore import Qt,QObject<br>
        from qgis.PyQt.QtGui import QTextCursor,QTextDocument<br>
        from qgis.gui import QgsFilterLineEdit,QgsSpinBox<br>
        <br>
        def contents_change(position:int, chars_removed:int,
        chars_added: int):<br>
            """triggered, if the content of the connected
        form_widget.document() has changed<br>
            Will capture a single tab-insert and instead switch the
        focus to the next form-element.<br>
        <br>
            Args:<br>
                position (int): position where edit was done<br>
                chars_removed (int): number of removed chars<br>
                chars_added (int): number of added chars<br>
            """<br>
            # check 1: only one char added<br>
            if chars_added == 1:<br>
                # QTextDocument, which was connected with this slot<br>
                q_txt_dcmt:QTextDocument = QObject().sender()<br>
                # check 2: and it was a tab<br>
                last_char:str = q_txt_dcmt.toPlainText()[position]<br>
                if last_char == "\t":<br>
                    # undo edit by deleting last_char<br>
                    cursor = QTextCursor(q_txt_dcmt)<br>
                    cursor.setPosition(position)<br>
                    cursor.deleteChar()<br>
        <br>
                    # searching for QFrame with objectName
        'mAttributeEditor' as topmost widget for the focusable
        form-elements<br>
                    # bottom-up from QObject().sender()<br>
                    att_ed_qfr:QFrame = None<br>
                    qpte:QTextBrowser|QPlainTextEdit = None<br>
                    parent = QObject().sender().parent()<br>
                    while parent:<br>
                        if parent.objectName() and parent.__class__ in
        [QTextBrowser,QPlainTextEdit]:<br>
                            # the triggering widget<br>
                            qpte = parent<br>
                        if parent.objectName() == "mAttributeEditor":<br>
                            # topmost widget<br>
                            att_ed_qfr = parent<br>
                            break<br>
                        parent = parent.parent()<br>
        <br>
                    if att_ed_qfr and qpte:<br>
                        qpte.setPlainText(q_txt_dcmt.toPlainText())<br>
        <br>
                        form_widgets = []<br>
                        form_idx = 0<br>
                        # findChildren fortunately delivers the widgets
        in tabIndex-order...<br>
                        for widget in
att_ed_qfr.findChildren(QWidget,options=Qt.FindChildOption.FindChildrenRecursively):<br>
                            # hope to have all QGis-used widget-classes
        for attribute-forms<br>
                            if widget.objectName() and widget.__class__
        in
[QTextBrowser,QPlainTextEdit,QgsFilterLineEdit,QCheckBox,QgsSpinBox,QDateTimeEdit]:<br>
                                if widget == qpte:<br>
                                    # the index of the triggering widget<br>
                                    form_idx = len(form_widgets)<br>
                                form_widgets.append(widget)<br>
        <br>
                        # focus next form-element<br>
                        focus_idx = form_idx + 1 if form_idx <
        len(form_widgets) - 1 else 0<br>
                        form_widgets[focus_idx].setFocus()<br>
                    else:<br>
                        raise Exception("Something went terribly
        wrong...")<br>
        <br>
        def my_form_open(dialog:QDialog, layer, feature):<br>
            # identify the multiline form-widgets by type and objectName
        (matching to field-name)<br>
            # and connect the contentsChange-signal to widget.document()
        (!)<br>
            all_field_names = [field.name() for field in layer.fields()]<br>
        <br>
            for widget in
dialog.findChildren(QWidget,options=Qt.FindChildOption.FindChildrenRecursively):<br>
                if widget.objectName() in all_field_names and
        (isinstance(widget,QPlainTextEdit) or
        isinstance(widget,QTextBrowser)):<br>
                   
        widget.document().contentsChange.connect(contents_change)<br>
        <br>
        <br>
        <br>
      </font></p>
    <p>Register as Attribute-form-init-function: Copy&Paste code,
      adopt the other settings</p>
    <blockquote>
      <p><img src="cid:part1.oktzOchu.rZAwHuWg@kni-online.de" alt=""></p>
    </blockquote>
    <p><br>
    </p>
    <blockquote>
      <p><img src="cid:part2.VMk43B9Y.lMKZVryA@kni-online.de" alt=""></p>
    </blockquote>
    <p><br>
    </p>
    <p>Depending on your settings messages will be displayed each time
      you open a form:</p>
    <blockquote>
      <p><img src="cid:part3.WkMaXjtU.2a0xvLud@kni-online.de" alt=""></p>
    </blockquote>
    <p>That gets annoying after a while and<span class="HwtZe" lang="en"><span
          class="jCAhz ChMk0b"><span class="ryNqvb"> can be prevented as
            follows:</span></span></span></p>
    <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb">Settings > Options > General >
            Project Files</span></span></span></p>
    <blockquote>
      <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
              class="ryNqvb"><img
                src="cid:part4.0VRQpmpe.oC5ZP0u1@kni-online.de" alt=""></span></span></span></p>
    </blockquote>
    <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb"><br>
          </span></span></span></p>
    <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb">hth</span></span></span></p>
    <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb">Ludwig</span></span></span></p>
    <div class="moz-cite-prefix">Am 22.09.26 um 16:16 schrieb Tobias
      Schula via QGIS-User:<br>
    </div>
    <blockquote type="cite"
      cite="mid:a8f6a91e-1a69-4d00-ac1a-546cc3c3b3f8@schula.org">Hello
      list!
      <br>
      <br>
      I've designed an input form that contains multiline text fields
      for a longer description of a feature. The users should be able to
      use the form with the keyboard, so they can navigate with "Tab",
      "Shift+Tab", accept changes with "Enter" and decline changes with
      "Esc".
      <br>
      <br>
      However, once I put a multiline text field in the form, the user
      is trapped in this field and cannot escape without using the
      mouse. This greatly interrupts the workflow, since the users are
      usually inputting hand written field notes at their desk.
      <br>
      <br>
      I can't seem to find any documentation on the navigation in forms,
      nor have I gotten to work any combinations of "Ctrl", "Shift",
      "Tab" or "Enter". I can only close the form with "Esc", but then
      all input will be lost.
      <br>
      <br>
      Does anyone have any idea or can someone point me to
      documentation? If there is no way to exit multiline fields, I will
      file a bug/feature request.
      <br>
      <br>
      <br>
      Best regards
      <br>
      <br>
      <br>
      <fieldset class="moz-mime-attachment-header"></fieldset>
      <pre wrap="" class="moz-quote-pre">_______________________________________________
QGIS-User mailing list
<a class="moz-txt-link-abbreviated" href="mailto:QGIS-User@lists.osgeo.org">QGIS-User@lists.osgeo.org</a>
List info: <a class="moz-txt-link-freetext" href="https://lists.osgeo.org/mailman/listinfo/qgis-user">https://lists.osgeo.org/mailman/listinfo/qgis-user</a>
Unsubscribe: <a class="moz-txt-link-freetext" href="https://lists.osgeo.org/mailman/listinfo/qgis-user">https://lists.osgeo.org/mailman/listinfo/qgis-user</a>
</pre>
    </blockquote>
  </body>
</html>