weixin_39816062
2020-12-05 02:57 阅读 0

Highlighting a hyperlink

Hello, I am trying to create automatic highlighting of hyperlinks inspired by RichTextFX demos. However, I need highlighted text to be clickable. Let's say simple print of URL would be enough. For example if I write www.github.com into CodeArea it will be highlighted and whenever I click on it "Go to www.github.com" will appear. Is it possible to do something like this in RichTextFX? Thanks for any replies.

Here is a sample of color highlighting:

 java
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import org.fxmisc.richtext.CodeArea;
import org.fxmisc.richtext.LineNumberFactory;
import org.fxmisc.richtext.StyleSpans;
import org.fxmisc.richtext.StyleSpansBuilder;

public class Main extends Application {

    private static final Pattern PATTERN = Pattern.compile("w{3}(\\.\\w+/?)+");  // Simple regex to hightlight www.github.com

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


    public void start(Stage primaryStage) {
        CodeArea codeArea = new CodeArea();
        codeArea.setParagraphGraphicFactory(LineNumberFactory.get(codeArea));

        codeArea.richChanges().subscribe(change -> codeArea.setStyleSpans(0, computeHighlighting(codeArea.getText())));

        Scene scene = new Scene(new StackPane(codeArea), 600, 400);

        Application.setUserAgentStylesheet(getClass().getResource("style.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.setTitle("Hyperlink Demo");
        primaryStage.show();
    }

    private static StyleSpans<collection>> computeHighlighting(String text) {
        Matcher matcher = PATTERN.matcher(text);
        int lastKwEnd = 0;
        StyleSpansBuilder<collection>> spansBuilder
                = new StyleSpansBuilder<>();
        while (matcher.find()) {
            String styleClass ="hyperlink";
            spansBuilder.add(Collections.emptyList(), matcher.start() - lastKwEnd);
            spansBuilder.add(Collections.singleton(styleClass), matcher.end() - matcher.start());
            lastKwEnd = matcher.end();
        }
        spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd);
        return spansBuilder.create();
    }
}
</collection></collection>

Is there any way I could apply my own style instead of css "hyperlink" style from previous example? Something like this:

 java
static class Hyperlink {
    static final Hyperlink NO_LINK = new Hyperlink();
    private final String url;
    private Hyperlink() {
        this(null);
    }
    Hyperlink(String url) {
        this.url = url;
    }
    void applyToText(Text text) {
        if(url != null) {
            text.setOnMouseClicked(click -> {
                System.out.println("Go to " + url);
            });
        }
    }
}

spansBuilder.add(Collections.singleton(new Hyperlink(matcher.group(0))), matcher.end() - matcher.start());

该提问来源于开源项目:FXMisc/RichTextFX

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

4条回答 默认 最新

  • weixin_39567169 weixin_39567169 2020-12-05 02:57

    Hi, it is possible and you are on to the right solution, except CodeArea will not work for you. You will need something like StyledTextArea<Void, Hyperlink>. You can find a demo of that in #124 (although the exact code would now be outdated).

    点赞 评论 复制链接分享
  • weixin_39816062 weixin_39816062 2020-12-05 02:57

    Thanks for response! I tried it and made it work. However I bumped into few errors. Firstly I have to reset styles every time, otherwise modified links would still work even when they dont match regex. Second is that when I set style at location where cursor is, any new text is written in that style, so index - 1 will do the trick. It is probably not the most elegant solution but I was unable to make it with StyleSpansBuilder and Collections. Here is a sample if anyone is interested:

     java
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import javafx.application.Application;
    import javafx.scene.Cursor;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.scene.paint.Color;
    import javafx.scene.text.Text;
    import javafx.stage.Stage;
    import org.fxmisc.richtext.*;
    
    public class Main extends Application {
    
        private static final Pattern PATTERN = Pattern.compile("w{3}(\\.\\w+/?)+.");  // ex. www.github.com
    
        static class Hyperlink {
            static final Hyperlink NO_LINK = new Hyperlink();
    
            private final String url;
    
            private Hyperlink() {
                this(null);
            }
    
            Hyperlink(String url) {
                this.url = url;
            }
    
            void applyToText(Text text) {
                if(url != null) {
                    text.setCursor(Cursor.HAND);
                    text.setFill(Color.BLUE);
                    text.setUnderline(true);
                    text.setOnMouseClicked(click -> {
                        System.out.println("Go to " + url);
                    });
                }
            }
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    
    
        public void start(Stage primaryStage) {
            StyledTextArea textArea = new StyledTextArea<>(
                    Hyperlink.NO_LINK,
                    (text, style) -> style.applyToText(text));
    
            textArea.textProperty().addListener((obs, oldText, newText) -> {
                textArea.clearStyle(0, newText.toString().length());  // Reset styles
                Matcher matcher = PATTERN.matcher(newText.toString());
                while (matcher.find()) {
                    textArea.setStyle(matcher.start(), matcher.end() - 1, new Hyperlink(matcher.group(0)));
                }
            });
    
            Scene scene = new Scene(new StackPane(textArea), 600, 400);
    
            primaryStage.setScene(scene);
            primaryStage.setTitle("Hyperlink Demo");
            primaryStage.show();
        }
    }
    
    点赞 评论 复制链接分享
  • weixin_39567169 weixin_39567169 2020-12-05 02:57

    Both problems you mention could be solved by applying the NO_LINK style to anything that was not recognized as a link. JavaKeywords demo does that, too.

    点赞 评论 复制链接分享
  • weixin_39816062 weixin_39816062 2020-12-05 02:57

    Got it, thanks a lot!

    点赞 评论 复制链接分享

相关推荐