2016-06-22 8 views
0

テキストドキュメントの特定のテキスト要素にコメントすることを可能にするプログラムを計画しています。基本的には、テキストの特定の部分を強調表示してコメントを追加する機能を作成したいと考えています。私はJavaFXの使用を計画していますが、私はスイングのような他のJavaパッケージやJSのものにもオープンしています。JavaFXでテキストコメント機能を作成する

Wordはうまくいきますが、私は他の機能を追加したいと思いますが、それは良いベースとして機能します。私が欲しいもののいくつかを行うもう1つの製品はGoogleブックスです。コメントを追加して、ハイライトを配置することができます。 PDFリーダーはすごく便利ですが、少なくとも今のところはPDFファイルの使用を避けたいと思います。

私は他のアドバイスを探しました。ハイライトを追加するためのリソースがありますが、これは少し複雑ですが不可能ではありません。 TextFlowオブジェクトはこれをうまく処理できます。私はそれ以上のことを検討するつもりですが、コメント機能は非常に重要なので、完全に作業する機会のない道に行きたいとは思っていません。

JavaFXでこれを行う方法に関するアドバイスはありますか?あるいは別のフレームワークで?

編集: ユーザーはコメントを変更して削除できるはずですが、一般的には、コメントを保存した後にユーザーが問題のファイルを開いたときにそのコメントを保持する必要があります。

+0

、あなたのコメントの寿命を検討していますか? – Peter

+0

わかりません。同様に、それらはエンドユーザーによって削除される予定ですか?その答えは、ユーザーが選択した場合でもユーザーは削除できますが、一般的にコメントは永久的です。 – buggaby

+0

質問を更新して、潜在的な回答がコメントを再読み込みできると考えられるようにしてください。一般的には永続的ですが、共有表示/プレゼンテーションのようなものでしたが、その期間のコメントが必要なのは – Peter

答えて

2

アイデアを流すためのJavaFXのアプローチを提供しました。しかし、あなたは、おそらくより良いあなたのニーズに合わせて変更したいと思う、あなたは後にしている主要な機能のいくつか含まれています - ノート下にいくつかの提案は、この


特長であります。

コメントするためにユーザに促すために、デフォルト ContextMenuに追加オプションを公開します選択し、関心の右クリックのテキスト:
  • コメントを追加します

    Add comment option Example of a comment being added

  • ハイライトテキスト:キーワードは、コメントペインで赤く強調表示されます。コメントはこのペイン内で選択された場合、TextAreaは/ハイライトに戻って、古いコメントを読む

  • 上記のステップのように、再びテキストを選択します:私はあなたを期待するとして、私はToDoでこれの汚い実装を含めました

/* TODO::コメントを保存し、読みたいかのあなた自身の方法を持っている構造を前提としていますのRangeStart、rangeEndのを| |関連するテキスト| コメント はこれを確認するために検証を追加、またはXML など 優れた構造と、それを完全に置き換えるのいずれかで、ケースLorem Ipsumからあなたが */

例を決める方アプローチの保存ベースの機能を実装

6, 11|ipsum|Test comment to apply against ipsum 
409, 418|deserunt |This is a long comment that should wrap around 
0, 11|Lorem ipsum|Lorem ipsum inception: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 


注:あなたは、以下の実装に構築したい

  • この実装ではコメントを削除する方法はありませんが、setOnContextMenuRequestedshowの組み合わせで可能です。この方法では、ContextMenuを使用して追加の機能を追加することができます。
  • HTMLEditor/WebViewを使用して、テキストを再選択するのではなく文書をスタイルすることができます。ここで助けたり、選択肢を提供することができるいくつかの記事です:

SSCCE

public class CommentAnnotation extends Application{ 

    public class DocumentAnnotator extends HBox { 
     private File documentToAnnotate; 
     private ScrollPane textViewer, commentViewer; 
     private TextArea textArea; 
     private VBox commentContainer; 
     private MenuItem addCommentItem; 

     private String textInViewer; 
     private ObservableList<Node> comments = FXCollections.observableArrayList(); 

     public DocumentAnnotator(File document){ 
      documentToAnnotate = document; 
      readInFile(); 
      setupElements(); 
     } 

