0

I am attempting to line up n amount of rectangles in a JavaFX program. My overall goal is to make some type of "Audio Equalizer" as attached. How do I achieve this using the Rectangle methods in JavaFx?

I know that if say I have a width in the pane that is 740 and I want to have 10 equal rectangles, each one would be 74 wide. So Rect 1's width would need to be positioned from : 0-74, Rect 2 would be 75-149 etc.

I have tried to use the Rectangle.setX and use ranges but that would leave one rectangle the size of the entire pane. Or one rectangle would be the perfect width, but only 1 rectangle would show.

Below is my attempt to Override the start method to display my visualizer.

The Start method is the root of the problem.

public class AudioEqualizer implements Visualizer {

private String name = "AudioEqualizer"; 
private Integer numOfBands;
private AnchorPane vizPane; 

private Double height = 0.0; 
private Double width = 0.0; 

private Double rectHeight = 0.0;
private Double rectWidth = 0.0;

private Double rectHeightPercentage = 1.3; 

private final Double startHue = 260.0;
private Double halfRectHeight = 0.0;


private Rectangle[] rectangles; 

@Override
public String getName() {
    return name;
}

@Override
public void start(Integer numBands, AnchorPane vizPane) {        
    end();

    this.numOfBands = numBands;
    this.vizPane = vizPane;

    height = vizPane.getHeight();
    width = vizPane.getWidth();


    Rectangle clip = new Rectangle(width, height);
    clip.setLayoutX(0);
    clip.setLayoutY(0);
    vizPane.setClip(clip);
    clip.setFill(Paint.valueOf("BLACK"));

   rectWidth = width / numBands;
   rectHeight = height / 2 ;
   rectangles = new Rectangle[numBands];


    for (int i = 0; i < numBands; i++) {

        Rectangle rectangle = new Rectangle((rectWidth * (i-1)), 0, 
        rectWidth, rectHeight); 
        //rectangle.setX(rectWidth); 
        rectangle.setFill(Color.hsb(startHue, 1.0, 1.0, 1.0));

        rectangles[i] = rectangle;
        vizPane.getChildren().add(rectangle);

    }

}

I would hope it would look something wherein I can get rectangles to line up next to each other as in this picture.

But what is actually occurring is one of two things depending on the code commented or uncommented within the for loop.

Goal: https://i.stack.imgur.com/EHiDd.jpg

Results:

1) https://i.stack.imgur.com/UhgBc.jpg

or

2) https://i.stack.imgur.com/VtewX.jpg

Thank you for your time.

  • If you put multiple `Rectangle`s with the same dimentions and color next to each other, the result looks as if it was a single rectangle. Note that your code does not result in an responsive layout. Resizing the parent won't change the size of the bars and depending on the time when the code is executed the dimensions of the parent may still be `0 x 0`... – fabian Apr 18 '19 at 09:09
  • See also `AudioBarChartApp`, cited among the answers [here](https://stackoverflow.com/q/54925007/230513). – trashgod Apr 18 '19 at 09:18
  • @fabian so you are saying have some offset and maybe my answer is right ? – Armaja LaRue-Love Apr 18 '19 at 13:10

1 Answers1

1

You can try using a HBox as a container for your rectangles. It will automatically place your rectangles one next to the other and it allows you to control how much space you want between them.

Add rectangles in the FXML

    <HBox fx:id="rectangleContainer" spacing="2" alignment="BOTTOM_LEFT" >
        <Rectangle fill="blue" width="10" height="50"/>
        <Rectangle fill="blue" width="10" height="20"/>
        <Rectangle fill="blue" width="10" height="10"/>
        <Rectangle fill="blue" width="10" height="40"/>
        <Rectangle fill="blue" width="10" height="50"/>
        <Rectangle fill="blue" width="10" height="60"/>
        <Rectangle fill="blue" width="10" height="30"/>
        <Rectangle fill="blue" width="10" height="30"/>
        <Rectangle fill="blue" width="10" height="20"/>
        <Rectangle fill="blue" width="10" height="10"/>
        <Rectangle fill="blue" width="10" height="50"/>
        <Rectangle fill="blue" width="10" height="60"/>
    </HBox>

This FXML will produce the following result: image.

Add the rectangles programmatically

If you want to add the rectangles programmatically, you just need the reference to the HBox and do something like the following.

@FXML
private HBox rectangleContainer;
...
for (int i = 0; i < numBands; i++) {
    Rectangle rect = new Rectangle(rectangleWidth, rectangleHeight); 
    rect.setFill(Color.BLUE);
    rectangleContainer.getChildren().add(rect);
}

Fixed width container

Let's suppose you have a 740px width HBox and you want to fill it with 10 rectangles separated by a 10px space.

int numBands = 10;
double spacing = 10.0;
double totalSpacing = spacing * (numBands-1);
double rectangleWidth = (rectangleContainer.getPrefWidth()-totalSpacing) / numBands;
for (int i = 0; i < numBands; i++) {
    Rectangle rect = new Rectangle(rectangleWidth, Math.random()*500); //random height. replace with the value you want 
    rect.setFill(Color.BLUE);
    rectangleContainer.getChildren().add(rect);
}

This is the result: image

Hope this helps.

Update:

Sorry, I did not realize you could not use an HBox. I think the problem in image 1 is that a spacing between the rectangles is missing. You can try changing the rectangle X with like this:

for (int i = 0; i < numBands; i++) {
    Rectangle rectangle = new Rectangle((rectWidth+2) * i, 0, 
    rectWidth, rectHeight); 
    rectangle.setFill(Color.hsb(startHue, 1.0, 1.0, 1.0));
    rectangles[i] = rectangle;
    vizPane.getChildren().add(rectangle);
}

I used a spacing of 2. This of course could make the AnchorPane to increase its width to fit all the rectangles and spacing. If you don't want that, you have to consider the spacing when calculating the width of the rectangles.

crowde
  • 321
  • 1
  • 12
  • This is so cool that it worked on your end. I cannot use an Hbox because the class that will call this class will not accept it. I get a thread warning when I attempt to add the HBox to the anchorPane and it doesn't display without it. – Armaja LaRue-Love Apr 18 '19 at 19:35
  • Jk It doesn't produce an error, it does only produce case 2 wherein there is only one rectangle. – Armaja LaRue-Love Apr 18 '19 at 19:59
  • Sorry, I didn't realize you could not use an HBox. I updated my answer. I took your code and just changed the X of the rectangle. Check if that helps – crowde Apr 18 '19 at 21:05