javafx笔记
资料网址 javafx css
https://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html
布局
GridPane p=new GridPane();// 清除或移除某个子节点
p.getChildren().clear(); //清空面板
p.getChildren().remove(int index); //根据下标去除结点
p.getChildren().remove(Node ); //去除node结点
p.getChildren().remove(int form,int to); //根据范围去除结点
p.getChildren().removeAll(Node...elements) //根据一个Node组去除结点
splitPane禁用调整
SplitPane.Divider divider = splitPane.getDividers().get(0);divider.positionProperty().addListener(new ChangeListener<Number>() {@Overridepublic void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {divider.setPosition(0.6);}});
在javafx中使用ECharts展示图表
基本
新建WebView,javafx.scene.web.WebView
向pane中添加WebView,borderPane.setCenter(webView)
获取web引擎,webEngine=webView.getEngine()
web引擎中加载HTML页面,webEngine.load(url)
禁用WebView上下文菜单,webView.setContextMenuEnabled(false)
加载文档时侦听状态更改,webEngine.getLoadWorker().stateProperty().addListener(
执行js,webEngine.executeScript(“myFunction()”);
加载数据
在webEngine.getLoadWorker().stateProperty().addListener()中
调整窗口大小
先获取window对象,JSObject win = (JSObject) webEngine.executeScript(“window”);
获取webView的宽和高,Double height = browser.getHeight();
新建窗口大小,ChartSize app = new ChartSize();
窗口大小赋值,
app.setHeight(height.intValue() - 200);
app.setWidth(width.intValue() - 30);
设置网页大小为定义的窗口的大小,win.setMember(“apps”, app);
执行脚本changeStyle(),webEngine.executeScript(“changeStyle()”);
加载数据
String script = charts.initLineOrBarsChart(names, labels, map, "", colors);
webEngine.executeScript(chartload);
控件通用
setFocusable 使控件能获得焦点,设置为true时,并不是说立刻获得焦点,要想立刻获得焦点,得用requestFocus
Frame f = new JFrame();
int intFlag = JOptionPane.showConfirmDialog(f,"删除" + name + "后,信息将不可恢复!您确定还继续吗?","警告", 0);
f.setFocusable(true);
f.requestFocus();
f.setAlwaysOnTop(true);
杂项
主线程问题
遇上 Not on FX application thread; currentThread = * 问题,使用以下方式解决
Platform.runLater(new Runnable() {@Overridepublic void run() {//更新JavaFX的主线程的代码放在此处}
});
设置遮罩层
使用canvas实现,放在stackPane的上面
canvas.setVisible(false);canvas.setWidth(1920);canvas.setHeight(1030);canvas.setMouseTransparent(true);GraphicsContext context = canvas.getGraphicsContext2D();context.setFont(Font.font("宋体", FontWeight.BOLD, 25));context.fillText("请稍等……", 900, 500);
另起线程执行非主页面的操作
private CompletableFuture<String> loadPageAsync(String[] info,ModuleTreeNode name1) {return CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000);return "ok";} catch (Exception e) {e.printStackTrace();return null;}});}...// 获取异步任务的结果CompletableFuture<String> result = completableFuture.thenApplyAsync(s -> {System.out.println("异步任务完成,结果:" + s);return s.toUpperCase();});
文本输入框 TextField
限定内容为数字
// 创建一个过滤器,只允许整数数字通过TextFormatter<Integer> textFormatter = new TextFormatter<>(new IntegerStringConverter(), 0, change -> {// 如果输入是有效的整数,则返回changeif (change.getControlNewText().matches("\\d*")) {return change;}// 如果输入无效,则返回null以阻止更改return null;});// 将过滤器应用到TextField上unitNumTF.setTextFormatter(textFormatter);
下拉框
// 添加选项list
combo.setItems(FXCollections.observableArrayList(arealist));// 选择第一个
combo.getSelectionModel().selectFirst();// 获取选择项的名称
String item = (String) combo.getSelectionModel().getSelectedItem();// 执行选项更新的动作
combo.setOnAction(e -> {String item = (String) combo.getSelectionModel().getSelectedItem();inittv(item);});
下拉搜索框
MyCheckBox.getComboBox(q11, tmplist);
操作数据时提示框
WaitingDialogFactory.popUpWaitingDialog(frame, calculateYItemThread, "正在提取数据...");
多选下拉组件
MyComboBox
单选按钮组
fxml中
<RadioButton mnemonicParsing="false" text="按地区排序" fx:id="sortByArea" toggleGroup="$toggleGroup">
<FlowPane.margin>
<Insets right="10.0"/>
</FlowPane.margin>
</RadioButton>
<RadioButton mnemonicParsing="false" text="按厂站排序" fx:id="sortByStation" toggleGroup="$toggleGroup">
<FlowPane.margin>
<Insets left="10.0" right="10.0"/>
</FlowPane.margin>
</RadioButton>
对应Controller文件中
@FXMLpublic RadioButton sortByArea;@FXMLpublic RadioButton sortByStation;@FXMLToggleGroup toggleGroup;
// 略toggleGroup = new ToggleGroup();sortByArea.setToggleGroup(toggleGroup);sortByStation.setToggleGroup(toggleGroup);toggleGroup.selectToggle(sortByArea);toggleGroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {@Overridepublic void changed(ObservableValue<? extends Toggle> observable, Toggle oldValue, Toggle newValue) {System.out.println("toggleGroup "+oldValue.toString()+" "+newValue.toString());}});
按钮功能文件选择导入导出
FileChooer类
FileChooser fileChooser = new FileChooser(); // 新建一个FileChooer类
fileChooser.setTitle("选择Excel文件"); // 设置标题
Stage selectFile = new Stage();
fileChooser.setInitialDirectory(new File(System.getProperty("user.home"))); // 设置初始打开的文件夹
fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("All Excel", "*.xlsx"),new FileChooser.ExtensionFilter("XLS", "*.xls"), new FileChooser.ExtensionFilter("XLSX", "*.xlsx")); // 设置可选择的文件类型
File file = fileChooser.showOpenDialog(selectFile); // 设置弹出文件选择窗口的依赖窗口
File file= fileChooser.showOpenDialog(importButton.getScene().getWindow()); // 也可以使用组件的窗口File file = fileChooser.showSaveDialog(null); // 导出的文件
通过前端获取组件
ScrollBar sb1 = (ScrollBar) tv1.lookup(".scroll-bar:vertical");
// ScrollBar sb2 = (ScrollBar) tv2.lookup(".scroll-bar:vertical");ScrollBar sb2 = (ScrollBar) tv2.queryAccessibleAttribute(AccessibleAttribute.VERTICAL_SCROLLBAR);
链接跳转与表格滚动定位选择
fxml文件
<TitledPane animated="false" collapsible="false" contentDisplay="CENTER" maxWidth="500.0" prefHeight="400.0" styleClass="flow-pane" text="校核结果">
<content>
<FlowPane alignment="TOP_CENTER" columnHalignment="CENTER" maxWidth="476.0" orientation="VERTICAL" prefHeight="370.0" styleClass="flow-pane">
<children>
<TextArea fx:id="textArea2" editable="false" maxWidth="474.0" prefHeight="90.0" wrapText="true" />
<TextFlow fx:id="textFlow" />
</children>
</FlowPane>
</content>
</TitledPane>
对应controller文件
tv.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {if (newValue != null) {
// System.out.println("新选择的数据项:" + newValue);Map<String, String> newV = (Map<String, String>) newValue;String s = newV.get("序号");String[] strings = dataList.get(Integer.parseInt(s) - 1);String msg = checkMap.getOrDefault(strings[9], "无");textArea1.setText(strings[2]);String[] msgs = msg.split("@");textArea2.setText(msgs[0]);textFlow.getChildren().clear();if (msgs.length>1){for (int i = 1; i < msgs.length; i++) {Hyperlink hyperlink = new Hyperlink(msgs[i]);int finalI = i;hyperlink.setOnAction(event -> {// 在此处添加链接点击时的逻辑
// System.out.println("Hyperlink clicked!");int index = 0;ObservableList items = tv.getItems();for (int j = 0; j < items.size(); j++) {Map<String, String> map = (Map<String, String>) items.get(j);String tdfw = map.get("停电范围");if (tdfw.equals(msgs[finalI])){index=j;break;}}tv.getSelectionModel().select(index);tv.scrollTo(index);});textFlow.getChildren().add(hyperlink);textFlow.getChildren().add(new javafx.scene.text.Text("\n"));}}upBtn.setDisable(tv.getSelectionModel().getSelectedIndex() == 0);downBtn.setDisable(false);}});
tableview
简介
javafx.scene.control.TableView
类型参数:S - TableView 项目列表中包含的对象的类型。
TableView 控件旨在可视化无限数量的数据行,分成列。 因此,TableView 与 ListView 控件非常相似,只是增加了对列的支持。 有关如何创建 TableView 的示例,请参阅下面的“创建 TableView”控件部分。
TableView 控件具有许多功能,包括:
-
强大的 TableColumn API:
-
支持单元工厂在渲染和编辑状态下轻松自定义单元内容。
-
minWidth/ prefWidth/ maxWidth 以及固定宽度列的规范。
-
用户在运行时调整宽度。
-
用户在运行时对列重新排序。
-
内置支持列嵌套
-
-
不同的调整大小策略来规定用户调整列大小时会发生什么。
-
通过单击列标题支持多列排序(按住 Shift 键盘键同时单击标题以按多列排序)。
请注意,TableView 旨在用于可视化数据 - 它不旨在用于布置您的用户界面。 如果您想以类似网格的方式布置您的用户界面,请考虑使用 GridPane 布局。
创建TableView
创建 TableView 是一个多步骤的过程,并且还取决于需要表示的底层数据模型。 对于这个例子,我们将使用 ObservableList,因为它是在 TableView 中显示数据的最简单方法。 Person 类将包含名字和姓氏属性。
创建并导入数据
方式1
在fxml文件中建立tableview标签,并添加id
<TableView fx:id="tv"/>
在对应的controller文件中注册
@FXMLprivate TableView<Map> tv;
添加列,同时绑定列的map键、设置列宽
TableColumn<Map, String> column = new TableColumn<>("列名");column.setCellValueFactory(new MapValueFactory<>("p"+i));column.setPrefWidth(colWidth[i]);tv.getColumns().add(column);
创建ObservableList,并把表格数据加载到ObservableList中,最后把数据放table中
ObservableList<Map> resdata = FXCollections.observableArrayList();if (!importList.isEmpty()){List<String[]> res2 = new ArrayList<>();HashSet<Integer> set1 = new HashSet<>();set1.add(30);set1.add(31);set1.add(32);set1.add(33);set1.add(34);set1.add(35);set1.add(36);set1.add(37);System.out.println("importList--"+ Arrays.toString(importList.get(0)));for (int i = 0; i < importList.size(); i++) {String[] strs = importList.get(i);Map<String,String> m = new HashMap<>();for (int j = 0,k = 0; j < strs.length; j++) {if (!set1.contains(j)){m.put("p"+k,strs[j]);k++;}}resdata.add(m);}tv.setItems(resdata);
方式2
for (int i = 0; i < TITLES.length; i++) {TableColumn<String, String> column = new TableColumn<>();column.setId(TITLES[i]);column.setText(TITLES[i]);column.setEditable(false);column.setStyle("-fx-alignment: CENTER;");column.setPrefWidth(TITLES_WIDTH[i]);column.setCellValueFactory(new MapValueFactory(TITLES[i]));column.setCellFactory(col -> new TableCell<String, String>() {@Overrideprotected void updateItem(String item, boolean empty) {super.updateItem(item, empty);if (item == null || empty) {setText(item);setTooltip(null);} else {setText(item);setTooltip(new Tooltip(item));}}});tv.getColumns().add(column);}tv.setRowFactory(tv -> new TableRow<Map>() {@Overrideprotected void updateItem(Map item, boolean empty) {super.updateItem(item, empty);// 在此处根据行内容设置背景色if (item != null) {String o = (String) item.get(TITLES[0]);String[] strs = dataList.get(Integer.parseInt(o)-1);if (checkMap.containsKey(strs[9])) {setStyle("-fx-background-color: #ff0000;");} else {setStyle("");}}}});tv.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {if (newValue != null) {
// System.out.println("新选择的数据项:" + newValue);Map<String, String> newV = (Map<String, String>) newValue;String s = newV.get("序号");String[] strings = dataList.get(Integer.parseInt(s)-1);String msg = checkMap.getOrDefault(strings[9], "无");textArea1.setText(strings[2]);textArea2.setText(msg);textArea3.setText("无");}});
导入数据
TableModeSet.setTableMode(tv, dataList);
模仿Excel的公式计算
TableColumn<Map, String> column5 = new TableColumn<>("增长率");column5.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Map, String>, ObservableValue<String>>() {@Overridepublic ObservableValue<String> call(TableColumn.CellDataFeatures<Map, String> param) {String c4Val = (String) param.getValue().get("c4");String c3Val = (String) param.getValue().get("c3");String resStr = "";try{double c4v = Integer.parseInt(c4Val);double c3v = Integer.parseInt(c3Val);double res = (c4v / c3v) - 1;resStr = df.format(res*100)+"%";} catch (NumberFormatException nfe){nfe.printStackTrace();}String finalResStr = resStr;return new ObservableValueBase<String>() {@Overridepublic String getValue() {return finalResStr;}};}});column5.setPrefWidth(100);
导出为Excel
方式1
ArrayList<String[]> exData = new ArrayList<>();int size = tv.getItems().size();for (int i = 0; i < size; i++) {String q0 = (String) tv.getColumns().get(0).getCellData(i);String q1 = (String) tv.getColumns().get(1).getCellData(i);String q2 = (String) tv.getColumns().get(2).getCellData(i);String q3 = (String) tv.getColumns().get(3).getCellData(i);String q5 = (String) tv.getColumns().get(5).getCellData(i);String q7 = (String) tv.getColumns().get(7).getCellData(i);String q9 = (String) tv.getColumns().get(9).getCellData(i);String q10 = (String) tv.getColumns().get(10).getCellData(i);String q11 = (String) tv.getColumns().get(11).getCellData(i);exData.add(new String[]{q0,q1,q2,q3,q5,q7,q9,q10,q11});}try(InputStream is = Constant.getExcelTemplateFile("ndjxphfx.xlsx")){if (is!=null){XSSFWorkbook workbook = new XSSFWorkbook(is);XSSFSheet sheet = workbook.getSheetAt(0);for (int i = 0; i < exData.size(); i++) {XSSFRow row = sheet.getRow(i + 2);String[] strs = exData.get(i);if (row.getCell(0)==null){row.createCell(0);}if (row.getCell(1)==null){row.createCell(1);}if (row.getCell(2)==null){row.createCell(2);}if (row.getCell(3)==null){row.createCell(3);}if (row.getCell(5)==null){row.createCell(5);}if (row.getCell(7)==null){row.createCell(7);}if (row.getCell(9)==null){row.createCell(9);}if (row.getCell(10)==null){row.createCell(10);}if (row.getCell(11)==null){row.createCell(11);}row.getCell(0).setCellValue(strs[0]);row.getCell(1).setCellValue(strs[1]);row.getCell(2).setCellValue(strs[2]);row.getCell(3).setCellValue(strs[3]);row.getCell(5).setCellValue(strs[4]);row.getCell(7).setCellValue(strs[5]);row.getCell(9).setCellValue(strs[6]);row.getCell(10).setCellValue(strs[7]);row.getCell(11).setCellValue(strs[8]);}FileChooser fc = new FileChooser();fc.setTitle(title);fc.setInitialFileName(title + ".xlsx");fc.getExtensionFilters().add(new FileChooser.ExtensionFilter("XLS Files", "*.xlsx",".xls"));File file = fc.showSaveDialog(null);OutputStream os = Files.newOutputStream(file.toPath());workbook.write(os);os.close();} else {Msg("未找到文件!!!");}} catch (IOException fnfe){fnfe.printStackTrace();}
方式2
if (dataList.isEmpty()) {Msg("无数据");return;}XSSFWorkbook wb = new XSSFWorkbook();// 设置标题行和正文的字体和单元格样式XSSFFont fontData = wb.createFont();fontData.setFontName("宋体");fontData.setFontHeightInPoints((short) 11);fontData.setBold(false);XSSFFont fontTitle = wb.createFont();fontTitle.setFontName("宋体");fontTitle.setFontHeightInPoints((short) 12);fontTitle.setBold(true);XSSFCellStyle styleData = wb.createCellStyle();styleData.setBorderTop((short) 1);styleData.setBorderBottom((short) 1);styleData.setBorderLeft((short) 1);styleData.setBorderRight((short) 1);styleData.setFont(fontData);styleData.setAlignment(HorizontalAlignment.CENTER);styleData.setVerticalAlignment(VerticalAlignment.CENTER);XSSFCellStyle styleTitle = wb.createCellStyle();styleTitle.setBorderTop((short) 1);styleTitle.setBorderBottom((short) 1);styleTitle.setBorderLeft((short) 1);styleTitle.setBorderRight((short) 1);styleTitle.setFont(fontTitle);styleTitle.setAlignment(HorizontalAlignment.CENTER);styleTitle.setVerticalAlignment(VerticalAlignment.CENTER);XSSFSheet sheet = wb.createSheet("情况");XSSFRow rowTitle = sheet.createRow(0);for (int i = 0; i < TITLES.length; i++) {XSSFCell cell = rowTitle.createCell(i, XSSFCell.CELL_TYPE_STRING);cell.setCellValue(TITLES[i]);}XSSFCell cell2 = rowTitle.createCell(TITLES.length, XSSFCell.CELL_TYPE_STRING);cell2.setCellValue("校核结果");XSSFCell cell3 = rowTitle.createCell(TITLES.length+1, XSSFCell.CELL_TYPE_STRING);cell3.setCellValue("校核建议");XSSFCellStyle cs = wb.createCellStyle();cs.setAlignment(HorizontalAlignment.LEFT);cs.setVerticalAlignment(VerticalAlignment.CENTER);cs.setFillBackgroundColor(IndexedColors.RED.getIndex());cs.setFillForegroundColor(IndexedColors.RED.getIndex());cs.setFillPattern(FillPatternType.SOLID_FOREGROUND);cs.setWrapText(true);for (int i = 0; i < dataList.size(); i++) {String[] strs = dataList.get(i);XSSFRow row = sheet.createRow(i + 1);for (int j = 0; j < strs.length; j++) {XSSFCell cell = row.createCell(j, XSSFCell.CELL_TYPE_STRING);cell.setCellValue(strs[j]);cell.setCellStyle(styleData);}}// 自动调整列宽for (int i = 0; i < TITLES_1.length; i++) {sheet.autoSizeColumn(i);}FileChooser fileChooser = new FileChooser();fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));fileChooser.setInitialFileName("月度" + repMonth.substring(0, 7) + ".xlsx");fileChooser.setTitle("导出数据");fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Excel Files", "*.xlsx", "*.xls"));File file = fileChooser.showSaveDialog(null);if (file != null) {try (FileOutputStream outputStream = new FileOutputStream(file)) {wb.write(outputStream);Msg("导出完成!");} catch (IOException e) {
// e.printStackTrace();Msg("导出失败!");}}
列编辑
使用setCellFactory方法来重新实现表格的单元格,使用TextFieldTableCell类来使其变成一个文本域。setOnEditCommit方法处理编辑过程,并且将更新后的值分配给对应的表格单元格。
tv.setEditable(true);
// 其它代码column10.setCellValueFactory(new MapValueFactory<>("c10"));column10.setPrefWidth(105);column10.setEditable(true);column10.setCellFactory(TextFieldTableCell.<Map>forTableColumn());column10.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Map, String>>() {@Overridepublic void handle(TableColumn.CellEditEvent<Map, String> event) {event.getTableView().getItems().get(event.getTablePosition().getRow()).put("c10",event.getNewValue());}});
// 其它代码
改变列为其它控件
tc.setCellFactory(new Callback<TableColumn<Map, String>, TableCell<Map, String>>() {@Overridepublic TableCell<Map, String> call(TableColumn<Map, String> param) {final TableCell<Map, String> tableCell = new TableCell<Map, String>() {@Overrideprotected void updateItem(String item, boolean empty) {super.updateItem(item, true);//清空样式setText(null);setGraphic(null);if (empty == false && item != null) {HBox hBox = new HBox();hBox.setAlignment(Pos.CENTER);ComboBox cb = new ComboBox();cb.setMinWidth(100);for (int i = 0; i < llxId.size(); i++) {cb.getItems().add(llxId.get(i));}if (item != null && !"".equals(item)) {cb.getSelectionModel().select(item);} else {
// cb.getSelectionModel().select(0);}if (this.getTableRow() != null) {ObservableList<Map> listData = this.getTableView().getItems();Map map = listData.get(this.getTableRow().getIndex());cb.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {@Overridepublic void changed(ObservableValue observable, Object oldValue, Object newValue) {map.put(s2[4], (String) newValue);}});}
// tableView.refresh();hBox.getChildren().add(cb);this.setGraphic(hBox);}}};return tableCell;}});
杂项
// 数据导入与获取
col1.setId("日期"); // 记得给列设置id,id和列名一致
TableModeSet.setTableMode(tv, list); // 导入
ObservableList<Map> maps = tv.getItems(); // 获取,结果是泛型为map的列表,一个map是一行,通过get(id)取值
// 列平均分布撑满表格
Column_Width.setMaxTableView(tv);
//或
tableview.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
// 列内容居中
col1.setStyle( "-fx-alignment: CENTER;");
// 设置列可编辑(回车保存)
col2.setEditable(true);
//col2.setCellFactory(TextFieldTableCell.forTableColumn()); 同下
Column_Width.setTableColumnIsEdit(col2);
// 添加列
tv.getColumns().addAll(col1, col2);
// 设置/禁用 列排序
<TableColumn fx:id="p3" prefWidth="57.0" styleClass="tableColumn" text="2" sortable="false"/>TableColumn<Type, Type> column = new TableColumn<>("email");
column.setSortable(false);
表格行右键菜单
tableView01.setRowFactory(param -> {TableRow row = new TableRow<>();ContextMenu rowMenu = new ContextMenu();MenuItem menuadd = new MenuItem("新增");menuadd.setOnAction(new EventHandler<ActionEvent>() {@Overridepublic void handle(ActionEvent event) {System.out.println("点击了新增选项");int index = row.getIndex();tableView01.getItems().add(index,new HashMap<>());}});MenuItem menudel = new MenuItem("删除");menudel.setOnAction(e -> {System.out.println("点击了删除选项");tableView01.getItems().remove(row.getItem());});rowMenu.getItems().addAll(menuadd,menudel);row.contextMenuProperty().bind(Bindings.when(Bindings.isNotNull(row.itemProperty())).then(rowMenu).otherwise((ContextMenu)null));return row;});
设置表格的行高
tv1.setFixedCellSize(35.0);
设置列排序
if ("序号".equals(TITLES[i]) || "工期".equals(TITLES[i])){column.setComparator(Comparator.comparing(Integer::valueOf));} else if ("停电开始时间".equals(TITLES[i]) || "停电结束时间".equals(TITLES[i])) {column.setComparator((o1, o2) -> LocalDate.parse(o1,dtf).compareTo(LocalDate.parse(o2)));}
设置单元格根据条件添加颜色
ObservableList columns = tv.getColumns();for (int i = 2; i < columns.size(); i++) {javafx.scene.control.TableColumn colu = (TableColumn) columns.get(i);colu.setCellFactory(col -> new TableCell<String, String>() {@Overrideprotected void updateItem(String item, boolean empty) {super.updateItem(item, empty);if (item == null || empty) {setText(item);setTooltip(null);} else {setText(item);setTooltip(new Tooltip(item));}int index = getIndex();String defaultStyle = getStyle();setStyle(defaultStyle +"-fx-background-color: #ffffff;");if (item!=null && !list.isEmpty()){if (Double.parseDouble(item) > Double.parseDouble(list.get(index)[0])) {setStyle(defaultStyle +"-fx-background-color: #ff0000;");}if (Double.parseDouble(item) < Double.parseDouble(list.get(index)[1])) {setStyle(defaultStyle +"-fx-background-color: #ff7f00;");}}}});}
复制出表格内容
tableView01.getSelectionModel().setCellSelectionEnabled(true);
tableView01.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
tableView01.setOnKeyPressed(event -> {if (event.isControlDown() && event.getCode() == KeyCode.C) {StringBuilder selectedData = new StringBuilder();ObservableList<TablePosition> selectedCells = tableView01.getSelectionModel().getSelectedCells();for (TablePosition tablePosition : selectedCells) {Object cellData = tableView01.getColumns().get(tablePosition.getColumn()).getCellData(tablePosition.getRow());if (selectedData.length()>0 && tablePosition.getColumn()==0){selectedData.append("\n");} else if (selectedData.length() > 0 && tablePosition.getColumn() != 0) {selectedData.append("\t");}selectedData.append(cellData);}Clipboard clipboard = Clipboard.getSystemClipboard();ClipboardContent content = new ClipboardContent();content.putString(selectedData.toString());clipboard.setContent(content);}
});
表格选中时单元格背景色不变或者异常(正常是蓝色),大概率是使用了setRowFactory、setColumnFactory、setCellFactory等方法重新定义了Row、Column、Cell,修改时取消这些用其它方法实现相应功能,或者在定义中设置有问题的属性
两个关联
主要是通过lookup函数获取了竖向滚动条,其中只有在界面加载完后才能获取到
ScrollBar s1 = (ScrollBar) tv1.lookup(".scroll-bar:vertical");ScrollBar s2 = (ScrollBar) tv2.lookup(".scroll-bar:vertical");
// System.out.println("s1 "+s1.valueProperty().getValue()+" s2 "+s2.valueProperty().getValue());if (s1!=null&&s2!=null){
// System.out.println("关联功能生效");s1.valueProperty().bindBidirectional(s2.valueProperty());}tv1.selectionModelProperty().bindBidirectional(tv2.selectionModelProperty());
// tv2.selectionModelProperty().bindBidirectional(tv1.selectionModelProperty());tv2.getSelectionModel().getSelectedCells().addListener(new InvalidationListener() {@Overridepublic void invalidated(Observable observable) {tv1.refresh();}});
展示图表
折线图
final CategoryAxis xAxis = new CategoryAxis(); // 非数字类型final NumberAxis yAxis = new NumberAxis(); // 数字类型
// xAxis.setLabel("Month");final LineChart<String,Number> lineChart = new LineChart<String,Number>(xAxis,yAxis);lineChart.setTitle(title);XYChart.Series series = new XYChart.Series();series.setName("已安排");XYChart.Series series2 = new XYChart.Series();series2.setName("可安排");XYChart.Series series3 = new XYChart.Series();series3.setName("可安排2");String[] data1 = chartMap.get("已安排");String[] data2 = chartMap.get("可安排");String[] data3 = chartMap.get("可安排2");if(data1.length!=0){for (int i = 0; i < data1.length; i++) {series.getData().add(new XYChart.Data<>(label[i],Integer.parseInt(data1[i])));series2.getData().add(new XYChart.Data<>(label[i],Integer.parseInt(data2[i])));series3.getData().add(new XYChart.Data<>(label[i],Integer.parseInt(data3[i])));}}lineChart.getData().addAll(series,series2,series3);mainbp.setCenter(lineChart);
展示提示
series.getData().forEach((Consumer<XYChart.Data<String, Number>>) str -> {Tooltip tip = new Tooltip(str.getXValue()+" "+str.getYValue());Tooltip.install(str.getNode(),tip);});
获取一年的天数并取值每一天
int days = FormateDate.getDaysOfYear(DataStore.planpdate_rep_year.substring(0, 4)); // 获取一年的天数DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); // 定义日期格式Calendar calendar = Calendar.getInstance();calendar.setTime(FormateDate.ParseStringToDate(dd1, "yyyy-MM-dd")); // 设置日历时间for (int i = 0; i < days; i++) {String[] strs = new String[2];strs[0] = df.format(calendar.getTime());for (int j = 0; j < reslist.size(); j++) {if (strs[0].equals(reslist.get(j)[0])) {
// System.out.println(strs[0] + " " + reslist.get(j)[0]+" "+reslist.get(j)[1]);strs[1] = reslist.get(j)[1];}}
// System.out.println("--"+i+" "+ Arrays.toString(strs));if(strs[1]==null){strs[1]="";}list.add(strs);calendar.add(Calendar.DATE, 1); // 增加一天}
按钮等function打开一个页面
Parent root = null;Stage primaryStage = new Stage();SpringFxmlLoader loader = new SpringFxmlLoader();try {root = (Parent) loader.springLoad(File.separator + "fxml" + File.separator + "rep" + File.separator + "ndjh" + File.separator + "NdjhJxrlMaxFixFXML.fxml");NdjhJxrlMaxFixFXMLController mf = loader.getController();//调用别的controller 需要用loader.getController方法,不然无法获取对应controller的fxml控件
// mf.dataList = resultList_xb;mf.dd1 = funDt()[0];mf.dd2 = funDt()[1];mf.init();
// mf.initChart_xb(resultList_xb);primaryStage.setTitle("最大维护");// 设置窗口的宽高double[] width = DataStore.getscreenSize();Scene scene = new Scene(root, width[1] * 2 / 5, width[0] * 4 / 5);primaryStage.setScene(scene);// 设置窗口样式/* StageStyle 枚举类DECORATED Stage用纯白色背景和平台装饰的样式TRANSPARENT Stage用透明背景且没有装饰的样式UNDECORATED Stage具有纯白色背景且没有装饰的样式。UTILITY Stage具有纯白色背景和用于实用工具的最小平台装饰的样式*/primaryStage.initStyle(StageStyle.DECORATED);primaryStage.show();// 利用窗口关闭的动作传递信息,在母窗口执行相应操作primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {@Overridepublic void handle(WindowEvent event) {if (mf.flag_chg) {chartInt = 0;initChart_Pro(dataList, xb_jPanel_only, "西北", 1);
// System.out.println("刷新了表格");}}});} catch (Exception e) {e.printStackTrace();}
提示确认等小弹出框
// 项目中一般包装为Msg()或ErrMsg()等函数使用// 实例化的同时选择类型
/* AlertType 枚举类
NONE 不设置任何属性
INFORMATION 一般提示信息
WARNING 警告类信息
ERROR 错误类信息
CONFIRMATION 确认框,有返回的布尔值
*/
Alert alert = new Alert(AlertType.CONFIRMATION);// 窗口标题、内容标题和内容
alert.setTitle("异常窗口");
alert.setHeaderText("Look, an Exception Dialog");
alert.setContentText(msg);// 展示并等待
alert.showAndWait();
// 若是确认框,需要返回值处理
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK) {return true;
} else {return false;
}
禁用组件
// 让组件完全不理会鼠标的事件
jDatePicker1.setMouseTransparent(true);// 禁用组件,组件会变灰色
jDatePicker1.setDisable(true);
异步
Task
Task<List<List<String[]>>> task = new Task<List<List<String[]>>>() {@Overrideprotected List<List<String[]>> call() {return service.qryYearUnitepData(pmonth);}};// 设置任务完成后的处理task.setOnSucceeded(event -> {lists = task.getValue();TableModeSet.setTableMode(tv1, lists.get(0));TableModeSet.setTableMode(tv2, lists.get(1));TableModeSet.setTableMode(tv3, lists.get(2));int yearTotal = lists.get(0).size() + lists.get(2).size();int monthTotal = lists.get(0).size() + lists.get(1).size();int monthAdd = lists.get(1).size();int yearNoexe = lists.get(2).size();label1.setText(String.valueOf(yearTotal));label2.setText(String.valueOf(monthTotal));label3.setText(String.valueOf(monthAdd));label4.setText(String.valueOf(yearNoexe));});// 启动任务new Thread(task).start();
Platform.runLater
Task<Void> task = new Task<Void>() {@Overrideprotected Void call() throws Exception {// 执行长时间的任务,不要在这里更新界面组件// 更新界面组件,使用Platform.runLater()Platform.runLater(() -> {// 在这里更新界面组件label.setText("Task completed!");});return null;}
};new Thread(task).start();
图形变换(Transform)
相关的类在package javafx.scene.transform;中
使用方法一般是定义变换对象,设置对应值,图形添加变换对象
平移(Translate)
// 定义平移Translate translate = new Translate();// X轴方向平移Slider slider7 = new Slider(0, 200, 0);slider7.setPrefWidth(800);slider7.valueProperty().addListener(new ChangeListener<Number>() {@Overridepublic void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {//设置旋转角度translate.setX((double) newValue);}});
// Y轴方向平移Slider slider8 = new Slider(0, 200, 0);slider8.setPrefWidth(800);slider8.valueProperty().addListener(new ChangeListener<Number>() {@Overridepublic void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {//设置旋转角度translate.setY((double) newValue);}});
// Z轴方向平移Slider slider9 = new Slider(0, 200, 0);slider9.setPrefWidth(800);slider9.valueProperty().addListener(new ChangeListener<Number>() {@Overridepublic void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {//设置旋转角度translate.setZ((double) newValue);}});
旋转(Rotate)
// 定义旋转方向对象,以下分别为x轴、y轴、z轴Rotate rotate1 = new Rotate(0, new Point3D(1, 0, 0));Rotate rotate2 = new Rotate(0, new Point3D(0, 1, 0));Rotate rotate3 = new Rotate(0, new Point3D(0, 0, 1));
// X轴旋转Slider slider1 = new Slider(0, 360, 0);slider1.setPrefWidth(800);slider1.valueProperty().addListener(new ChangeListener<Number>() {@Overridepublic void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {//设置旋转角度rotate1.setAngle((double) newValue);}});
// Y轴旋转Slider slider2 = new Slider(0, 360, 0);slider2.setPrefWidth(800);slider2.valueProperty().addListener(new ChangeListener<Number>() {@Overridepublic void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {//设置旋转角度rotate2.setAngle((double) newValue);}});
// Z轴旋转Slider slider3 = new Slider(0, 360, 0);slider3.setPrefWidth(800);slider3.valueProperty().addListener(new ChangeListener<Number>() {@Overridepublic void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {//设置旋转角度rotate3.setAngle((double) newValue);}});
缩放(Scale)
// 定义缩放Scale scale = new Scale();
// X轴方向的缩放Slider slider4 = new Slider(0.5, 2, 1);slider4.setPrefWidth(800);slider4.valueProperty().addListener(new ChangeListener<Number>() {@Overridepublic void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {//设置旋转角度scale.setX((double) newValue);}});
// Y轴方向的缩放Slider slider5 = new Slider(0.5, 2, 1);slider5.setPrefWidth(800);slider5.valueProperty().addListener(new ChangeListener<Number>() {@Overridepublic void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {//设置旋转角度scale.setY((double) newValue);}});
// Z轴方向的缩放Slider slider6 = new Slider(0.5, 2, 1);slider6.setPrefWidth(800);slider6.valueProperty().addListener(new ChangeListener<Number>() {@Overridepublic void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {//设置旋转角度scale.setZ((double) newValue);}});
错切(Shear)
// 定义错切Shear shear = new Shear();Slider slider10 = new Slider(0, 10, 0);slider10.setPrefWidth(800);slider10.valueProperty().addListener(new ChangeListener<Number>() {@Overridepublic void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {//设置旋转角度shear.setX((double) newValue);}});Slider slider11 = new Slider(0, 10, 0);slider11.setPrefWidth(800);slider11.valueProperty().addListener(new ChangeListener<Number>() {@Overridepublic void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {//设置旋转角度shear.setY((double) newValue);}});
仿射(Affine)
基础动画(Animation)
过渡(Transition)
褪色过渡(FadeTransition)
// 定义一个褪色过渡,参数1是动画时间,参数2是动画主体FadeTransition ft = new FadeTransition(Duration.millis(3000), mian);
// 定义褪色成都的起始ft.setFromValue(1.0);ft.setToValue(0.1);
// 定义一直重复ft.setCycleCount(Timeline.INDEFINITE);
// 定义此动画是否在交替循环中反转方向。
// 如果为真,动画将在第一个循环中向前进行,然后在第二个循环中反向,依此类推。
// 否则,动画将循环,以便每个循环从开始向前推进。ft.setAutoReverse(true);
// 修改动画的属性值后需要stop()后再play()ft.play();
路径过渡(PathTransition)
// 定义路径Path path = new Path();path.getElements().add(new MoveTo(20,20));path.getElements().add(new CubicCurveTo(380, 0, 380, 120, 200, 120));path.getElements().add(new CubicCurveTo(0, 120, 0, 240, 380, 240));
// 定义路径动画PathTransition pt = new PathTransition();pt.setDuration(Duration.millis(4000));pt.setPath(path);pt.setNode(mian);
// 将目标节点的旋转矩阵设置为使节点沿几何路径垂直于路径的切线。pt.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);pt.setCycleCount(Timeline.INDEFINITE);pt.setAutoReverse(true);pt.play();
并行过渡(ParallelTransition)
FadeTransition fadeTransition = new FadeTransition(Duration.millis(2000), mian);fadeTransition.setFromValue(1.0f);fadeTransition.setToValue(0.3f);fadeTransition.setCycleCount(2);fadeTransition.setAutoReverse(true);TranslateTransition translateTransition = new TranslateTransition(Duration.millis(2000), mian);translateTransition.setFromX(50);translateTransition.setToX(350);translateTransition.setCycleCount(2);translateTransition.setAutoReverse(true);RotateTransition rotateTransition = new RotateTransition(Duration.millis(2000), mian);rotateTransition.setByAngle(180f);rotateTransition.setCycleCount(2);rotateTransition.setAutoReverse(true);ScaleTransition scaleTransition = new ScaleTransition(Duration.millis(2000), mian);scaleTransition.setToX(2f);scaleTransition.setToY(2f);scaleTransition.setCycleCount(2);scaleTransition.setAutoReverse(true);ParallelTransition parallelTransition = new ParallelTransition();parallelTransition.getChildren().addAll(fadeTransition,translateTransition,rotateTransition,scaleTransition);parallelTransition.setCycleCount(Timeline.INDEFINITE);parallelTransition.play();
串行过渡(SequentialTransition)
SequentialTransition sequentialTransition = new SequentialTransition();sequentialTransition.getChildren().addAll(fadeTransition,translateTransition,rotateTransition,scaleTransition);sequentialTransition.setCycleCount(Timeline.INDEFINITE);sequentialTransition.setAutoReverse(true);sequentialTransition.play();
基本时间轴动画(Timeline)
final Timeline timeline = new Timeline();timeline.setCycleCount(Timeline.INDEFINITE);timeline.setAutoReverse(true);final KeyValue kv = new KeyValue(mian.xProperty(), 300);final KeyFrame kf = new KeyFrame(Duration.millis(500), kv);timeline.getKeyFrames().add(kf);timeline.getKeyFrames().add(new KeyFrame(Duration.millis(500), new KeyValue(mian.yProperty(),200)));timeline.play();
时间轴事件
public class TS2 extends Application {//主时间轴Timeline timeline;AnimationTimer timer;//用于指定实际帧的变量Integer i=0;@Overridepublic void start(Stage primaryStage) throws Exception {Rectangle mian = new Rectangle(150, 120, 100, 80);mian.setFill(new Color(1, 0, 0, 1));Group group = new Group();Text text = new Text (i.toString());text.setStroke(Color.BLACK);text.setLayoutX(10);text.setLayoutY(20);group.getChildren().addAll(mian,text);//为了移动圆创建一个时间轴timeline = new Timeline();timeline.setCycleCount(Timeline.INDEFINITE);timeline.setAutoReverse(true);//在每个帧开始时你可以添加一个特定的动作timer = new AnimationTimer() {@Overridepublic void handle(long l) {text.setText(i.toString());i++;}};//创建一个带有缩放因子的keyValue:将圆缩放2倍KeyValue keyValueX = new KeyValue(mian.scaleXProperty(), 2);KeyValue keyValueY = new KeyValue(mian.scaleYProperty(), 2);//创建一个KeyFrame, keyValue会在2秒钟时抵达Duration duration = Duration.millis(2000);//当抵达关键帧时可以指定一个特定的动作EventHandler onFinished = new EventHandler<ActionEvent>() {@Overridepublic void handle(ActionEvent t) {mian.setTranslateX(java.lang.Math.random()*200-100);//复位计数器i = 0;}};KeyFrame keyFrame = new KeyFrame(duration, onFinished , keyValueX, keyValueY);//将关键帧添加到时间轴中timeline.getKeyFrames().add(keyFrame);timeline.play();timer.start();Scene scene = new Scene(group,800,600,new Color(1,0.9,0.7,1));primaryStage.setScene(scene);primaryStage.setTitle("窗口标题");primaryStage.show();}public static void main(String[] args) {Application.launch(args);}
}
插值器(Interpolator)
插值(Interpolation)定义了对象在动作起始和结束点之间的位置
JavaFX提供了多种内置Interpolator,可以用于在你的动画中创建不同的特效
// 使用了内置插值器final Timeline timeline = new Timeline();timeline.setCycleCount(Timeline.INDEFINITE);timeline.setAutoReverse(true);final KeyValue kv = new KeyValue(mian.xProperty(), 300,Interpolator.EASE_BOTH);final KeyFrame kf = new KeyFrame(Duration.millis(500), kv);timeline.getKeyFrames().add(kf);timeline.getKeyFrames().add(new KeyFrame(Duration.millis(500), new KeyValue(mian.yProperty(),200)));timeline.play();
视觉特效(Effect)
混合特效(Blend Effect)
混合是一种使用预定义的混合模式将两个输入组合到一起的特效
主要使用方式:node.setBlendMode(BlendMode.SRC_ATOP);
底层输入内容的决定基于以下规则:
● 在同一个Group中具有更低Z-order的所有内容都包括在内。
● 如果对应的Group具有明确定义的混合模式,则终止底层输入查找过程,之前所找到的内容都会包括在内作为底层输入
● 如果Group具有默认的混合模式,则所有在Group之下的节点都包括在内,并且继续递归应用此规则。
● 如果处理过程递归回到了根节点,那么scene的背景图也包括在内
Circle circle = new Circle(80,80,80,new Color(1,0.5,0,1));Rectangle rectangle = new Rectangle(100,100,200,150);rectangle.setFill(new Color(0.5,0.5,1,1));rectangle.setBlendMode(BlendMode.SRC_ATOP);Group group = new Group();group.getChildren().addAll(circle,rectangle);group.setBlendMode(BlendMode.SRC_OVER);Scene scene = new Scene(group,800,600,new Color(1,0.9,0.7,1));stage.setScene(scene);stage.setTitle("特效动画");stage.show();
注意:设置group中组件的混合模式后,最好再设置下group的混合模式
发光特效(Bloom Effect)
发光特效使图像中较亮的部分发光,发光效果基于一个可配置的阀值。阀值范围是0.0到1.0,默认是0.3。
Bloom bloom = new Bloom();bloom.setThreshold(0.7);group.setEffect(bloom);
模糊特效(Blur Effects)
方框模糊(BoxBlur)
方框模糊(BoxBlur)是一种使用了简单方框过滤器内核的模糊特效。你可以分别在两个维度上定义大小,以此来控制应用到对象上的模糊量,以及指定一个Iterations参数用来控制模糊结果的质量。
BoxBlur bb = new BoxBlur();bb.setWidth(8);bb.setHeight(8);bb.setIterations(5);text.setEffect(bb);
动感模糊(Motion Blur)
动感模糊特效使用了高斯模糊,它可以配置半径和角度来创建移动对象的效果
MotionBlur mb = new MotionBlur();mb.setRadius(15.0f);mb.setAngle(45.0f);text.setEffect(mb)
高斯模糊(Gaussian Blur)
高斯模糊是一种使用高斯算法并指定一个半径来实现对象模糊的特效。
text.setEffect(new GaussianBlur());
阴影特效(Drop Shadow Effect)
普通阴影(DropShadow)
DropShadow ds1 = new DropShadow();ds1.setOffsetY(4.0f);ds1.setOffsetX(4.0f);ds1.setColor(Color.BLACK);text.setEffect(ds1);
内阴影(InnerShadow)
InnerShadow is = new InnerShadow();is.setOffsetX(2.0f);is.setOffsetY(2.0f);text.setEffect(is);
倒影(Reflection)
Reflection r = new Reflection();r.setFraction(0.9);text.setEffect(r);
光照特效(Lighting)
Light.Distant light = new Light.Distant();
// 光照的角度,0是右边light.setAzimuth(0f);Lighting l = new Lighting();l.setLight(light);
// 接受光照的范围l.setSurfaceScale(4.0f);circle.setEffect(l);
透视特效(PerspectiveTransform)
PerspectiveTransform pt = new PerspectiveTransform();pt.setUlx(10.0f);pt.setUly(10.0f);pt.setUrx(100.0f);pt.setUry(20.0f);pt.setLrx(100.0f);pt.setLry(120.0f);pt.setLlx(10.0f);pt.setLly(80.0f);group.setEffect(pt);
特效链
一些特效带有一个input属性,你可以用它来创建一个特效链。这个特效链类似于树形结构,因为有的特效允许两个input参数,而有的则一个都没有。
DropShadow ds = new DropShadow();ds.setOffsetY(5.0);ds.setOffsetX(5.0);ds.setColor(Color.GRAY);Reflection reflection = new Reflection();ds.setInput(reflection); rect.setEffect(ds);
界面变灰色
使用ColorAdjust
// hue,saturation,brightness,contrast
// 色相、饱和度、亮度、对比度ColorAdjust colorAdjust = new ColorAdjust(0,-0.96,-0.05,0);mainbp.setEffect(colorAdjust);
手动实现
public class App extends Application {@Overridepublic void start(Stage ps) {Pane root = new Pane();root.setMinSize(300, 300);root.setStyle("-fx-background-color: #40444b;");Image image = new Image("https://res.cloudinary.com/mesa-clone/image/upload/v1642936429/1f914_tydc44.png");ImageView view = new ImageView(grayScale(image));view.setTranslateX(5);view.setTranslateY(5);root.getChildren().add(view);ps.setScene(new Scene(root));ps.setTitle("javafx grayscale test");ps.show();}private static Image grayScale(Image img) {WritableImage res = new WritableImage((int) img.getWidth(), (int) img.getHeight());PixelReader pr = img.getPixelReader();PixelWriter pw = res.getPixelWriter();for (int y = 0; y < img.getHeight(); y++) {for (int x = 0; x < img.getWidth(); x++) {pw.setColor(x, y, pr.getColor(x, y).grayscale());}}return res;}
}