2016-06-08 1 views
1

Я пытаюсь создать WhatsApp-Like Conversation-View в JavaFX.JavaFX WhatApp-Like ConversationView

Чтобы отправить отправленные сообщения справа, а полученные сообщения появятся слева, я не могу использовать TextArea. Как мне это сделать? Я попробовал GridPane без TextArea, но это не облегчило ситуацию.

Кроме того, это хорошая практика, чтобы сделать элементы управления статическими?

Дополнительно: если вы также можете помочь мне сделать чат-пузырь за текстом, было бы здорово.

Вот мой код:

public class ConversationView implements WhatAppView { 
    private static Label nameLabel, statusLabel; 
    private static TextField messageTextField; 
    static TextArea messagesTextArea; 
    private static GridPane conversationSection; 
    private static Label changeViewLink; 
    private static Button sendMsgButton; 

// private static int rowIndex = 1; 

public void showView() { 
    AppMain.stage.setResizable(false); 
    AppMain.stage.setWidth(350); 
    AppMain.stage.setHeight(550); 
    BorderPane rootPane = new BorderPane(); 
    rootPane.setPadding(new Insets(5, 5, 5, 5)); 

    final int sectionHeight = 55; 

    StackPane contactSection = new StackPane(); 
    nameLabel = new Label("RW"); 
    statusLabel = new Label("Online"); 
    changeViewLink = new Label("Go Back"); 
    changeViewLink.setStyle("-fx-text-fill: blue;"); 
    changeViewLink.styleProperty().bind(
      Bindings.when(changeViewLink.hoverProperty()) 
        .then(new SimpleStringProperty("-fx-underline: true; -fx-text-fill: blue;")) 
        .otherwise(new SimpleStringProperty("-fx-underline: false; -fx-text-fill: blue;"))); 
    changeViewLink.setOnMouseClicked(new EventHandler<MouseEvent>() { 
     public void handle(MouseEvent event) { 
      AppMain.changeView(new ChatsView()); 
     } 
    }); 
    contactSection.getChildren().addAll(nameLabel, statusLabel, changeViewLink); 
    StackPane.setAlignment(changeViewLink, Pos.TOP_RIGHT); 
    StackPane.setAlignment(statusLabel, Pos.BOTTOM_CENTER); 
    contactSection.setPrefHeight(sectionHeight); 

    conversationSection = new GridPane(); 
    conversationSection.setStyle("-fx-background-image: url('whatsapp-wallpaper.jpg')"); 

    messagesTextArea = new TextArea(); 
    messagesTextArea.setEditable(false); 
    // conversationSection.getColumnConstraints().addAll(new 
    // ColumnConstraints(AppMain.stage.getWidth()/2 - 10), new 
    // ColumnConstraints(AppMain.stage.getWidth()/2 - 10)); 
    conversationSection.add(messagesTextArea, 0, 0); 
    conversationSection.setPrefSize(AppMain.stage.getWidth(), AppMain.stage.getHeight()); 
    // conversationSection.getStylesheets().add("conversation.css"); 
    ScrollPane scroll = new ScrollPane(); 
    scroll.setPrefSize(conversationSection.getWidth(), conversationSection.getHeight()); 
    scroll.setContent(conversationSection); 

    FlowPane messageSection = new FlowPane(); 
    sendMsgButton = new Button("_Send"); 
    sendMsgButton.setDisable(true); 
    sendMsgButton.setOnAction(new EventHandler<ActionEvent>() { 
     @Override 
     public void handle(ActionEvent event) { 
      sendMsg(); 
     } 
    }); 
    sendMsgButton.setPrefHeight(sectionHeight); 
    Tooltip sendMsgToolTip = new Tooltip("Send Message"); 
    Tooltip.install(sendMsgButton, sendMsgToolTip); 

    FlowPane.setMargin(sendMsgButton, new Insets(0, 0, 0, 5)); 
    messageTextField = new TextField(); 
    messageTextField.setPromptText("Type your message here..."); 
    Platform.runLater(new Runnable() { // 100% focus 
     public void run() { 
      messageTextField.requestFocus(); 
     } 
    }); 
    messageTextField.setPrefWidth(AppMain.stage.getWidth() - AppMain.stage.getWidth()/5); 
    messageTextField.setPrefHeight(sectionHeight); 
    messageTextField.setAlignment(Pos.TOP_LEFT); 
    messageTextField.setOnKeyTyped(new EventHandler<KeyEvent>() { 
     @Override 
     public void handle(KeyEvent event) { 
      if (messageTextField.getText() != null && !messageTextField.getText().isEmpty()) { 
       sendMsgButton.setDisable(false); 
      } else { 
       sendMsgButton.setDisable(true); 
      } 
     } 
    }); 
    messageTextField.setOnKeyPressed(new EventHandler<KeyEvent>() { 
     @Override 
     public void handle(KeyEvent event) { 
      if (event.getCode().equals(KeyCode.ENTER) && messageTextField.getText() != null 
        && !messageTextField.getText().isEmpty()) { 
       sendMsg(); 
      } 
     } 
    }); 
    messageSection.getChildren().add(messageTextField); 
    messageSection.getChildren().add(sendMsgButton); 
    messageSection.setPrefHeight(sectionHeight); 

    rootPane.setTop(contactSection); 
    rootPane.setCenter(conversationSection); 
    rootPane.setBottom(messageSection); 

    Scene scene = new Scene(rootPane); 
    AppMain.stage.setScene(scene); 
    AppMain.stage.setTitle("WhatsApp"); 
} 
} 



