-1

Tasked with creating a user interface that has a top bar which includes a menu. The menu should have four items. First prints the date to a dialog box, second writes that date to a .txt file, third changes the frame background color to random color hue of the color green, fourth exits.

I have everything working except number 3. I have it set up so that the menuBar changes to a predetermined color green when you select the colorItem MenuItem.

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import java.util.Random;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import java.time.LocalDate;


public class Main extends Application {
    @Override
    public void start(Stage stage) {
 
        // Create MenuBar
        MenuBar menuBar = new MenuBar();
        
        // Create menus
        Menu dateMenu = new Menu("Print");
        Menu textMenu = new Menu("Write");
        Menu colorMenu = new Menu("Change Color");
        Menu exitMenu = new Menu("Options");
        
        // Create MenuItems
        MenuItem dateItem = new MenuItem("Date/Time");
        MenuItem textItem = new MenuItem("Save To Text File");
        MenuItem colorItem = new MenuItem("Random Color");
        MenuItem exitItem = new MenuItem("Exit");
        
        // Add menuItems to the Menus
        dateMenu.getItems().addAll(dateItem);
        textMenu.getItems().addAll(textItem);
        colorMenu.getItems().addAll(colorItem);
        exitMenu.getItems().addAll(exitItem);
        
        // Add Menus to the MenuBar
        menuBar.getMenus().addAll(dateMenu, textMenu, colorMenu, exitMenu);
        
       
        // When user clicks on Date/Time MenuItem
        dateMenu.setOnAction(new EventHandler<ActionEvent>()    {

            @Override
            public void handle(ActionEvent event) {
                LocalDate today = LocalDate.now();
                Alert alert = new Alert(AlertType.INFORMATION);
                alert.setTitle("Date Printer");
                alert.setHeaderText(null);
                alert.setContentText("Today's Date is: " + today);
                alert.showAndWait();
                            }
        });
        
        // When user clicks on Save to Text File MenuItem
        textMenu.setOnAction(new EventHandler<ActionEvent>()    {

            @Override
            public void handle(ActionEvent event) {
                LocalDate today = LocalDate.now();
                try {
                    
                    // Log message created
                    String content = "Button clicked on: " + today;

                    File file = new  File("C:\\Users\\stca\\OneDrive - Episerver\\Desktop\\Week3.txt");

                    // File already created on desktop
                    if (!file.exists()) {
                        file.createNewFile();
                    }

                    FileWriter fw = new FileWriter(file.getAbsoluteFile());
                    BufferedWriter bw = new BufferedWriter(fw);
                    bw.write(content);
                    bw.close();

                    System.out.println("Done");

                } catch (IOException e) {
                    e.printStackTrace();
                }
                            }
        });
        
        // When user clicks on Change Color MenuItem
        colorMenu.setOnAction(new EventHandler<ActionEvent>()   {

            @Override
            public void handle(ActionEvent event) {
                menuBar.setStyle("-fx-background-color: #33cc33;");
                            }
        });
        
        // Set Accelerator for Exit MenuItem.
        exitItem.setAccelerator(KeyCombination.keyCombination("Ctrl+X"));
         
        // When user clicks on the Exit MenuItem
        exitItem.setOnAction((EventHandler<ActionEvent>) new EventHandler<ActionEvent>() {
         
            @Override
            public void handle(ActionEvent event) {
                System.exit(0);
            }
        });
        

        BorderPane root = new BorderPane();
        root.setTop(menuBar);
        Scene scene = new Scene(root, 400, 200);
        
        stage.setTitle("JavaFX Menu for CSC372");
        stage.setScene(scene);
        stage.show();
    }
 
    public static void main(String[] args) {
        Application.launch(args);
    }
 
}

How do I get the background to change color instead of the menuBar? Also, how can I invoke some randomization of different hues of green? I tried this:

        // When user clicks on Change Color MenuItem
        colorMenu.setOnAction(new EventHandler<ActionEvent>()   {

            @Override
            public void handle(ActionEvent event) {
                Random random = new Random(); 
                int r = random.nextInt(); 
                int g = random.nextInt(); 
                int b = random.nextInt(); 
                Color randomColor = new Color(r, g, b);
                menuBar.setStyle("-fx-background-color: randomColor");
                            }
        });

But my IDE is telling me that the constructor is not visible.

