【问题标题】:How To Make Button Background Change OnClick如何使按钮背景更改 OnClick
【发布时间】:2019-07-25 21:30:18
【问题描述】:

我正在尝试使用 Scene Builder 解决我正在使用 javafx 11 和 java11 处理的计算器项目的问题。我试图找出一种方法,使计算器上的按钮在从键盘输入相应值时改变颜色。有没有办法解决这个问题,或者 onKeyPressed 等类型的解决方案?

当用户用鼠标单击按钮时,我能够使按钮改变颜色(变为绿色)。这是在我的 CSS 样式表中完成的。我试图在我的控制器类中向我的 onKeyReleased 方法添加一个方法,并且可以通过这种方式更改背景,但无法确定一种方法来及时恢复颜色而不导致 UI 滞后。我希望 UI 更改颜色类似于大多数计算器,例如标准 Windows 计算器。这是用户按住键并改变颜色的地方,当释放键时它会变回。

//main.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;

public class Main extends Application {

@Override
public void start(Stage primaryStage) throws Exception {
    Parent root = 
 FXMLLoader.load(getClass().getResource("calculator.fxml"));
    primaryStage.getIcons().add(new Image("CALC.png"));
    primaryStage.setTitle(" TS Calculator");
    primaryStage.setScene(new Scene(root, 250, 375));
    primaryStage.setResizable(true);
    primaryStage.setMinHeight(375);
    primaryStage.setMinWidth(250);
    primaryStage.show();
}
public static void main(String[] args) {
    launch(args);
}

 /CSS
Button{
-fx-background-color: black;
-fx-text-align: center;
-fx-text-fill: white;
-fx-border-color: green;
-fx-font-size: 1em;
-fx-border-radius: 10 10 10 10;
-fx-background-radius: 10 10 10 10;
}
Button:pressed{
-fx-background-color: green;
}
TextField{
-fx-font-size: 1.5em;
}

//FXML (Only showing 1 button)

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>

<GridPane maxHeight="1.7976931348623157E308" 
maxWidth="1.7976931348623157E308" minHeight="306.00" minWidth="204.0"
      prefHeight="288.0" prefWidth="208.0" style="-fx-background-color: 
DARKSLATEGREY; -fx-border-color: green;"
      stylesheets="@styles.css" xmlns="http://javafx.com/javafx/11.0.1" 
xmlns:fx="http://javafx.com/fxml/1" 
fx:controller="com.trevorsmith.Controller"
      onKeyReleased="#acceptKeyboardInput">
<AnchorPane prefHeight="200.0" prefWidth="200.0" GridPane.columnSpan="4" 
GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS" 
onKeyPressed="#acceptKeyboardInput">
    <children>
            <TextField fx:id="textFieldDisplay"  editable="false" 
alignment="CENTER_RIGHT" maxHeight="1.7976931348623157E308" 
 maxWidth="1.7976931348623157E308" prefWidth="196.0" 
AnchorPane.bottomAnchor="2.0" AnchorPane.leftAnchor="2.0" 
AnchorPane.rightAnchor="2.0" AnchorPane.topAnchor="2.0" />
  </children>
</AnchorPane>
<AnchorPane maxHeight="1.7976931348623157E308" 
maxWidth="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0" 
GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" GridPane.vgrow="ALWAYS">
  <children>
      <Button maxHeight="1.7976931348623157E308" 
maxWidth="1.7976931348623157E308" text="0" AnchorPane.bottomAnchor="0.0" 
AnchorPane.leftAnchor="2.0" AnchorPane.rightAnchor="0.0" 
AnchorPane.topAnchor="0.0" />
  </children>

我无法在点击时改变背景颜色,当我松开按键时它会变回来。

【问题讨论】:

