JavaFX 8:添加新选项卡时不稳定的交互式 TabPane
JavaFX 8: Unstable interactive TabPane when adding new Tab
我正在制作一个高度交互的 TabPane,用于在 JavaFX 8 中查看联系人列表。为此,我制作了自己的 Tab 子类 EditableTab,它具有通过双击名称更改选项卡名称的功能概述。当用户点击+号创建一个新的联系人列表时,我想让程序创建一个新的选项卡,select它,然后关注名字和select所有的文本——名字很自然联系人列表(类似于在 windows 中创建新文件)。
我的问题:这似乎很不稳定。大多数时候,似乎出现了某种 animation/transition 问题,选项卡名称最终为空。这是单击 + 按钮时 通常但并非总是 发生的情况的屏幕截图:
这就是我想要的:
这是我的 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();
}
我怀疑问题出在某些 animation/transition 时间上,但这实际上只是一个猜测。我尝试将 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();
}
}
这是我的代码 RenamableTab
class:
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();
}
}
我在选择另一个选项卡时出现了新选项卡按钮问题,不确定您是如何克服的。
我正在制作一个高度交互的 TabPane,用于在 JavaFX 8 中查看联系人列表。为此,我制作了自己的 Tab 子类 EditableTab,它具有通过双击名称更改选项卡名称的功能概述。当用户点击+号创建一个新的联系人列表时,我想让程序创建一个新的选项卡,select它,然后关注名字和select所有的文本——名字很自然联系人列表(类似于在 windows 中创建新文件)。
我的问题:这似乎很不稳定。大多数时候,似乎出现了某种 animation/transition 问题,选项卡名称最终为空。这是单击 + 按钮时 通常但并非总是 发生的情况的屏幕截图:
这就是我想要的:
这是我的 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();
}
我怀疑问题出在某些 animation/transition 时间上,但这实际上只是一个猜测。我尝试将 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();
}
}
这是我的代码 RenamableTab
class:
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();
}
}
我在选择另一个选项卡时出现了新选项卡按钮问题,不确定您是如何克服的。