CSUSC
  • 1
  • 2
  • 2
    Check your imports: `java.awt.Color` has such a constructor, but `javafx.scene.paint.Color` does not. This [example](https://stackoverflow.com/a/31761362/230513) uses `Color.hsb()`. – trashgod Sep 01 '21 at 22:31
  • [mcve] please .. and get your technical vocabulary right: there is no _javafx frame_ – kleopatra Sep 01 '21 at 22:41
  • 1
    You’ll probably find the [documentation of Color](https://openjfx.io/javadoc/16/javafx.graphics/javafx/scene/paint/Color.html) helpful. – VGR Sep 02 '21 at 04:30
  • 1
    *"How do I get the background to change color instead of the menuBar?"* `root.setStyle(...)` instead of `menuBar.setStyle(...)`? (Obviously you'll need to reorder the code slightly.) – James_D Sep 02 '21 at 13:12

2 Answers2

1

Sample code

This code allows the user to trigger setting a random background color (a shade of green) after selecting a menu item.

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.Random;

public class ColorSelector extends Application {
    private final Random random = new Random(42);

    private final ColorGenerator colorGenerator = new ColorGenerator();

    @Override
    public void start(Stage stage) {
        MenuItem colorItem = new MenuItem("Random Color");
        Menu colorMenu = new Menu("Change Color", null, colorItem);
        MenuBar menuBar = new MenuBar(colorMenu);

        BorderPane root = new BorderPane();
        root.setTop(menuBar);
        setRandomBackgroundColor(root);
        colorMenu.setOnAction(event -> setRandomBackgroundColor(root));

        Scene scene = new Scene(root, 400, 200);
        stage.setScene(scene);

        stage.show();
    }

    private void setRandomBackgroundColor(Region region) {
        Color color = colorGenerator.generateRandomShadeOfGreen();

        // option 1: set the fill on the root via a background color.
        region.setBackground(
                new Background(
                        new BackgroundFill(color, null, null)
                )
        );

        // option 2: set the fill on the root via a css style.
        // region.setStyle("-fx-background-color: #" + colorToString(color));
    }

    private String colorToString(Color color) {
        int r = (int)Math.round(color.getRed() * 255.0);
        int g = (int)Math.round(color.getGreen() * 255.0);
        int b = (int)Math.round(color.getBlue() * 255.0);
        int o = (int)Math.round(color.getOpacity() * 255.0);

        return String.format("%02x%02x%02x%02x" , r, g, b, o);
    }

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

    private class ColorGenerator {
        private int curColorIndex = 0;

        private final Color[] colorTable = {
                Color.rgb(0, 50, 0),
                Color.rgb(0, 100, 0),
                Color.rgb(0, 150, 0),
                Color.rgb(0, 250, 0),
        };

        private Color generateRandomShadeOfGreen() {
            int nextColorIndex = curColorIndex;

            while (nextColorIndex == curColorIndex) {
                nextColorIndex = random.nextInt(colorTable.length);
            }

            curColorIndex = nextColorIndex;

            return colorTable[nextColorIndex];
        }
    }
}

Advice on the usage of this solution

I know this is your homework, but here is a sample solution anyway, I don't advise just copy and pasting it and handing it in, you can use it to check your implementation if you run into issues.

For bonus points try to understand the meaning of Random(42) (read the javadoc for Random). Also, read the relevant Background and Color API javadoc and the color section of the JavaFX CSS reference guide.

Implementation notes

For the color lookup, it uses a pre-defined color table, which would seem to me to be a good solution to the problem.

The table could be defined externally in CSS rather than inline, doing so is out of scope for this answer. If interested, search the JavaFX source code base for usages of CHART_COLOR_ in the moderna.css file to see how this is done.

Instead of using a lookup table, you could just create a random g value for the RGB specifier if you wanted.

The code demonstrates setting a color via either a BackgroundFill or an inline CSS style.

Other issues with your color randomization function

  1. The arguments (even for the correct color constructor) will have a range for RGB values (e.g. 0-255), so you can't just use any random int value.
  2. You probably don't want an RGB value which is too low, otherwise, it will just look black to the naked eye.
  3. You can't just take a Java variable and write its name in a String to have the variable value in the string.
  4. If you only want a green RGB color, then set the r and b values to 0.
  5. Reuse the random number generator, don't create one on every click, that is expensive.
jewelsea
  • 150,031
  • 14
  • 366
  • 406
-2

I can drop a hint or two; but I've run this program because I wrote my first CTA3 with code that is almost identical to yours (with a few differences). The instructions don't say that you have to write this program in JavaFX.