我想创建一个自定义按钮,有两个状态按下或未按下,就像一个切换按钮。我有两张图片来实现这个效果(按下和未按下),那么我该如何创建按钮并使用我的图片显示它?该按钮必须采用图像的尺寸。
我没有使用FXML。谢谢你的帮助。
我想创建一个自定义按钮,有两个状态按下或未按下,就像一个切换按钮。我有两张图片来实现这个效果(按下和未按下),那么我该如何创建按钮并使用我的图片显示它?该按钮必须采用图像的尺寸。
我没有使用FXML。谢谢你的帮助。
Button
,可以像此答案中提到的ToggleButton
一样进行样式设置。.toggle-button {
-fx-graphic: url('http://icons.iconarchive.com/icons/aha-soft/desktop-buffet/128/Pizza-icon.png');
}
.toggle-button:selected {
-fx-graphic: url('http://icons.iconarchive.com/icons/aha-soft/desktop-buffet/128/Piece-of-cake-icon.png');
}
或者使用附带的 CSS 定义背景图片。
// file imagetogglebutton.css deployed in the same package as ToggleButtonImage.class
.toggle-button {
-fx-background-image: url('http://icons.iconarchive.com/icons/aha-soft/desktop-buffet/128/Pizza-icon.png');
-fx-background-repeat: no-repeat;
-fx-background-position: center;
}
.toggle-button:selected {
-fx-background-image: url('http://icons.iconarchive.com/icons/aha-soft/desktop-buffet/128/Piece-of-cake-icon.png');
}
我更喜欢使用-fx-graphic规范而不是-fx-background-*规范,因为样式化背景图像的规则很棘手,并且设置背景不会自动调整按钮大小,而设置图形会。
以下是一些示例代码:
注意:此示例中使用的StackPaneBuilder已被弃用并从JavaFX中删除,请用new StackPane()替换该代码,并调用结果堆栈窗格上的方法来设置堆栈窗格属性,而不是使用生成器。
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.StackPaneBuilder;
import javafx.stage.Stage;
public class ToggleButtonImage extends Application {
public static void main(String[] args) throws Exception { launch(args); }
@Override public void start(final Stage stage) throws Exception {
final ToggleButton toggle = new ToggleButton();
toggle.getStylesheets().add(this.getClass().getResource(
"imagetogglebutton.css"
).toExternalForm());
toggle.setMinSize(148, 148); toggle.setMaxSize(148, 148);
stage.setScene(new Scene(
StackPaneBuilder.create()
.children(toggle)
.style("-fx-padding:10; -fx-background-color: cornsilk;")
.build()
));
stage.show();
}
}
这样做的一些优点是:
另一个选择是不使用CSS,仍然使用ToggleButton,但在代码中设置图像。
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.*;
import javafx.scene.control.ToggleButton;
import javafx.scene.image.*;
import javafx.scene.layout.StackPaneBuilder;
import javafx.stage.Stage;
public class ToggleButtonImageViaGraphic extends Application {
public static void main(String[] args) throws Exception { launch(args); }
@Override public void start(final Stage stage) throws Exception {
final ToggleButton toggle = new ToggleButton();
final Image unselected = new Image(
"http://icons.iconarchive.com/icons/aha-soft/desktop-buffet/128/Pizza-icon.png"
);
final Image selected = new Image(
"http://icons.iconarchive.com/icons/aha-soft/desktop-buffet/128/Piece-of-cake-icon.png"
);
final ImageView toggleImage = new ImageView();
toggle.setGraphic(toggleImage);
toggleImage.imageProperty().bind(Bindings
.when(toggle.selectedProperty())
.then(selected)
.otherwise(unselected)
);
stage.setScene(new Scene(
StackPaneBuilder.create()
.children(toggle)
.style("-fx-padding:10; -fx-background-color: cornsilk;")
.build()
));
stage.show();
}
}
如果你不熟悉CSS,那么基于代码的方法有优势。
为了获得最佳性能并易于在未签名的小程序和Webstart沙箱中移植,请将图像与您的应用程序捆绑在一起,并通过相对路径URL引用它们,而不是从网络上下载它们。
您只需要创建一个继承自父类的自定义类。在该类上放置一个ImageView,在mousedown和mouseup事件中更改ImageView的图像即可。
public class ImageButton extends Parent {
private static final Image NORMAL_IMAGE = ...;
private static final Image PRESSED_IMAGE = ...;
private final ImageView iv;
public ImageButton() {
this.iv = new ImageView(NORMAL_IMAGE);
this.getChildren().add(this.iv);
this.iv.setOnMousePressed(new EventHandler<MouseEvent>() {
public void handle(MouseEvent evt) {
iv.setImage(PRESSED_IMAGE);
}
});
// TODO other event handlers like mouse up
}
}
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
public class ImageButton extends Button {
public void updateImages(final Image selected, final Image unselected) {
final ImageView iv = new ImageView(selected);
this.getChildren().add(iv);
iv.setOnMousePressed(new EventHandler<MouseEvent>() {
public void handle(MouseEvent evt) {
iv.setImage(unselected);
}
});
iv.setOnMouseReleased(new EventHandler<MouseEvent>() {
public void handle(MouseEvent evt) {
iv.setImage(selected);
}
});
super.setGraphic(iv);
}
}
由于某些原因,当我在场景中有许多这样的对象(比如工具栏)时,使用按钮在点击时处理图像交换总是表现得“迟缓”,而且动态调整大小非常缓慢,甚至有时会导致Java虚拟机本身崩溃。
相比之下,直接使用ImageView对象始终被证明非常响应,无论我在场景中有多少个。它们可以立即切换图像,可以实时调整大小并获得即时响应,使用起来感觉非常自然,不像按钮那样有点“阻力”。
以下是我的做法:
public void buildImageButtons() {
double iconSize = 50;
Image unSelectedOne = new Image(Main.class.getResourceAsStream("UnselectedImageOne.png"));
Image selectedOne = new Image(Main.class.getResourceAsStream("SelectedImageOne.png"));
Image unSelectedTwo = new Image(Main.class.getResourceAsStream("UnselectedImageTwo.png"));
Image selectedTwo = new Image(Main.class.getResourceAsStream("SelectedImageTwo.png"));
ImageView ivOne = newImageView(unSelectedOne, selectedOne, iconSize);
ImageView ivTwo = newImageView(unSelectedTwo, selectedTwo, iconSize);
ivOne.setOnMouseClicked(e -> methodOne());
ivTwo.setOnMouseClicked(e -> methodTwo());
}
private ImageView newImageView(Image unselected, Image selected, double iconSize) {
ImageView iv = new ImageView(unselected);
iv.setPreserveRatio(true);
iv.setFitWidth(iconSize);
iv.setOnMousePressed(e->{
iv.setImage(selected);
});
iv.setOnMouseReleased(e->{
iv.setImage(unselected);
});
return iv;
}
private void methodOne() {
System.out.println("Image One Clicked");
}
private void methodTwo() {
System.out.println("Image Two Clicked");
}