  • 监听按键事件并根据按下和释放的按键更改按键颜色。
  • 您能详细说明一下吗?我尝试了 onKeyTyped 和 onKeyPressed 并且在使用它们时都没有改变按钮颜色。

标签: java javafx fxml java-11 javafx-11


【解决方案1】:

您需要在Scene 上注册几个监听器来监听按下的按键。

获得密钥后,您可以使用 JavaFX 的 PseudoClass 选择器更新每个 Buttonpressed 样式。

可能有更简化的方法来执行此操作,但这是我的实现。这是一个完整的示例,您可以尝试查看它的实际效果。

请注意,我没有实现计算器的实际功能。

最后的结果/截图在最后。


Main.java:

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("MainLayout.fxml"));

            Scene scene = new Scene(loader.load());
            scene.getStylesheets().add("style.css");
            primaryStage.setScene(scene);
            primaryStage.setTitle("Calculator");
            primaryStage.show();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

MainLayout.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox alignment="TOP_CENTER" spacing="10.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1"
      fx:controller="UI.BaseApps.Calculator.MainController">
    <padding>
        <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
    </padding>
    <children>
        <TextField fx:id="txtDisplay" disable="true" alignment="CENTER_RIGHT" editable="false" minHeight="-Infinity"
                   prefHeight="50.0" text="0"/>
        <GridPane hgap="10.0" vgap="10.0" VBox.vgrow="ALWAYS">
            <columnConstraints>
                <ColumnConstraints hgrow="SOMETIMES" minWidth="-Infinity"/>
                <ColumnConstraints hgrow="SOMETIMES" minWidth="-Infinity"/>
                <ColumnConstraints hgrow="SOMETIMES" minWidth="-Infinity"/>
                <ColumnConstraints hgrow="NEVER" minWidth="-Infinity"/>
                <ColumnConstraints hgrow="SOMETIMES" minWidth="-Infinity"/>
                <ColumnConstraints hgrow="SOMETIMES" minWidth="-Infinity"/>
            </columnConstraints>
            <rowConstraints>
                <RowConstraints minHeight="-Infinity" vgrow="SOMETIMES"/>
                <RowConstraints minHeight="-Infinity" vgrow="SOMETIMES"/>
                <RowConstraints minHeight="-Infinity" vgrow="SOMETIMES"/>
                <RowConstraints minHeight="-Infinity" vgrow="SOMETIMES"/>
            </rowConstraints>
            <children>
                <Button fx:id="btn7" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="7"/>
                <Button fx:id="btn8" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="8" GridPane.columnIndex="1"/>
                <Button fx:id="btn9" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="9" GridPane.columnIndex="2"/>
                <Separator orientation="VERTICAL" prefHeight="200.0" GridPane.columnIndex="3" GridPane.rowSpan="4"/>
                <Button fx:id="btnDivide" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="÷" GridPane.columnIndex="4"/>
                <Button fx:id="btnClear" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="C" GridPane.columnIndex="5"/>
                <Button fx:id="btn4" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="4" GridPane.rowIndex="1"/>
                <Button fx:id="btn5" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="5" GridPane.columnIndex="1"
                        GridPane.rowIndex="1"/>
                <Button fx:id="btn6" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="6" GridPane.columnIndex="2"
                        GridPane.rowIndex="1"/>
                <Button fx:id="btnMultiply" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="x" GridPane.columnIndex="4"
                        GridPane.rowIndex="1"/>
                <Button fx:id="btn1" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="1" GridPane.rowIndex="2"/>
                <Button fx:id="btn2" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="2" GridPane.columnIndex="1"
                        GridPane.rowIndex="2"/>
                <Button fx:id="btn3" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="3" GridPane.columnIndex="2"
                        GridPane.rowIndex="2"/>
                <Button fx:id="btn0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" text="0" GridPane.columnSpan="2"
                        GridPane.rowIndex="3"/>
                <Button fx:id="btnDecimal" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="." GridPane.columnIndex="2"
                        GridPane.rowIndex="3"/>
                <Button fx:id="btnSubtract" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="-" GridPane.columnIndex="4"
                        GridPane.rowIndex="2"/>
                <Button fx:id="btnAdd" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="+" GridPane.columnIndex="4"
                        GridPane.rowIndex="3"/>
                <Button fx:id="btnEquals" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="="
                        GridPane.columnIndex="5" GridPane.rowIndex="2" GridPane.rowSpan="2"/>
                <Button fx:id="btnBackspace" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                        mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="←" GridPane.columnIndex="5"
                        GridPane.rowIndex="1"/>
            </children>
        </GridPane>
    </children>
