JTextField -> CaretPos bei SelectionStart() setzten nicht bei SelectionEnd()

JavaRentner

Aktives Mitglied
Guten Tag

Ausgangslage:
JTextField mit Text ("Warum auch nicht")
setze:
SelectionStart(3)
SelectionEnd(JTextField.getText().length)

Text ist richtig selektiert!
Aber der Cursor blinkt am ENDE der selektion.

SetCaretPosition(3) setzt den Cursor an Position 3 auch gut.
(leider ist jetzt kein Text mehr selektiert.)

Frage:
Gibt es eine Möglichkeit, dass der Cursor an dritter Stelle blinkt aber der Text ab dieser bis ende Text selektiert bleibt?
Brauchts dazu einen Renderer? Wenn JA, wie müsste dann entsprechende Befehlsgebung aussehen?

Vielen Dank
 
Das funktioniert, wie in den JavaDocs dokumentiert:
Java:
textField.setCaretPosition(textField.getText().length());
textField.moveCaretPosition(3);
 
OK
Wo liegt der Unterschied von:
Code:
textField.moveCaretPosition(3);
und
Java:
textField.seCaretPosition(3);

in beiden fällen ist nichts mehr selektiert...

Dann wie kann ich, wenn der Text im TextField länger ist als die Breite des TextField, die länge des sichtbaren Textes herausfinden?

So könnte ich doch ab dem setSelectionStart(3) bis setSelectionEnd(letztes sichtbare Zeichen) selektieren?
Damit wäre mir schon geholfen.
 
in beiden fällen ist nichts mehr selektiert...
setCaretPosition entfernt die Auswahl, moveCaretPosition erzeugt eine Auswahl, ausgehend von der aktuellen Position. Wenn Du es so wie in Kommentar #2 gezeigt machst, wird zuerst der Cursor auf das Ende des Textfelds gesetzt - die Auswahl wird entfernt - und anschließend - mit Auswahl - auf die Position 3 (0-based) bewegt.

Dann wie kann ich, wenn der Text im TextField länger ist als die Breite des TextField, die länge des sichtbaren Textes herausfinden?
Java:
import java.awt.*;
import javax.swing.*;

public class TfTest {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JTextField tf = new JTextField(5);
            tf.setText("Lorem ipsum dolor sit amet, consetetur sadipscing elitr");

            JPanel input = new JPanel();
            input.add(tf);

            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.add(input, BorderLayout.WEST);
            frame.setSize(400, 300);
            frame.setVisible(true);

            Insets insets = tf.getInsets();
            int pos = tf.viewToModel2D(new Point(tf.getWidth() - insets.right, insets.top));
            tf.setCaretPosition(pos);
            tf.moveCaretPosition(3);
        });
    }
}
/code]
 
Mist, das hätte ich nicht gedacht... Es ist nicht möglich, etwas zu selektieren und dabei den Caret auf den Anfang der Selektion zu setzen ...

Java:
import javax.swing.*;

public class SelectDemo {
    public enum SelectCaretBehavior {
        DO_NOT_MOVE_CARET,
        MOVE_CARET_TO_SELECT_START,
        MOVE_CARET_TO_SELECT_END
    }

    private final JTextArea textArea1 = new JTextArea("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed d");

    public SelectDemo() {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("SelectDemo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(400, 300);
            frame.setVisible(true);

            textArea1.setLineWrap(true);
            frame.add(new JScrollPane(textArea1));
        });
    }

    public void selectText(int start, int end, SelectCaretBehavior caretBehavior) {
        switch (caretBehavior) {
            case DO_NOT_MOVE_CARET:
                break;
            case MOVE_CARET_TO_SELECT_START:
                textArea1.setCaretPosition(start);
                break;
            case MOVE_CARET_TO_SELECT_END:
                textArea1.setCaretPosition(end);
                break;
        }
        textArea1.select(start, end);
    }

    public static void main(String[] args) {
        new SelectDemo().selectText(5, 10, SelectCaretBehavior.MOVE_CARET_TO_SELECT_START);
    }
}

Leider doch ein Bug
 
Danke, das geht:

Java:
import javax.swing.*;

public class SelectDemo {
    public enum SelectCaretBehavior {
        DO_NOT_MOVE_CARET,
        MOVE_CARET_TO_SELECT_START,
        MOVE_CARET_TO_SELECT_END
    }

    private final JTextArea textArea1 = new JTextArea("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo in pede. Praesent blandit odio eu enim. Pellentesque sed d");

    public SelectDemo() {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("SelectDemo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(400, 300);
            frame.setVisible(true);

            textArea1.setLineWrap(true);
            frame.add(new JScrollPane(textArea1));
        });
    }

    public void selectText(int start, int end, SelectCaretBehavior caretBehavior) {
        if (start < 0 || end > textArea1.getText().length()) {
            throw new IllegalArgumentException("Indexes out of bounds");
        }
        if (caretBehavior == null) {
            throw new IllegalArgumentException("Caret behavior cannot be null");
        }
        switch (caretBehavior) {
            case DO_NOT_MOVE_CARET -> textArea1.select(start, end);
            case MOVE_CARET_TO_SELECT_START -> {
                textArea1.setCaretPosition(end);
                textArea1.moveCaretPosition(start);
            }
            case MOVE_CARET_TO_SELECT_END -> {
                textArea1.setCaretPosition(start);
                textArea1.moveCaretPosition(end);
            }
        }
    }

    public static void main(String[] args) {
        new SelectDemo().selectText(5, 10, SelectCaretBehavior.MOVE_CARET_TO_SELECT_START);
    }
}
 
