我想让一个微调框输入时间,就像这样:YoutubeVidéo
如果有人知道源代码隐藏在哪里,那将是完美的。但是,如果没有,我想尝试自己实现,但是我该如何使3个不同的(可聚焦的)文本区域像这样?
编辑:这是我所得到的,但是我希望能够选择小时数并增加小时数,而不仅仅是分钟数(和c的秒数相同)
Spinner<LocalTime> spinner = new Spinner(new SpinnerValueFactory() {
{
setConverter(new LocalTimeStringConverter(FormatStyle.MEDIUM));
}
@Override
public void decrement(int steps) {
if (getValue() == null)
setValue(LocalTime.now());
else {
LocalTime time = (LocalTime) getValue();
setValue(time.minusMinutes(steps));
}
}
@Override
public void increment(int steps) {
if (this.getValue() == null)
setValue(LocalTime.now());
else {
LocalTime time = (LocalTime) getValue();
setValue(time.plusMinutes(steps));
}
}
});
spinner.setEditable(true);
这是我得到的结果:
谢谢
我认为选择编辑器各个部分的最佳方法是检查caretPosition
编辑器中的内容,并根据需要增加/减少适当的部分。您还可以TextFormatter
在编辑器上设置a
来控制允许的输入等。
这是一个快速尝试:并非要达到生产质量,而应该是一个好的开始:
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import javafx.scene.control.TextFormatter;
import javafx.scene.input.InputEvent;
import javafx.util.StringConverter;
public class TimeSpinner extends Spinner<LocalTime> {
// Mode represents the unit that is currently being edited.
// For convenience expose methods for incrementing and decrementing that
// unit, and for selecting the appropriate portion in a spinner's editor
enum Mode {
HOURS {
@Override
LocalTime increment(LocalTime time, int steps) {
return time.plusHours(steps);
}
@Override
void select(TimeSpinner spinner) {
int index = spinner.getEditor().getText().indexOf(':');
spinner.getEditor().selectRange(0, index);
}
},
MINUTES {
@Override
LocalTime increment(LocalTime time, int steps) {
return time.plusMinutes(steps);
}
@Override
void select(TimeSpinner spinner) {
int hrIndex = spinner.getEditor().getText().indexOf(':');
int minIndex = spinner.getEditor().getText().indexOf(':', hrIndex + 1);
spinner.getEditor().selectRange(hrIndex+1, minIndex);
}
},
SECONDS {
@Override
LocalTime increment(LocalTime time, int steps) {
return time.plusSeconds(steps);
}
@Override
void select(TimeSpinner spinner) {
int index = spinner.getEditor().getText().lastIndexOf(':');
spinner.getEditor().selectRange(index+1, spinner.getEditor().getText().length());
}
};
abstract LocalTime increment(LocalTime time, int steps);
abstract void select(TimeSpinner spinner);
LocalTime decrement(LocalTime time, int steps) {
return increment(time, -steps);
}
}
// Property containing the current editing mode:
private final ObjectProperty<Mode> mode = new SimpleObjectProperty<>(Mode.HOURS) ;
public ObjectProperty<Mode> modeProperty() {
return mode;
}
public final Mode getMode() {
return modeProperty().get();
}
public final void setMode(Mode mode) {
modeProperty().set(mode);
}
public TimeSpinner(LocalTime time) {
setEditable(true);
// Create a StringConverter for converting between the text in the
// editor and the actual value:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
StringConverter<LocalTime> localTimeConverter = new StringConverter<LocalTime>() {
@Override
public String toString(LocalTime time) {
return formatter.format(time);
}
@Override
public LocalTime fromString(String string) {
String[] tokens = string.split(":");
int hours = getIntField(tokens, 0);
int minutes = getIntField(tokens, 1) ;
int seconds = getIntField(tokens, 2);
int totalSeconds = (hours * 60 + minutes) * 60 + seconds ;
return LocalTime.of((totalSeconds / 3600) % 24, (totalSeconds / 60) % 60, seconds % 60);
}
private int getIntField(String[] tokens, int index) {
if (tokens.length <= index || tokens[index].isEmpty()) {
return 0 ;
}
return Integer.parseInt(tokens[index]);
}
};
// The textFormatter both manages the text <-> LocalTime conversion,
// and vetoes any edits that are not valid. We just make sure we have
// two colons and only digits in between:
TextFormatter<LocalTime> textFormatter = new TextFormatter<LocalTime>(localTimeConverter, LocalTime.now(), c -> {
String newText = c.getControlNewText();
if (newText.matches("[0-9]{0,2}:[0-9]{0,2}:[0-9]{0,2}")) {
return c ;
}
return null ;
});
// The spinner value factory defines increment and decrement by
// delegating to the current editing mode:
SpinnerValueFactory<LocalTime> valueFactory = new SpinnerValueFactory<LocalTime>() {
{
setConverter(localTimeConverter);
setValue(time);
}
@Override
public void decrement(int steps) {
setValue(mode.get().decrement(getValue(), steps));
mode.get().select(TimeSpinner.this);
}
@Override
public void increment(int steps) {
setValue(mode.get().increment(getValue(), steps));
mode.get().select(TimeSpinner.this);
}
};
this.setValueFactory(valueFactory);
this.getEditor().setTextFormatter(textFormatter);
// Update the mode when the user interacts with the editor.
// This is a bit of a hack, e.g. calling spinner.getEditor().positionCaret()
// could result in incorrect state. Directly observing the caretPostion
// didn't work well though; getting that to work properly might be
// a better approach in the long run.
this.getEditor().addEventHandler(InputEvent.ANY, e -> {
int caretPos = this.getEditor().getCaretPosition();
int hrIndex = this.getEditor().getText().indexOf(':');
int minIndex = this.getEditor().getText().indexOf(':', hrIndex + 1);
if (caretPos <= hrIndex) {
mode.set( Mode.HOURS );
} else if (caretPos <= minIndex) {
mode.set( Mode.MINUTES );
} else {
mode.set( Mode.SECONDS );
}
});
// When the mode changes, select the new portion:
mode.addListener((obs, oldMode, newMode) -> newMode.select(this));
}
public TimeSpinner() {
this(LocalTime.now());
}
}
这是一个使用它的简单示例:
import java.time.format.DateTimeFormatter;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TimeSpinnerExample extends Application {
@Override
public void start(Stage primaryStage) {
TimeSpinner spinner = new TimeSpinner();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm:ss a");
spinner.valueProperty().addListener((obs, oldTime, newTime) ->
System.out.println(formatter.format(newTime)));
StackPane root = new StackPane(spinner);
Scene scene = new Scene(root, 350, 120);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
问题内容: StackPane 。我想在Java文件中创建值和静态值,以便可以将其用于其他文件。 这可能吗? 问题答案: 如果您的常数是在类别中定义: 那么您可以按以下方式在FXML中进行访问: 确保在fxml文件中已对要使用的类进行了适当的导入。
我正在开发我的第一个应用程序,我的GUI部分使用javafx。在此代码中,按下按钮时,我正在尝试连接到邮件服务器: 但我有一个问题: 异常线程"Thread-4"ase.handleIllegalStateException:不在FX应用程序线程上;当前线程=Thread-4在ase.java:204Tcom.sun.javafx.scene.control.skin.FxUserThread(T
FXML1-menu开始: fxml2-rules的开始(第14行的错误是这里的第一行,在此之前,这里只是预先导入):
问题内容: 喜欢标题中的内容如何对.txt文件进行过滤? 我写了这样的东西,但有错误:( 问题答案: 在这里,您将找到一些工作示例。这也是JFileChooser中使用的FileFilter的一个很好的示例。 基础是,您需要重写FileFilter类,并在其accpet方法中编写自定义代码。上例中的accept方法是根据文件类型进行过滤: 或更简单易用的是FileNameFilter,它具有以fi
问题内容: 在我的数据库方案中,我需要一个自动增量主键。我如何实现此功能? PS要访问DynamoDB,我使用倍增极了Node.js的,模块 问题答案: 免责声明:我是Dynamodb-mapper项目的维护者 自动递增键的直观工作流程: 获得最后的柜台位置 加1 使用新数字作为对象的索引 保存新的计数器值 保存对象 这只是为了解释基本思想。绝对不要这样做,因为它不是原子的。在某些工作负载下,您可