アイデアを流すためのJavaFXのアプローチを提供しました。しかし、あなたは、おそらくより良いあなたのニーズに合わせて変更したいと思う、あなたは後にしている主要な機能のいくつか含まれています - ノート下にいくつかの提案は、この
/* 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.
注:あなたは、以下の実装に構築したい
- この実装ではコメントを削除する方法はありませんが、
setOnContextMenuRequested
とshow
の組み合わせで可能です。この方法では、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();
}
}
、あなたのコメントの寿命を検討していますか? – Peter
わかりません。同様に、それらはエンドユーザーによって削除される予定ですか?その答えは、ユーザーが選択した場合でもユーザーは削除できますが、一般的にコメントは永久的です。 – buggaby
質問を更新して、潜在的な回答がコメントを再読み込みできると考えられるようにしてください。一般的には永続的ですが、共有表示/プレゼンテーションのようなものでしたが、その期間のコメントが必要なのは – Peter