2015-06-20 2 views
2

Я делаю интерактивную TabPane для просмотра списков контактов в JavaFX 8. Для этого я создал свой собственный подкласс Tab, EditableTab, который имеет функции для изменения имени дважды щелкнув имя в обзоре. Когда пользователь нажимает знак + для создания нового списка контактов, я хочу, чтобы программа создала новую вкладку, выделила ее, затем сфокусировала имя и выделила весь текст - естественно назвать список контактов сразу (аналогично когда вы создаете новый файл в окнах).JavaFX 8: Нестабильная интерактивная TabPane при добавлении новой вкладки

Моя проблема: Это кажется очень неустойчивым. В большинстве случаев кажется, что возникает какая-то проблема анимации/перехода, а имя табуляции заканчивается пустым. Вот скриншот того, что обычно, но не всегда, происходит, когда кнопка + нажата: screenshot

И вот что я хочу: screenshot2

Вот код для моего EditableTab:

public class EditableTab extends Tab { 

private Label lbl; 
private TextField txtField; 

public EditableTab(String text, Node content) { 
    super(); 
    setContent(content); 
    lbl = new Label(text); 
    txtField = new TextField(text); 
    txtField.setStyle("-fx-background-color: transparent"); 
    setGraphic(lbl); 
    setupInteractivity(); 
} 

public TextField getTextField() { 
    return txtField; 
} 

private void setupInteractivity() { 
    lbl.setOnMouseClicked((mouseEvent) -> { 
     if (mouseEvent.getClickCount() == 2) { 
      showTextField(); 
     } 
    }); 

    txtField.setOnAction(event -> setGraphic(lbl)); 

    txtField.focusedProperty().addListener(
      (observable, oldValue, newValue) -> { 
     if (! newValue) { 
      lbl.setText(txtField.getText()); 
      setGraphic(lbl); 
     } 
    }); 
} 

public void showTextField() { 
    txtField.setPrefWidth(lbl.getWidth()); 
    txtField.setText(lbl.getText()); 
    setGraphic(txtField); 
    txtField.selectAll(); 
    txtField.requestFocus(); 
} 

}

А вот код, в котором реализована функциональность:

private void addNewContactlist() { 
    Contactlist newList = new Contactlist(); 
    newList.setName("New contact list"); 
    contactlistApp.getContactlistData().add(newList); 
    ListView<Person> lv = new ListView<Person>(newList.getContacts()); 
    setupListView(lv); 
    int position = tabPane.getTabs().size() - 1; 
    EditableTab tab = createEditableTab("New contact list", lv); 
    tabPane.getTabs().add(position, tab); 
    tabPane.getSelectionModel().select(tab); 
    tab.showTextField(); 
} 

Я подозреваю, что проблема связана с некоторыми таймингами анимации/перехода, но это действительно просто догадка. Я попробовал обернуть showTextField() звонок в Platform.runLater() без везения.

Вот небольшой тест приложение, чтобы повторить вопрос:

public class TestApp extends Application { 

TabPane tabPane = new TabPane(); 

@Override 
public void start(Stage primaryStage) throws Exception { 
    Tab addNewContactlistTab = new Tab(); 
    addNewContactlistTab.setClosable(false); 
    Label lbl = new Label("\u2795"); 

    lbl.setOnMouseClicked(mouseEvent -> { 
     if (tabPane.getTabs().size() == 1) { 
      addNewTab(); 
     } 
    }); 

    addNewContactlistTab.setGraphic(lbl); 
    tabPane.getTabs().add(addNewContactlistTab); 

    addNewContactlistTab.selectedProperty().addListener(
      (observable, oldValue, newValue) -> { 
     if (newValue && tabPane.getTabs().size() != 1) { 
      addNewTab(); 
     } 
    }); 

    Scene scene = new Scene(tabPane); 
    primaryStage.setScene(scene); 
    primaryStage.setWidth(600); 
    primaryStage.setHeight(400); 
    primaryStage.show(); 
} 

private void addNewTab() { 
    int insertionIndex = tabPane.getTabs().size() - 1; 
    ListView<String> lv = new ListView<String>(); 
    EditableTab tab = new EditableTab("Unnamed", lv); 
    tabPane.getTabs().add(insertionIndex, tab); 
    tabPane.getSelectionModel().select(tab); 
    tab.showTextField(); 
} 

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

}

