JavaFx 自定义设计按钮在使用的应用程序中单击检测
JavaFx custom design button click detect in used application
使用 FXML 和两个文件 CustomToggleSwitch.fxml 和 CustomToggleSwitch.java 创建了自定义设计。
CustomToggleSwitch.fxml 有以下代码
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<fx:root type="Pane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button mnemonicParsing="false" onAction="#click" text="Button" />
</children>
</fx:root>
CustomToggleSwitch.java 有代码
package com.custom;
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;
public class CustomToggleSwitch extends Pane{
int tick;
public CustomToggleSwitch() {
FXMLLoader loader=new FXMLLoader(getClass().getResource("CustomToggleSwitch.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
@FXML
public void click(ActionEvent actionEvent){
System.out.println(tick++);
}
}
从这些文件创建 jar 文件并在应用程序项目中使用该 jar 文件。应用程序有 test.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import com.custom.*?>
<?import com.custom.CustomToggleSwitch?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="- Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<CustomToggleSwitch layoutX="29.0" layoutY="48.0" />
</children>
</AnchorPane>
控制器 class(TestController.java) 有以下内容
public class TestController implements Initializable{
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
}
@FXML
public void click(){
System.out.println("Test");
}
}
按钮在 GUI 上成功显示,按钮点击也得到 detected.Button 在输出控制台上显示 0,1,2,3..etc。但是测试没有打印在屏幕上。
如何检测应用程序控制器中的按钮按下情况class?谁能帮我解决这个问题。
非常感谢大家。
发生这种情况是因为 onAction="#click"
在 CustomToggleSwitch.fxml 中声明,因此 FXMLLoader
将在 CustomToggleSwitch.java 中查找 click()
。
在 TestController
class 中添加一个 click()
不会有任何作用,因为您在 test.fxml 中没有任何带有 onAction="#click"
的节点。
CustomToggleSwitch 中的 Button
与 TestController
class 通信的一种方法是将事件中继出去。
public class CustomToggleSwitch extends Pane {
// Same stuff
private List<Runnable> onClickRunnables = new ArrayList<>();
public final void addButtonOnClickRunnable(Runnable runnable) {
Objects.requireNonNull(runnable);
onClickRunnables.add(runnable);
}
@FXML
private void click(ActionEvent actionEvent){
System.out.println(tick++);
if (!onClickRunnables.isEmpty()) {
onClickRunnables.forEach(r -> r.run());
}
}
}
public class TestController implements Initializable {
// Give CustomToggleSwitch control an fx:id in FXML
@FXML private CustomToggleSwitch customSwitch;
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
customSwitch.addButtonOnClickRunnable(this::click);
}
}
另一种方法是将CustomToggleSwitch
中的Button
暴露出来。就个人而言,我建议不要这样做,因为隐藏 "control" 的实现更整洁。
add listener property with getter and setter in your component
controller.
Jai的例子是正确的,但是和javafx的其他组件不一致。为了正确实施,使用可以在 FXML 和手动模式下操作的属性是合适的。
这是添加了 onMyAction 属性 的用户组件控制器。此属性用于事件通知。
public class CustomToggleSwitch extends Pane {
private ObjectProperty<EventHandler<ActionEvent>> onMyAction = new SimpleObjectProperty<EventHandler<ActionEvent>>();
public CustomToggleSwitch() {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/sample/CustomToggleSwitch.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
}
catch (IOException e) {
e.printStackTrace();
}
}
@FXML
private void initialize() {
}
@FXML
private void click(ActionEvent event) {
if(onMyAction.get() != null) {
onMyAction.get().handle(event);
}
}
public EventHandler<ActionEvent> getOnMyAction() {
return onMyAction.get();
}
public ObjectProperty<EventHandler<ActionEvent>> onMyActionProperty() {
return onMyAction;
}
public void setOnMyAction(EventHandler<ActionEvent> onMyAction) {
this.onMyAction.set(onMyAction);
}
}
有了这样的结构化组件,onMyAction 属性 可以通过 FXML 例如添加
<AnchorPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml" >
<CustomToggleSwitch onMyAction="#testHandler"/>
</AnchorPane>
public class Controller {
@FXML
private void testHandler(ActionEvent event) {
}
}
或手动
<AnchorPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml" >
<CustomToggleSwitch fx:id="customToggleSwitch"/>
</AnchorPane>
public class Controller {
@FXML
private CustomToggleSwitch customToggleSwitch;
@FXML
private void initialize() {
customToggleSwitch.setOnMyAction(event -> {
});
}
}
更新
You don't need to use a property. Making the getter and setter available should be sufficient to use it from fxml. (I didn't encountered a case where I would add a listerner to a event handler property yet.)
这是没有使用属性
的转换
public class CustomToggleSwitch extends Pane {
private EventHandler<ActionEvent> myEventHandler;
public CustomToggleSwitch() {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/sample/CustomToggleSwitch.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
}
catch (IOException e) {
e.printStackTrace();
}
}
@FXML
private void initialize() {
}
@FXML
private void click(ActionEvent event) {
if(myEventHandler != null) {
myEventHandler.handle(event);
}
}
public EventHandler<ActionEvent> getOnMyAction() {
return myEventHandler;
}
public void setOnMyAction(EventHandler<ActionEvent> onMyAction) {
myEventHandler = onMyAction;
}
}
使用 FXML 和两个文件 CustomToggleSwitch.fxml 和 CustomToggleSwitch.java 创建了自定义设计。
CustomToggleSwitch.fxml 有以下代码
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<fx:root type="Pane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button mnemonicParsing="false" onAction="#click" text="Button" />
</children>
</fx:root>
CustomToggleSwitch.java 有代码
package com.custom;
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;
public class CustomToggleSwitch extends Pane{
int tick;
public CustomToggleSwitch() {
FXMLLoader loader=new FXMLLoader(getClass().getResource("CustomToggleSwitch.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
@FXML
public void click(ActionEvent actionEvent){
System.out.println(tick++);
}
}
从这些文件创建 jar 文件并在应用程序项目中使用该 jar 文件。应用程序有 test.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import com.custom.*?>
<?import com.custom.CustomToggleSwitch?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="- Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<CustomToggleSwitch layoutX="29.0" layoutY="48.0" />
</children>
</AnchorPane>
控制器 class(TestController.java) 有以下内容
public class TestController implements Initializable{
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
}
@FXML
public void click(){
System.out.println("Test");
}
}
按钮在 GUI 上成功显示,按钮点击也得到 detected.Button 在输出控制台上显示 0,1,2,3..etc。但是测试没有打印在屏幕上。
如何检测应用程序控制器中的按钮按下情况class?谁能帮我解决这个问题。
非常感谢大家。
发生这种情况是因为 onAction="#click"
在 CustomToggleSwitch.fxml 中声明,因此 FXMLLoader
将在 CustomToggleSwitch.java 中查找 click()
。
在 TestController
class 中添加一个 click()
不会有任何作用,因为您在 test.fxml 中没有任何带有 onAction="#click"
的节点。
CustomToggleSwitch 中的 Button
与 TestController
class 通信的一种方法是将事件中继出去。
public class CustomToggleSwitch extends Pane {
// Same stuff
private List<Runnable> onClickRunnables = new ArrayList<>();
public final void addButtonOnClickRunnable(Runnable runnable) {
Objects.requireNonNull(runnable);
onClickRunnables.add(runnable);
}
@FXML
private void click(ActionEvent actionEvent){
System.out.println(tick++);
if (!onClickRunnables.isEmpty()) {
onClickRunnables.forEach(r -> r.run());
}
}
}
public class TestController implements Initializable {
// Give CustomToggleSwitch control an fx:id in FXML
@FXML private CustomToggleSwitch customSwitch;
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
customSwitch.addButtonOnClickRunnable(this::click);
}
}
另一种方法是将CustomToggleSwitch
中的Button
暴露出来。就个人而言,我建议不要这样做,因为隐藏 "control" 的实现更整洁。
add listener property with getter and setter in your component controller.
Jai的例子是正确的,但是和javafx的其他组件不一致。为了正确实施,使用可以在 FXML 和手动模式下操作的属性是合适的。
这是添加了 onMyAction 属性 的用户组件控制器。此属性用于事件通知。
public class CustomToggleSwitch extends Pane {
private ObjectProperty<EventHandler<ActionEvent>> onMyAction = new SimpleObjectProperty<EventHandler<ActionEvent>>();
public CustomToggleSwitch() {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/sample/CustomToggleSwitch.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
}
catch (IOException e) {
e.printStackTrace();
}
}
@FXML
private void initialize() {
}
@FXML
private void click(ActionEvent event) {
if(onMyAction.get() != null) {
onMyAction.get().handle(event);
}
}
public EventHandler<ActionEvent> getOnMyAction() {
return onMyAction.get();
}
public ObjectProperty<EventHandler<ActionEvent>> onMyActionProperty() {
return onMyAction;
}
public void setOnMyAction(EventHandler<ActionEvent> onMyAction) {
this.onMyAction.set(onMyAction);
}
}
有了这样的结构化组件,onMyAction 属性 可以通过 FXML 例如添加
<AnchorPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml" >
<CustomToggleSwitch onMyAction="#testHandler"/>
</AnchorPane>
public class Controller {
@FXML
private void testHandler(ActionEvent event) {
}
}
或手动
<AnchorPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml" >
<CustomToggleSwitch fx:id="customToggleSwitch"/>
</AnchorPane>
public class Controller {
@FXML
private CustomToggleSwitch customToggleSwitch;
@FXML
private void initialize() {
customToggleSwitch.setOnMyAction(event -> {
});
}
}
更新
You don't need to use a property. Making the getter and setter available should be sufficient to use it from fxml. (I didn't encountered a case where I would add a listerner to a event handler property yet.)
这是没有使用属性
的转换public class CustomToggleSwitch extends Pane {
private EventHandler<ActionEvent> myEventHandler;
public CustomToggleSwitch() {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/sample/CustomToggleSwitch.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
}
catch (IOException e) {
e.printStackTrace();
}
}
@FXML
private void initialize() {
}
@FXML
private void click(ActionEvent event) {
if(myEventHandler != null) {
myEventHandler.handle(event);
}
}
public EventHandler<ActionEvent> getOnMyAction() {
return myEventHandler;
}
public void setOnMyAction(EventHandler<ActionEvent> onMyAction) {
myEventHandler = onMyAction;
}
}