public class AppMain extends Application { 
static Stage stage; 

@Override 
public void start(Stage primaryStage) throws Exception { 
    stage = primaryStage; 
    AppMain.stage.show(); 
    changeView(new ConversationView()); 
} 
public static void changeView(WhatAppView view) { 
    view.showView(); 
} 
} 

public interface WhatAppView { 
    public void showView(); 
} 
+1

http://stackoverflow.com/questions/7026507/почему-являются-статическим переменными-рассмотренным зло – fabian

+0

@Fabian даже для GUI? –

ответ

1

Вы можете создать пользовательский элемент управления, чтобы определить выравнивание сообщения и эстетику, такие как пузырь, как внешний вид. В качестве поклонника HBox и VBox я рекомендовал бы их использование в сочетании с SVGPath, чтобы украсить сообщение.

SVGPath позволяет создавать пользовательские фигуры, предоставляя информацию о строках, дугах и т. Д. Они не уникальны для java, поэтому есть несколько доступных ресурсов, чтобы увидеть некоторые базовые/расширенные примеры. Моя рекомендация будет прочитать здесь: SVGPath и использовать TryitEditor экспериментировать

Вот два простых примеров: enter image description here


Когда дело доходит до раскладывать сообщения в VBox окажется вполне достаточно. Вы можете привязать просмотренных детей к сообщениям ObservableList, которые вы сможете выполнить итерацией позже. Дополнительным преимуществом этого является то, что добавление в список будет автоматически обновлять пользовательский интерфейс, и вы также сможете повторить их позже, если вы реализуете дополнительные функции, такие как удаление, переадресация и т. Д.

Я бы рекомендовал прочитать вверх на Bindings апи, особенно bindContentBidirectional для получения дополнительной информации об этой


Используя мои вышеизложенные рекомендации я написал небольшой пример ниже вы можете ссылаться. Это визуально не впечатляет, но, надеюсь, вы можете получить некоторые идеи из него, в частности, это:

Дополнительно: если вы можете помочь мне сделать чат пузырь за текстом, это было бы здорово.

Сообщения/речевые пузыри:

enum SpeechDirection{ 
    LEFT, RIGHT 
} 

public class SpeechBox extends HBox{ 
    private Color DEFAULT_SENDER_COLOR = Color.GOLD; 
    private Color DEFAULT_RECEIVER_COLOR = Color.LIMEGREEN; 
    private Background DEFAULT_SENDER_BACKGROUND, DEFAULT_RECEIVER_BACKGROUND; 

    private String message; 
    private SpeechDirection direction; 

    private Label displayedText; 
    private SVGPath directionIndicator; 

    public SpeechBox(String message, SpeechDirection direction){ 
     this.message = message; 
     this.direction = direction; 
     initialiseDefaults(); 
     setupElements(); 
    } 

    private void initialiseDefaults(){ 
     DEFAULT_SENDER_BACKGROUND = new Background(
       new BackgroundFill(DEFAULT_SENDER_COLOR, new CornerRadii(5,0,5,5,false), Insets.EMPTY)); 
     DEFAULT_RECEIVER_BACKGROUND = new Background(
       new BackgroundFill(DEFAULT_RECEIVER_COLOR, new CornerRadii(0,5,5,5,false), Insets.EMPTY)); 
    } 

    private void setupElements(){ 
     displayedText = new Label(message); 
     displayedText.setPadding(new Insets(5)); 
     displayedText.setWrapText(true); 
     directionIndicator = new SVGPath(); 

     if(direction == SpeechDirection.LEFT){ 
      configureForReceiver(); 
     } 
     else{ 
      configureForSender(); 
     } 
    } 