</VBox>

MainController.java:

import javafx.application.Platform;
import javafx.css.PseudoClass;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;

public class MainController {

    // Here we'll define our PseudoClass needed to set the style for each pressed Button
    private static final PseudoClass PRESSED = PseudoClass.getPseudoClass("pressed");

    // Define FXML controls
    @FXML
    private TextField txtDisplay;
    @FXML
    private Button btn7, btn8, btn9;
    @FXML
    private Button btn4, btn5, btn6;
    @FXML
    private Button btn1, btn2, btn3;
    @FXML
    private Button btn0, btnDecimal;
    @FXML
    private Button btnMultiply, btnSubtract, btnAdd, btnDivide;
    @FXML
    private Button btnClear, btnEquals, btnBackspace;

    @FXML
    private void initialize() {

        // We need access to the Scene to register our key listeners, so we need to wrap the code in a Platform.runLater(). If we try to do this without Platform.runLater(), we'll get a NullPointerException because txtDisplay hasn't been rendered yet.
        Platform.runLater(() -> {

            Scene scene = txtDisplay.getScene();

            // Add a listener to capture any key that is pressed. We add this to the entire scene and we can then change the style of the corresponding button accordingly.
            scene.setOnKeyPressed(event -> {

                // We need to know which Button we're working with
                Button button = getButton(event.getCode());

                // Add our "pressed" style to the Button
                if (button != null) button.pseudoClassStateChanged(PRESSED, true);
            });

            // Once the user releases the key, remove our custom style and trigger whatever onAction() code has been applied to the corresponding Button.
            scene.setOnKeyReleased(event -> {

                Button button = getButton(event.getCode());
                if (button != null) {
                    button.pseudoClassStateChanged(PRESSED, false);

                    // Fire the button's onAction()
                    button.fire();
                }

            });
        });


    }

    // Helper method to get the Button that corresponds to the pressed key. The Scene.setOnKeyPressed() listener provides the KeyCode for the pressed key. We can use that to determine which of our Buttons to trigger.
    private Button getButton(KeyCode keyCode) {
        switch (keyCode) {
            case NUMPAD0: return btn0;
            case NUMPAD1: return btn1;
            case NUMPAD2: return btn2;
            case NUMPAD3: return btn3;
            case NUMPAD4: return btn4;
            case NUMPAD5: return btn5;
            case NUMPAD6: return btn6;
            case NUMPAD7: return btn7;
            case NUMPAD8: return btn8;
            case NUMPAD9: return btn9;
            case DECIMAL: return btnDecimal;
            case DIVIDE: return btnDivide;
            case ADD: return btnAdd;
            case MULTIPLY: return btnMultiply;
            case SUBTRACT: return btnSubtract;
            case ENTER: return btnEquals;
            case BACK_SPACE: return btnBackspace;
            case ESCAPE: return btnClear;
        }
        return null;
    }
}

style.css:

.text-field {
    -fx-opacity: 1.0;
    -fx-font-family: Consolas;
    -fx-font-size: 200%;
}

.button {
    -fx-font-family: Consolas;
    -fx-font-size: 150%;
    -fx-background-radius: 25px;
    -fx-border-radius: 25px;

    /* Remove focus highlighting */
    -fx-focus-traversable: false;
}

.button:pressed {
    -fx-background-color: lightgreen;
    -fx-border-color: green;
}

结果如下:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-06
    • 2014-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多