@mihe7
Das ist das Ergebnis, wenn ich den Code aus #6 laufen lasse:
funktioniert perfekt! 😄

Hab die Klasse etwas angepasst (TFTest.java) und sie macht genau das was ich wollte!
Aber in der Klasse TestMyCombo.java (MyCombo.java) wird mir der eingegebene Buchstabe selektiert und nicht ab dem eingegebenen Buchstabe bis ans ende des sichtbaren Textes wie im TFTest.java.

Ich hoffe es ist erlaubt das Projekte-Zip (69.5KiB) hier anzuhängen...?
(verwende im Projekt -> OpenJDK13)

Habe eine Methode [getInsetPos(JTextField tf)]
in TFTest.java wird mir:
Java:
int pos = tf.viewToModel2D(new Point(tf.getWidth() - insets.right, insets.top));
die position des letztem sichtbaren Zeichen zurückgegeben.

Aber in MyCombo.java, welche auch eine Methode [getInsetPos(JTextField tf)] enthält,
wird mir immer 0 zurückgegeben!

Zum testen sind beide Main-Methoden im Projekt enthalten.

Beim starten wird in beiden Mains "Noteworthy-Bold" im JTextField ausgegeben und CaredPosition ist 0!

Verhalten:
beim drücken der Taste "a" wird der Text durch den Schriftnamen "aakar" ersetzt.

in TFTest.java wird aakar selektiert.
in MyCombo.java aakar selektiert.

Was mache ich falsch, ich blick nicht durch!
Warum reagiert das JTextField in MyCombo.java nicht gleich wie das JTextField in TFTest.java

Wäre super, wenn jemand meinen Fehler aufzeigen könnte.
Vielen Dank.

PS: bei mir ist die erste Schriftart die mit a anfängt aakar! Es kann auch Arial sein...
 

Anhänge

Zuletzt bearbeitet:
Sollte ungefähr so gehen:

Java:
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

public class MyJTextArea extends JTextArea {
    private static final Font FONT = new Font("Arial", Font.PLAIN, 20);

    public MyJTextArea(String text) {
        super(text);
        setFont(FONT);
        setLineWrap(true);
        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent evt) {
                setCaretToEnd();
            }
        });
        getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                setCaretToEnd();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                setCaretToEnd();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                setCaretToEnd();
            }
        });
    }

    public void setCaretToEnd() {
        try {
            int lastCharLineIndex = viewToModel2D(new Point(getWidth(), getInsets().top));
            int widthInPixel = getFontMetrics(FONT).stringWidth(getText(0, lastCharLineIndex));
            System.out.println("lastCharLineIndex: " + lastCharLineIndex);
            System.out.println("widthInPixel: " + widthInPixel);
            setCaretPosition(lastCharLineIndex);
        } catch (BadLocationException ignore) {
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 400);
        MyJTextArea area = new MyJTextArea("Hello, World! bla bla bla bla bla bla bla bla bla bla");
        frame.add(new JScrollPane(area));
        frame.setVisible(true);
    }
}

Aber das Problem ist, manchmal ist hinter dem letzten, sichtbaren Zeichen kein Platz mehr für den Caret ... dann wird es davor platziert.
 
Was mache ich falsch, ich blick nicht durch!
Der Code von mir ist im wahrsten Sinne des Wortes ein "edge case" - ich füge ja gerade mal die insets hinzu. Wäre davon ausgegangen, dass das so passt, tut es aber nicht (immer). Interessanterweise funktioniert es, wenn man tf.getHeight() - insets.bottom verwendet.

Java:
    private static int getInsetPos(JTextField tf) {
        Insets insets = tf.getInsets();
        int pos = tf.viewToModel2D(new Point(tf.getWidth() - insets.right, tf.getHeight() - insets.bottom));
        return pos;
    }

EDIT: weil es mir gerade einfällt... eventuell hängt das mit der Skalierung der Anzeige zusammen. Wenn ich 1 als top-Inset habe und das skaliere, könnte der int-Wert auf 0 abgeschnitten werden und das wäre dann außerhalb.
 
@mihe7
Der Fehler von mir muss iwo anders liegen! Aber ich hab keinen Durchblick!
Das verhalten ist mit bottom äquivalent zu top.
Soll heissen, es funktioniert wie gewünscht! Egal bottom resp. top. (Post #9)

Nur wo mache ich den Fehler?
Im ZIP-Anhang habe ich die Klasse "MyCombo.java" und darin verwende ich die gleiche Methode wie im "TfTest.java" ebenfalls im ZIP:
Java:
    private static int getInsetPos(JTextField tf) {
        Insets insets = tf.getInsets();
        int pos = tf.viewToModel2D(new Point(tf.getWidth() - insets.right, insets.bottom));
        return pos;
    }
Im "TfTest.java" funktioniert es egal top resp. bottom!
In der Klasse "MyCombo.java" gibt er mir immer pos=0 zurück! Warum???

Heble ich das irgendwo aus und finde es nicht mehr?
 

Zurück
Oben