JavaFX-使用图像创建自定义按钮

JavaFX-使用图像创建自定义按钮,javafx,Javafx,我想创建一个自定义按钮,有两种状态按下或不按下,像一个切换按钮。我有两个图像来做这件事(按下和未按下),那么我如何创建按钮,并显示它与我的图像?按钮必须采用图像的大小。 我没有使用FXML。 感谢您的帮助。您只需创建自己的类,该类继承自父类。 在上面放置一个ImageView,在mousedown和MouseUp事件上只需更改ImageView的图像 public class ImageButton extends Parent { private static final Image

我想创建一个自定义按钮,有两种状态按下或不按下,像一个切换按钮。我有两个图像来做这件事(按下和未按下),那么我如何创建按钮,并显示它与我的图像?按钮必须采用图像的大小。
我没有使用FXML。
感谢您的帮助。

您只需创建自己的类,该类继承自父类。 在上面放置一个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

    } 

}
公共类ImageButton扩展父类{
私有静态最终图像法线_图像=。。。;
私有静态最终图像按下_图像=。。。;
私人最终影像视图四;
公共图像按钮(){
this.iv=新图像视图(正常图像);
this.getChildren().add(this.iv);
this.iv.setOnMousePressed(新的EventHandler(){
公共无效句柄(MouseEvent evt){
iv.设置图像(按下图像);
}
});
//TODO其他事件处理程序,如鼠标悬停
} 
}

实现这一点有几种不同的方法,我将概述我最喜欢的方法

使用并对其应用自定义样式。我建议这样做是因为您所需的控件“类似于切换按钮”,但看起来与默认的切换按钮样式不同

我的首选方法是在css中为按钮定义图形:

.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 background-*规范相比,我更喜欢-fx图形规范,因为设置背景图像样式的规则比较复杂,设置背景不会自动调整按钮与图像的大小,而设置图形则会

还有一些示例代码:

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不相似,则不必使用css


    为了获得最佳性能并易于移植到未签名的小程序和webstart沙盒,请将图像与应用程序捆绑在一起,并通过相对路径URL引用它们,而不是从网上下载它们。

    前面两个答案的组合就达到了目的。谢谢从Button继承的新类。注意:在显示按钮之前应调用updateImages()

    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);
        }
    }
    
    导入javafx.event.EventHandler;
    导入javafx.scene.control.Button;
    导入javafx.scene.image.image;
    导入javafx.scene.image.ImageView;
    导入javafx.scene.input.MouseEvent;
    公共类ImageButton扩展按钮{
    公共无效更新图像(已选择最终图像,未选择最终图像){
    最终图像视图iv=新图像视图(选定);
    this.getChildren().add(iv);
    iv.setOnMousePressed(新的EventHandler(){
    公共无效句柄(MouseEvent evt){
    iv.设置图像(未选择);
    }
    });
    iv.setOnMouseReleased(新的EventHandler(){
    公共无效句柄(MouseEvent evt){
    iv.设置图像(选定);
    }
    });
    超级图形(四);
    }
    }
    
    Wow!我能说什么?这是一个非常好的答案,非常感谢。我想我会选择第一种解决方案,我会在代码中将大小应用到我的按钮上,这在JavaFX应用程序中似乎很常见,不像Swing;在css中,只让我的按钮填充我的图像。这是一个很好的答案,但显示了JavaFX的一个弱点。这种要求在21世纪是杂乱无章和毫无根据的。你更喜欢哪一个更强大的解决方案?