TextArea Swing 和 JavaFX 选择范围的区别

Posted

技术标签:

【中文标题】TextArea Swing 和 JavaFX 选择范围的区别【英文标题】:TextArea Swing and JavaFX select range difference 【发布时间】:2017-04-13 04:25:07 【问题描述】:

目前我正在编写一个 Swing 应用程序以在 JTextArea 中显示源代码(C++、Java 等),并在文本查看器中包含 selecting 元素。要选择,使用元素的位置偏移量内容长度。这是我的代码:

package application;

import java.awt.BorderLayout;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;

public class MainSwing 

    public static void main(String[] args) throws Exception
        JFrame frame = new JFrame();
        frame.setSize(500, 400);
        String content = new String(Files.readAllBytes(Paths.get("src/application/File.cpp")), Charset.forName("UTF-8"));
        int functionOffset = 61;
        int functionLength = 26;
        System.out.println(content.indexOf("int PlusTest(int x, int y)"));

        JPanel panel = new JPanel(new BorderLayout());

        JButton btn = new JButton("Select function (Swing)");
        panel.add(btn, BorderLayout.NORTH);

        JTextArea area = new JTextArea(content);
        panel.add(area, BorderLayout.CENTER);

        btn.addActionListener(e-> 
            area.requestFocusInWindow();
            area.setCaretPosition(functionOffset);
            area.moveCaretPosition(functionOffset + functionLength);
        );

        frame.setContentPane(panel);
        frame.setVisible(true);
    


示例源文件(保存为ANSI、CR-LF格式):

/*---------------Arithmetic operator---------------*/

int PlusTest(int x, int y)
    int z = x + y;

    if (z > 0)
        return 1;
    else
        return 0;

注意:示例代码开头有2个空行 这段代码运行良好,它选择了 C++ 函数声明部分的范围:

现在,我在 JavaFX 8(Java 版本:1.8.0_112)中编写了一个类似的应用程序:

package application;

import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;


public class Main extends Application 

    @Override
    public void start(Stage primaryStage) 
        try 
            VBox root = new VBox();
            String content = new String(Files.readAllBytes(Paths.get("src/application/File.cpp")), Charset.forName("UTF-8"));
            int functionOffset = 61;
            int functionLength = 26;
            System.out.println(content.indexOf("int PlusTest(int x, int y)"));

            Button btn1 = new Button("Select function (JavaFX)");
            TextArea area1 = new TextArea(content);
            root.getChildren().addAll(btn1, area1);

            btn1.setOnAction(e->
                area1.selectRange(functionOffset, functionOffset + functionLength);
            );

            Scene scene = new Scene(root,800, 300);
            primaryStage.setScene(scene);
            primaryStage.show();
         catch(Exception e) 
            e.printStackTrace();
        
    

    public static void main(String[] args) 
        launch(args);
    

结果如下:

那么,为什么这里会有所不同?我是否使用了错误的功能? 感谢您的帮助

编辑 1 试试这个代码:

System.out.println(content.length());
System.out.println(area1.getText().length());

结果是:JavaFX 版本中为 157 146 在 Swing 版本中,它是:157 157

【问题讨论】:

这并不是您问题的真正答案,但是您为什么不使用area1.getText().indexOf("int PlusTest(int x, int y)") 之类的东西来获得函数的正确偏移量呢?这将返回索引 55,这似乎是函数的正确起始位置。 以上代码仅供提问。我真正的应用程序将 C/C++ 源代码作为输入,使用 3rd-party 插件 (Eclipse CDT) 来解析内部的所有令牌元素及其位置。之后,我使用此位置在源查看器中选择范围。如果我的源代码在 2 个不同的类中包含 2 个完全 C++ 函数,您的方法将不起作用 @DVarga,问题是在JavaFX版本中,它应该像Swing版本一样选择“int PlusTest(int x, int y)”,但它没有 @DVarga, @Jonatan Stenbacka:我在两个版本中都尝试过System.out.println(content.indexOf("int PlusTest(int x, int y)"));,并且都将 61 打印为起始位置 是的,"\r\n" (CR+LF) 很可能会变成简单的\n,这就是区别所在。 content = content.replaceAll("\r\n", "\n"); 似乎解决了这个问题。 【参考方案1】:

TextArea 似乎忽略了回车(“\r”)并使用换行符(“\n”)作为行分隔符。

测试它:

TextArea area1 = new TextArea("\r\n");
System.out.println((int) "\r\n".charAt(0));
System.out.println((int) "\r\n".charAt(1));

System.out.println("TextArea text length: " + area1.getText().length());

System.out.println((int) area1.getText().charAt(0));

和输出:

13
10
TextArea text length: 1
10

更新:

挖掘TextInputControl的来源导致这部分代码:

private static boolean isInvalidCharacter(char c, boolean newlineIllegal, boolean tabIllegal) 
    if (c == 0x7F) return true;
    if (c == 0xA) return newlineIllegal;
    if (c == 0x9) return tabIllegal;
    if (c < 0x20) return true;
    return false;

有趣的分支是if (c &lt; 0x20) return true;,这意味着回车符被标记为无效,因此它不会附加到控件的文本中


由于您的文件使用 CR+LF 作为行分隔符,如果您执行以下操作:

int functionOffset = content.indexOf("int PlusTest(int x, int y)");
content = content.replaceAll("\r\n", "\n");
int functionOffset2 = content.indexOf("int PlusTest(int x, int y)");

System.out.println("Offset before: " + functionOffset + " and after: " + functionOffset2);

输出是:

Offset before: 61 and after: 57

因此,在将字符串添加到 TextArea 之前从字符串中删除 CR 字符应该可以解决问题:

String content = new String(Files.readAllBytes(Paths.get("src/application/File.cpp")), Charset.forName("UTF-8"));
content = content.replaceAll("\r\n", "\n");

【讨论】:

以上是关于TextArea Swing 和 JavaFX 选择范围的区别的主要内容,如果未能解决你的问题,请参考以下文章

javafx如何设置文本框TextArea背景色为透明

将命令行文本输出到 Javafx Textarea

“textarea”中的 JavaFX 8 计数行

使用JAVAFX和SWING有啥区别[重复]

JavaFX - TextArea 的掩码文本

是否可以使用 JavaFX 和 Swing 制作具有视觉吸引力的 GUI?