2014-08-29 60 views
3

我正在尋找在我正在編寫的窗格上的任意位置創建可編輯標籤。我覺得TextField或TextArea對象是我可以用來實現該功能的。顯然更多的是因爲當我創建它時不知道如何定位對象。我在「混沌Java」網站上找到了一個例子,但我需要做更多的工作來了解那裏發生了什麼。 http://chaoticjava.com/posts/another-javafx-example-the-editable-label/如何在javafx 2.2中創建可編輯標籤

我在尋找來自這個羣體的更多信息。

(有沒有錯誤,因爲我沒有寫任何代碼。)

+1

什麼是根? AnchorPane?窗格?你的問題現在太廣泛了。改變它並添加一個能夠重現錯誤的[mcve](http://stackoverflow.com/help/mcve)。 – Mansueli 2014-08-29 16:30:19

+0

我不清楚「可編輯標籤」如何與「TextField」不同。爲什麼不使用'TextField'? – 2014-08-29 17:19:55

+0

想象一下,只是想在您正在工作的窗口中的任何位置鍵入文本,而不將其與任何其他控件相關聯。之後我可能想要編輯該文本,所以我點擊文本並瞧!文本變得可編輯。 – 2014-08-29 17:31:39

回答

5

我是那種好奇如何實現這一點,所以我給它一個嘗試。這是我想出的。

lonely

使用的方法是很一樣,在他的評論由詹姆斯·建議:

我會用一個窗格開始。 。 。,TextFields在編輯時表示文本。使用Pane和Text對象註冊鼠標偵聽器,並使用layoutX和layoutY屬性來定位事物。 。 。只是爲了使用文本字段,並使用CSS使它們在未聚焦時看起來像標籤,而在聚焦時看起來像文本字段。

唯一非常棘手的部分是如何正確確定文本字段的大小,因爲文本字段中的文本不會通過公開API公開以允許您聽取它的佈局邊界。你也許可以使用css查找函數來獲得所附的文本,但我選擇使用私有太陽FontMetrics API(將來可能不推薦使用)來獲取文本的大小。在將來使用Java 9時,您應該能夠在不使用私有API的情況下執行任務。

該解決方案不會像處理多格式或多行文本那樣做任何棘手的事情,它只是對可放置在場景上的幾個單詞的簡短單行註釋。

TextCreator.java

// ## CAUTION: beware the com.sun imports... 
import com.sun.javafx.tk.FontMetrics; 
import com.sun.javafx.tk.Toolkit; 

import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.scene.Cursor; 
import javafx.scene.Scene; 
import javafx.scene.control.TextField; 
import javafx.scene.image.Image; 
import javafx.scene.image.ImageView; 
import javafx.scene.layout.Pane; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

/** 
* Displays a map of the lonely mountain upon which draggable, editable labels can be overlaid. 
*/ 
public class TextCreator extends Application { 
    private static final String MAP_IMAGE_LOC = 
      "http://images.wikia.com/lotr/images/archive/f/f6/20130209175313!F27c_thorins_map_from_the_hobbit.jpg"; 

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

    @Override 
    public void start(final Stage stage) throws Exception { 
     Pane pane = new Pane(); 

     pane.setOnMouseClicked(event -> { 
      if (event.getTarget() == pane) { 
       pane.getChildren().add(
         new EditableDraggableText(event.getX(), event.getY()) 
       ); 
      } 
     }); 

     EditableDraggableText cssStyled = 
       new EditableDraggableText(439, 253, "Style them with CSS"); 
     cssStyled.getStyleClass().add("highlighted"); 

     pane.getChildren().addAll(
       new EditableDraggableText(330, 101, "Click to add a label"), 
       new EditableDraggableText(318, 225, "You can edit your labels"), 
       cssStyled, 
       new EditableDraggableText(336, 307, "And drag them"), 
       new EditableDraggableText(309, 346, "Around The Lonely Mountain") 
     ); 

     StackPane layout = new StackPane(
      new ImageView(
        new Image(
          MAP_IMAGE_LOC 
        ) 
      ), 
      pane 
     ); 

     Scene scene = new Scene(layout); 
     scene.getStylesheets().add(getClass().getResource(
      "editable-text.css" 
     ).toExternalForm()); 

     stage.setScene(scene); 
     stage.setResizable(false); 
     stage.show(); 
    } 

    /** 
    * A text field which has no special decorations like background, border or focus ring. 
    * i.e. the EditableText just looks like a vanilla Text node or a Label node. 
    */ 
    class EditableText extends TextField { 
     // The right margin allows a little bit of space 
     // to the right of the text for the editor caret. 
     private final double RIGHT_MARGIN = 5; 

     EditableText(double x, double y) { 
      relocate(x, y); 
      getStyleClass().add("editable-text"); 

      //** CAUTION: this uses a non-public API (FontMetrics) to calculate the field size 
      //   the non-public API may be removed in a future JavaFX version. 
      // see: https://javafx-jira.kenai.com/browse/RT-8060 
      //  Need font/text measurement API 
      FontMetrics metrics = Toolkit.getToolkit().getFontLoader().getFontMetrics(getFont()); 
      setPrefWidth(RIGHT_MARGIN); 
      textProperty().addListener((observable, oldTextString, newTextString) -> 
       setPrefWidth(metrics.computeStringWidth(newTextString) + RIGHT_MARGIN) 
      ); 

      Platform.runLater(this::requestFocus); 
     } 
    } 

    /** 
    * An EditableText (a text field which looks like a label), which can be dragged around 
    * the screen to reposition it. 
    */ 
    class EditableDraggableText extends StackPane { 
     private final double PADDING = 5; 
     private EditableText text = new EditableText(PADDING, PADDING); 

     EditableDraggableText(double x, double y) { 
      relocate(x - PADDING, y - PADDING); 
      getChildren().add(text); 
      getStyleClass().add("editable-draggable-text"); 

      // if the text is empty when we lose focus, 
      // the node has no purpose anymore 
      // just remove it from the scene. 
      text.focusedProperty().addListener((observable, hadFocus, hasFocus) -> { 
       if (!hasFocus && getParent() != null && getParent() instanceof Pane && 
        (text.getText() == null || text.getText().trim().isEmpty())) { 
        ((Pane) getParent()).getChildren().remove(this); 
       } 
      }); 

      enableDrag(); 
     } 

     public EditableDraggableText(int x, int y, String text) { 
      this(x, y); 
      this.text.setText(text); 
     } 

     // make a node movable by dragging it around with the mouse. 
     private void enableDrag() { 
      final Delta dragDelta = new Delta(); 
      setOnMousePressed(mouseEvent -> { 
       this.toFront(); 
       // record a delta distance for the drag and drop operation. 
       dragDelta.x = mouseEvent.getX(); 
       dragDelta.y = mouseEvent.getY(); 
       getScene().setCursor(Cursor.MOVE); 
      }); 
      setOnMouseReleased(mouseEvent -> getScene().setCursor(Cursor.HAND)); 
      setOnMouseDragged(mouseEvent -> { 
       double newX = getLayoutX() + mouseEvent.getX() - dragDelta.x; 
       if (newX > 0 && newX < getScene().getWidth()) { 
        setLayoutX(newX); 
       } 
       double newY = getLayoutY() + mouseEvent.getY() - dragDelta.y; 
       if (newY > 0 && newY < getScene().getHeight()) { 
        setLayoutY(newY); 
       } 
      }); 
      setOnMouseEntered(mouseEvent -> { 
       if (!mouseEvent.isPrimaryButtonDown()) { 
        getScene().setCursor(Cursor.HAND); 
       } 
      }); 
      setOnMouseExited(mouseEvent -> { 
       if (!mouseEvent.isPrimaryButtonDown()) { 
        getScene().setCursor(Cursor.DEFAULT); 
       } 
      }); 
     } 

     // records relative x and y co-ordinates. 
     private class Delta { 
      double x, y; 
     } 
    }  
} 

編輯-text.css

.editable-text { 
    -fx-background-color: transparent; 
    -fx-background-insets: 0; 
    -fx-background-radius: 0; 
    -fx-padding: 0; 
} 

.editable-draggable-text:hover .editable-text { 
    -fx-background-color: yellow; 
} 

.editable-draggable-text { 
    -fx-padding: 5; 
    -fx-background-color: rgba(152, 251, 152, 0.2); // translucent palegreen 
} 

.editable-draggable-text:hover { 
    -fx-background-color: orange; 
} 

.highlighted { 
    -fx-background-color: rgba(255, 182, 93, 0.3); // translucent mistyrose 
    -fx-border-style: dashed; 
    -fx-border-color: firebrick; 
} 

如果你有時間,你可以清潔樣品實施起來,捐給ControlsFX項目。

+0

非常棒,+1!如果有人願意/不願意改善這一點,請告訴我。這部分/完全工作會很棒;) – ItachiUchiha 2014-08-30 07:35:14