ответ

1

Вот мой код RenamableTab класса:

import javafx.application.Platform; 
import javafx.scene.Node; 
import javafx.scene.control.Label; 
import javafx.scene.control.Tab; 
import javafx.scene.control.TextField; 

public class RenamableTab extends Tab { 
    private final Label  label; 
    private final TextField textField; 

    public RenamableTab() { 
     this("New Tab", null); 
    } 

    public RenamableTab(String text) { 
     this(text, null); 
    } 

    public RenamableTab(String text, Node content) { 
     super(); 
     label = new Label(text); 
     textField = new TextField(text); 
     setContent(content); 
     textField.setStyle("-fx-background-color: transparent"); 
     setGraphic(label); 
     label.setOnMouseClicked((mouseEvent) -> { 
      if (mouseEvent.getClickCount() == 2) { 
       rename(); 
      } 
     }); 
     textField.setOnAction(event -> setGraphic(label)); 
     textField.focusedProperty().addListener((observable, oldValue, newValue) -> { 
      if (!newValue) { 
       label.setText(textField.getText()); 
       setGraphic(label); 
      } 
     }); 
    } 

    public TextField getTextField() { 
     return textField; 
    } 

    public void rename() { 
     //textField.setPrefWidth(label.getWidth()); 
     //textField.setText(label.getText()); 
     setGraphic(textField); 
     new Thread() { 
      @Override 
      public void run() { 
       try { 
        Thread.sleep(300); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
       Platform.runLater(new Runnable() { 
        @Override 
        public void run() { 
         textField.selectAll(); 
         textField.requestFocus(); 
        } 
       }); 
      } 
     }.start(); 
    } 
} 

А вот мой код для FancyTabPane:

import javafx.event.EventHandler; 
import javafx.scene.control.Label; 
import javafx.scene.control.Tab; 
import javafx.scene.control.TabPane; 
import javafx.scene.input.MouseEvent; 

public class FancyTabPane extends TabPane { 
    public FancyTabPane() { 
     Tab newTabTab = new Tab(); 
     newTabTab.setClosable(false); 
     Label addLabel = new Label("\u2795"); 
     addLabel.setOnMouseClicked(new EventHandler<MouseEvent>() { 
      @Override 
      public void handle(MouseEvent paramT) { 
       System.out.println("mouse click"); 
       addTab(); 
      } 
     }); 
     /* 
     * getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() { 
     * @Override 
     * public void changed(ObservableValue<? extends Tab> paramObservableValue, Tab paramT1, Tab 
     * paramT2) { 
     * System.out.println("model"); 
     * if (paramT1 == newTabTab) { 
     * System.out.println("tab"); 
     * addTab(); 
     * } 
     * } 
     * }); 
     */ 
     newTabTab.setGraphic(addLabel); 
     getTabs().add(newTabTab); 
    } 

    public void addTab() { 
     RenamableTab newTab = new RenamableTab(); 
     getTabs().add(getTabs().size() - 1, newTab); 
     getSelectionModel().select(newTab); 
     newTab.rename(); 
    } 
} 

Я выбрал новую кнопку вкладки, когда выбрана другая вкладка, не уверен, как вы ее преодолели.

+0

Спасибо! Однако, по крайней мере, на моем компьютере, это все равно не будет выбирать весь текст и готово TextField для редактирования. – TAsk

+1

Это странно, я все еще работаю над этим. –

+1

Действительно! Я склоняюсь к отказу от функциональности. Нажатие кнопки для переименования немедленно может повредить рабочий процесс. – TAsk

Смежные вопросы