     public DocumentAnnotator(File document, File storedComments){ 
      this(document); 
      //Re-load previous comments 
      try{ 
       Files.lines(storedComments.toPath()).forEach(this::parseAndPopulateComment); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 

     private void readInFile(){ 
      try { 
       textInViewer = Files.lines(documentToAnnotate.toPath()) 
         .collect(Collectors.joining("\n")); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 

     private void parseAndPopulateComment(String comment){ 
      /*ToDo: Assumes structure: rangeStart , rangeEnd | associated text | comment 
        Either add validation to confirm this, or replace it completely with a 
        better structure such as xml 
        Implement the save-based functionality of whichever approach you decide on 
      */ 
      String[] splitResult = comment.split("\\|"); 
      createComment(IndexRange.valueOf(splitResult[0]), splitResult[1], splitResult[2]); 
     } 

     private void setupElements(){ 
      setupViewers(); 
      getChildren().setAll(textViewer, new Separator(Orientation.VERTICAL), commentViewer); 
     } 

     private void setupViewers(){ 
      setupTextViewer(); 
      setupCommentViewer(); 
     } 

     private void setupTextViewer(){ 
      setupTextArea(); 

      textViewer = new ScrollPane(textArea); 
      textViewer.minHeightProperty().bind(heightProperty()); 
      textViewer.maxHeightProperty().bind(heightProperty()); 
      textArea.maxWidthProperty().bind(textViewer.widthProperty()); 
      textArea.minHeightProperty().bind(textViewer.heightProperty()); 
     } 

     private void setupTextArea(){ 
      textArea = new TextArea(textInViewer); 
      //Ensure that if this controls dimensions change, the text will wrap around again 
      textArea.setWrapText(true); 

      addCommentItem = new MenuItem("Add comment"); 
      addCommentItem.setOnAction(event -> { 
       IndexRange range = textArea.getSelection(); 
       String selectedText = textArea.getSelectedText(); 
       String commentText = promptUserForComment(selectedText); 
       if(selectedText.isEmpty() || commentText.isEmpty()){ return; } 
       createComment(range, selectedText, commentText); 
      }); 

      //Append an "Add comment" option to the default menu which contains cut|copy|paste etc 
      TextAreaSkin modifiedSkin = new TextAreaSkin(textArea){ 
       @Override 
       public void populateContextMenu(ContextMenu contextMenu) { 
        super.populateContextMenu(contextMenu); 
        contextMenu.getItems().add(0, addCommentItem); 
        contextMenu.getItems().add(1, new SeparatorMenuItem()); 
       } 
      }; 
      textArea.setSkin(modifiedSkin); 
      textArea.setEditable(false); 
     } 

     private String promptUserForComment(String selectedText){ 
      TextInputDialog inputDialog = new TextInputDialog(); 
      inputDialog.setHeaderText(null); 
      inputDialog.setTitle("Input comment"); 
      inputDialog.setContentText("Enter the comment to associate against: " + selectedText); 
      return inputDialog.showAndWait().get(); 
     } 

     private void setupCommentViewer(){ 
      commentContainer = new VBox(5); 
      Bindings.bindContentBidirectional(commentContainer.getChildren(), comments); 
      commentViewer = new ScrollPane(commentContainer); 
      //Use 30% of the control's width to display comments 
      commentViewer.minWidthProperty().bind(widthProperty().multiply(0.30)); 
      commentViewer.maxWidthProperty().bind(widthProperty().multiply(0.30)); 
      commentViewer.minHeightProperty().bind(heightProperty()); 
      commentViewer.maxHeightProperty().bind(heightProperty()); 
      //Imitate wrapping 
      commentViewer.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); 
      //Account for scroller width 
      commentContainer.maxWidthProperty().bind(commentViewer.widthProperty().subtract(5)); 
     } 

     private void createComment(IndexRange range, String selectedText, String commentText){ 
      AssociatedComment comment = new AssociatedComment(range, selectedText, commentText); 
      //Re-select the range when the comment is clicked 
      comment.setOnMouseClicked(clickEvent -> textArea.selectRange(
        comment.getAssociatedRange().getStart(), comment.getAssociatedRange().getEnd())); 
      comments.add(comment); 
     } 
    } 

    public class AssociatedComment extends TextFlow { 
     private IndexRange associatedRange; 
     private Text associatedText, associatedComment; 

     public AssociatedComment(IndexRange range, String text, String comment){ 
      associatedRange = range; 
      associatedText = new Text(text); 
      associatedText.setFill(Color.RED); 
      associatedComment = new Text(comment); 
      getChildren().setAll(associatedText, new Text(" : "), associatedComment); 
     } 

     public IndexRange getAssociatedRange(){ 
      return associatedRange; 
     } 

     public String getAssociatedText(){ 
      return associatedText.getText(); 
     } 

     public String getAssociatedComment(){ 
      return associatedComment.getText(); 
     } 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     File lorem = new File(getClass().getClassLoader().getResource("loremIpsum.txt").toURI()); 
     File loremComments = new File(getClass().getClassLoader().getResource("loremComments.txt").toURI()); 
     DocumentAnnotator annotator = new DocumentAnnotator(lorem); 
     //DocumentAnnotator annotator = new DocumentAnnotator(lorem, loremComments); 

     Scene scene = new Scene(annotator, 600, 400); 
     primaryStage.setScene(scene); 
     primaryStage.setTitle("Document annotation"); 
     primaryStage.show(); 
    } 
} 
+1

本当に素晴らしいスタートです!宝物。コメントに関しては、電子ブックフォーマットと同様にファイルを統一し、カスタムhtmlタグでコメントを扱うことを考えていました。しかし、別のファイルも素晴らしいです。私は両方の方法で周りを突き進ます必要があります。仕事にはとても感謝しています! – buggaby

+0

私は、コメントペインと、WordまたはPDFリーダーのスピーチバブルのように、その場所にコメントの内容を示すいくつかのタイプのメソッドの間を行き来し続けています。しかし、私は、これらのUI要素を手動で作成すると考えています。あなたが考案したペインオプションは、はるかにアクセスしやすいようです。 – buggaby

関連する問題