    private void configureForSender(){ 
     displayedText.setBackground(DEFAULT_SENDER_BACKGROUND); 
     displayedText.setAlignment(Pos.CENTER_RIGHT); 
     directionIndicator.setContent("M10 0 L0 10 L0 0 Z"); 
     directionIndicator.setFill(DEFAULT_SENDER_COLOR); 

     HBox container = new HBox(displayedText, directionIndicator); 
     //Use at most 75% of the width provided to the SpeechBox for displaying the message 
     container.maxWidthProperty().bind(widthProperty().multiply(0.75)); 
     getChildren().setAll(container); 
     setAlignment(Pos.CENTER_RIGHT); 
    } 

    private void configureForReceiver(){ 
     displayedText.setBackground(DEFAULT_RECEIVER_BACKGROUND); 
     displayedText.setAlignment(Pos.CENTER_LEFT); 
     directionIndicator.setContent("M0 0 L10 0 L10 10 Z"); 
     directionIndicator.setFill(DEFAULT_RECEIVER_COLOR); 

     HBox container = new HBox(directionIndicator, displayedText); 
     //Use at most 75% of the width provided to the SpeechBox for displaying the message 
     container.maxWidthProperty().bind(widthProperty().multiply(0.75)); 
     getChildren().setAll(container); 
     setAlignment(Pos.CENTER_LEFT); 
    } 
} 

Разговор окно:

public class ConversationView extends VBox{ 
    private String conversationPartner; 
    private ObservableList<Node> speechBubbles = FXCollections.observableArrayList(); 

    private Label contactHeader; 
    private ScrollPane messageScroller; 
    private VBox messageContainer; 
    private HBox inputContainer; 

    public ConversationView(String conversationPartner){ 
     super(5); 
     this.conversationPartner = conversationPartner; 
     setupElements(); 
    } 

    private void setupElements(){ 
     setupContactHeader(); 
     setupMessageDisplay(); 
     setupInputDisplay(); 
     getChildren().setAll(contactHeader, messageScroller, inputContainer); 
     setPadding(new Insets(5)); 
    } 

    private void setupContactHeader(){ 
     contactHeader = new Label(conversationPartner); 
     contactHeader.setAlignment(Pos.CENTER); 
     contactHeader.setFont(Font.font("Comic Sans MS", 14)); 
    } 

    private void setupMessageDisplay(){ 
     messageContainer = new VBox(5); 
     Bindings.bindContentBidirectional(speechBubbles, messageContainer.getChildren()); 

     messageScroller = new ScrollPane(messageContainer); 
     messageScroller.setVbarPolicy(ScrollBarPolicy.AS_NEEDED); 
     messageScroller.setHbarPolicy(ScrollBarPolicy.NEVER); 
     messageScroller.setPrefHeight(300); 
     messageScroller.prefWidthProperty().bind(messageContainer.prefWidthProperty().subtract(5)); 
     messageScroller.setFitToWidth(true); 
     //Make the scroller scroll to the bottom when a new message is added 
     speechBubbles.addListener((ListChangeListener<Node>) change -> { 
      while (change.next()) { 
       if(change.wasAdded()){ 
        messageScroller.setVvalue(messageScroller.getVmax()); 
       } 
      } 
     }); 
    } 

    private void setupInputDisplay(){ 
     inputContainer = new HBox(5); 

     TextField userInput = new TextField(); 
     userInput.setPromptText("Enter message"); 

     Button sendMessageButton = new Button("Send"); 
     sendMessageButton.disableProperty().bind(userInput.lengthProperty().isEqualTo(0)); 
     sendMessageButton.setOnAction(event-> { 
      sendMessage(userInput.getText()); 
      userInput.setText(""); 
     }); 

     //For testing purposes 
     Button receiveMessageButton = new Button("Receive"); 
     receiveMessageButton.disableProperty().bind(userInput.lengthProperty().isEqualTo(0)); 
     receiveMessageButton.setOnAction(event-> { 
      receiveMessage(userInput.getText()); 
      userInput.setText(""); 
     }); 

     inputContainer.getChildren().setAll(userInput, sendMessageButton, receiveMessageButton); 
    } 

    public void sendMessage(String message){ 
     speechBubbles.add(new SpeechBox(message, SpeechDirection.RIGHT)); 
    } 

    public void receiveMessage(String message){ 
     speechBubbles.add(new SpeechBox(message, SpeechDirection.LEFT)); 
    } 
} 

Выход:

enter image description here

+0

спасибо помощнику. отличный пример –