我有 Trade 对象类和一个
public class Trade {
private DoubleProperty price;
private ReadOnlyBooleanWrapper caution;
public Trade(double price){
this.price = new SimpleDoubleProperty(price);
this.caution = new ReadOnlyBooleanWrapper();
this.caution.bind(this.volume.greaterThan(0));
}
public double getPrice(){
return this.price.get();
}
public DoubleProperty priceProperty(){
return this.price;
}
public void setPrice(double price){
this.price.set(price);
}
}
在我的 Controller 类中,我有以下 TableView 和 TableColumn
问题有两个:
double。但是下面的 EditingDoubleCell 代码只返回 String。 我怎样才能让它返回 double 值,并且用户输入的所有 String 都将被忽略?Price 列单元格内的字体(谈论相同的价格单元格)会将其颜色更改为蓝色当 caution 属性为 true 时变为红色 当 caution 属性为 false 时?public class EditingDoubleCell extends TableCell<Trade,String>{
private TextField textField;
public EditingDoubleCell() {
}
@Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.requestFocus();
//textField.selectAll();
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
private void createTextField(){
Locale locale = new Locale("en", "UK");
String pattern = "###,###.###";
DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(locale);
df.applyPattern(pattern);
//String format = df.format(123456789.123);
//System.out.println(format);
//NumberFormat nf = NumberFormat.getIntegerInstance();
textField = new TextField();
// add filter to allow for typing only integer
textField.setTextFormatter( new TextFormatter<>( c ->
{
if (c.getControlNewText().isEmpty()) {
return c;
}
ParsePosition parsePosition = new ParsePosition( 0 );
Object object = df.parse( c.getControlNewText(), parsePosition );
if ( object == null || parsePosition.getIndex() < c.getControlNewText().length() )
{
return null;
}
else
{
return c;
}
} ) );
textField.setText( getString() );
textField.setMinWidth( this.getWidth() - this.getGraphicTextGap() * 2 );
// commit on Enter
textField.setOnAction( new EventHandler<ActionEvent>()
{
@Override
public void handle( ActionEvent event )
{
commitEdit( textField.getText() );
}
} );
textField.focusedProperty().addListener( new ChangeListener<Boolean>()
{
@Override
public void changed( ObservableValue<? extends Boolean> arg0,
Boolean arg1, Boolean arg2 )
{
if ( !arg2 )
{
commitEdit( textField.getText() );
}
}
} );
}
}
最佳答案
对于问题的第一部分,您应该创建自己的 TextFormatter作为TextFormatter<Double> .这使得 valueProperty的 TextFormatter进入Property<Double> , 因此您可以通过调用 getValue() 来提交您的编辑在格式化板上。您需要指定一个 StringConverter<Double>这样它就知道如何从文本到 Double ,反之亦然。所以这看起来像:
StringConverter<Double> converter = new StringConverter<Double>() {
@Override
public String toString(Double number) {
return df.format(number);
}
@Override
public Double fromString(String string) {
try {
double value = df.parse(string).doubleValue() ;
return value;
} catch (ParseException e) {
e.printStackTrace();
return 0.0 ;
}
}
};
textFormatter = new TextFormatter<>(converter, 0.0, c -> {
if (partialInputPattern.matcher(c.getControlNewText()).matches()) {
return c ;
} else {
return null ;
}
}) ;
我在这里更改了过滤器,因为您的过滤器只匹配“完整”输入。由于过滤器应用于每个单独的编辑,因此您必须允许“部分”输入,例如 "100," .您拥有的过滤器不允许这样做(例如)。此处版本中的过滤器使用正则表达式:您可以修改它以使其正确,但我使用
Pattern partialInputPattern = Pattern.compile(""[-+]?[,0-9]*(\\.[0-9]*)?");
这对它允许的内容相当宽松。
现在,不是在用户按下回车时直接提交编辑,而是在文本格式化程序的值更改时提交编辑:
// commit on Enter
textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> {
commitEdit(newValue);
});
整个细胞类现在看起来像
public static class EditingDoubleCell extends TableCell<Trade,Double>{
private TextField textField;
private TextFormatter<Double> textFormatter ;
private DecimalFormat df ;
public EditingDoubleCell(String...styleClasses) {
Locale locale = new Locale("en", "UK");
String pattern = "###,###.###";
df = (DecimalFormat) NumberFormat.getNumberInstance(locale);
df.applyPattern(pattern);
getStyleClass().addAll(styleClasses);
}
@Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.requestFocus();
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText(df.format(getItem()));
setGraphic(null);
}
@Override
public void updateItem(Double item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private String getString() {
return getItem() == null ? "" : df.format(getItem());
}
private void createTextField(){
textField = new TextField();
StringConverter<Double> converter = new StringConverter<Double>() {
@Override
public String toString(Double number) {
return df.format(number);
}
@Override
public Double fromString(String string) {
try {
double value = df.parse(string).doubleValue() ;
return value;
} catch (ParseException e) {
e.printStackTrace();
return 0.0 ;
}
}
};
textFormatter = new TextFormatter<>(converter, 0.0, c ->
{
if (c.getControlNewText().isEmpty()) {
return c;
}
ParsePosition parsePosition = new ParsePosition( 0 );
Object object = df.parse( c.getControlNewText(), parsePosition );
if ( object == null || parsePosition.getIndex() < c.getControlNewText().length() )
{
return null;
}
else
{
return c;
}
} ) ;
// add filter to allow for typing only integer
textField.setTextFormatter( textFormatter);
textField.setText( getString() );
textField.setMinWidth( this.getWidth() - this.getGraphicTextGap() * 2 );
// commit on Enter
textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> {
commitEdit(newValue);
});
}
}
(我添加了构造函数参数,因此它将与您第二个问题的解决方案一起使用。)
第二部分在别处得到了回答,但我只想创建一个 rowFactory对于根据警告属性的状态设置 CSS 伪类的表格:
PseudoClass caution = PseudoClass.getPseudoClass("caution");
table.setRowFactory(tv -> {
TableRow<Trade> row = new TableRow<>();
ChangeListener<Boolean> cautionListener = (obs, wasCaution, isNowCaution) ->
row.pseudoClassStateChanged(caution, isNowCaution);
row.itemProperty().addListener((obs, oldTrade, newTrade) -> {
if (oldTrade != null) {
oldTrade.cautionProperty().removeListener(cautionListener);
}
if (newTrade == null) {
row.pseudoClassStateChanged(caution, false);
} else {
row.pseudoClassStateChanged(caution, newTrade.isCaution());
newTrade.cautionProperty().addListener(cautionListener);
}
});
return row ;
});
然后只需在要更改样式的单元格上设置样式类(例如,将样式类 "price-cell" 添加到您定义的 EditingDoubleCell 中)。然后,您可以只使用 CSS 样式表根据需要更改样式,例如
.table-row-cell .price-cell {
-fx-text-fill: red ;
}
.table-row-cell:caution .price-cell {
-fx-text-fill: blue ;
}
将使行中没有 caution 的价格单元格的文本变为红色设置,并在需要的行中将其设置为蓝色。
这是完整的 SSCCE:
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.function.Function;
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class TradeTable extends Application {
private final Random rng = new Random();
@Override
public void start(Stage primaryStage) {
TableView<Trade> table = new TableView<>();
table.setEditable(true);
TableColumn<Trade, Integer> volumeCol = column("Volume", trade -> trade.volumeProperty().asObject());
TableColumn<Trade, Double> priceCol = column("Price", trade -> trade.priceProperty().asObject());
priceCol.setCellFactory(col -> new EditingDoubleCell("price-cell"));
table.getColumns().add(volumeCol);
table.getColumns().add(priceCol);
PseudoClass caution = PseudoClass.getPseudoClass("caution");
table.setRowFactory(tv -> {
TableRow<Trade> row = new TableRow<>();
ChangeListener<Boolean> cautionListener = (obs, wasCaution, isNowCaution) ->
row.pseudoClassStateChanged(caution, isNowCaution);
row.itemProperty().addListener((obs, oldTrade, newTrade) -> {
if (oldTrade != null) {
oldTrade.cautionProperty().removeListener(cautionListener);
}
if (newTrade == null) {
row.pseudoClassStateChanged(caution, false);
} else {
row.pseudoClassStateChanged(caution, newTrade.isCaution());
newTrade.cautionProperty().addListener(cautionListener);
}
});
return row ;
});
table.getItems().addAll(createRandomData());
Button button = new Button("Change Data");
button.setOnAction(e -> table.getItems().forEach(trade -> {
if (rng.nextDouble() < 0.5) {
trade.setVolume(0);
} else {
trade.setVolume(rng.nextInt(10000));
}
trade.setPrice(rng.nextDouble() * 1000);
}));
BorderPane.setAlignment(button, Pos.CENTER);
BorderPane.setMargin(button, new Insets(10));
BorderPane root = new BorderPane(table, null, null, button, null);
Scene scene = new Scene(root, 600, 600);
scene.getStylesheets().add("trade-table.css");
primaryStage.setScene(scene);
primaryStage.show();
}
private List<Trade> createRandomData() {
List<Trade> trades = new ArrayList<>(50);
for (int i = 0 ; i < 50; i++) {
int volume = rng.nextDouble() < 0.5 ? 0 : rng.nextInt(10000) ;
double price = rng.nextDouble() * 10000 ;
trades.add(new Trade(price, volume));
}
return trades ;
}
private static <S,T> TableColumn<S,T> column(String title, Function<S, ObservableValue<T>> property) {
TableColumn<S,T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
return col ;
}
public static class Trade {
private DoubleProperty price;
private IntegerProperty volume ;
private ReadOnlyBooleanWrapper caution;
public Trade(double price, int volume){
this.price = new SimpleDoubleProperty(price);
this.volume = new SimpleIntegerProperty(volume);
this.caution = new ReadOnlyBooleanWrapper();
this.caution.bind(this.volume.greaterThan(0));
}
public double getPrice(){
return this.price.get();
}
public DoubleProperty priceProperty(){
return this.price;
}
public void setPrice(double price){
this.price.set(price);
}
public final IntegerProperty volumeProperty() {
return this.volume;
}
public final int getVolume() {
return this.volumeProperty().get();
}
public final void setVolume(final int volume) {
this.volumeProperty().set(volume);
}
public final ReadOnlyBooleanProperty cautionProperty() {
return this.caution.getReadOnlyProperty();
}
public final boolean isCaution() {
return this.cautionProperty().get();
}
}
public static class EditingDoubleCell extends TableCell<Trade,Double>{
private TextField textField;
private TextFormatter<Double> textFormatter ;
private Pattern partialInputPattern = Pattern.compile(
"[-+]?[,0-9]*(\\.[0-9]*)?");
private DecimalFormat df ;
public EditingDoubleCell(String...styleClasses) {
Locale locale = new Locale("en", "UK");
String pattern = "###,###.###";
df = (DecimalFormat) NumberFormat.getNumberInstance(locale);
df.applyPattern(pattern);
getStyleClass().addAll(styleClasses);
}
@Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.requestFocus();
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText(df.format(getItem()));
setGraphic(null);
}
@Override
public void updateItem(Double item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private String getString() {
return getItem() == null ? "" : df.format(getItem());
}
private void createTextField(){
textField = new TextField();
StringConverter<Double> converter = new StringConverter<Double>() {
@Override
public String toString(Double number) {
return df.format(number);
}
@Override
public Double fromString(String string) {
try {
double value = df.parse(string).doubleValue() ;
return value;
} catch (ParseException e) {
e.printStackTrace();
return 0.0 ;
}
}
};
textFormatter = new TextFormatter<>(converter, 0.0, c -> {
if (partialInputPattern.matcher(c.getControlNewText()).matches()) {
return c ;
} else {
return null ;
}
}) ;
// add filter to allow for typing only integer
textField.setTextFormatter( textFormatter);
textField.setText( getString() );
textField.setMinWidth( this.getWidth() - this.getGraphicTextGap() * 2 );
// commit on Enter
textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> {
commitEdit(newValue);
});
}
}
public static void main(String[] args) {
launch(args);
}
}
使用上面 trade-table.css 中的 CSS 代码。
关于javafx:如何使 TableCell Edit 返回 double 而不是字符串,并且字体会根据条件更改颜色?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32188676/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje