Matrix of Buttons (How to Create and Arrange) in JavaFX - java

This is my first program written in JavaFX (as opposed to Swing). I'm starting small by simply displaying data sets in a matrix of buttons (I do not wish to use a Table just yet).
package matrixjavafx;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.util.Random; // required for random number generation
/**
*
* #author Matt
*/
public class MatrixJavaFX extends Application {
Button[][] matrix; //names the grid of buttons
#Override
public void start(Stage primaryStage) {
int SIZE = 10;
int length = SIZE;
int width = SIZE;
StackPane root = new StackPane();
matrix = new Button[width][length]; // allocates the size of the matrix
// runs a for loop and an embedded for loop to create buttons to fill the size of the matrix
// these buttons are then added to the matrix
for(int y = 0; y < length; y++)
{
for(int x = 0; x < width; x++)
{
Random rand = new Random(); // Creates new Random object for generating random numbers
// The following variables are generated using Random object rand.
// rand.nextInt(2) generates a double ranging from 0.000 to 0.999.
// setting the target variable to be an integer truncates the range to 0 - 1.
int rand1 = rand.nextInt(2); // Declare and initialize random integer (0 - 1) + 1
matrix[x][y] = new Button(/*"(" + rand1 + ")"*/); //creates new random binary button
matrix[x][y].setText("(" + rand1 + ")"); // Sets the text inside the matrix
matrix[x][y].setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Random Binary Matrix (JavaFX)");
}
});
root.getChildren().add(matrix[x][y]);
}
}
Scene scene = new Scene(root, 500, 500);
primaryStage.setTitle("Random Binary Matrix (JavaFX)");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
greeting(); // Greets the User and explains the purpose of the program
launch(args); // Opens the window that generates and displays the matrix
//new MatrixSwingGUI(width, length); // makes new MatrixSwing with 2 parameters
thanks(); // Thanks User and indicates that the program is about to close
}
public static void greeting()
{
// Greets the User and displays the program's purpose
System.out.println("Welcome to the Random Matrix Generator\n");
System.out.println("The purpose of this program is to generate and display "
+ "\na 10 x 10 matrix of random 0's, and 1's.");
}
public static void thanks() // Thanks User and indicates that the program is about to close
{
System.out.println("\nGoodbye and Thank You for using the Random Matrix Generator\n\n");
} // End thanks method
}
The heart of the problem seems to be the following line, since by default all of the buttons are stacking on top of each other in the center of the pane.
StackPane root = new StackPane();
That said, I would like the buttons to align side by side for all of length and width, resulting in an n x m matrix. What should be done to accomplish this? What additional javafx.scene.* files need to be imported?

The basic problem is the Layout that you have chosen for the project. You can get an in-depth knowledge about layouts, that javafx support over here
StackPane stacks all the Nodes that you pass it. I would suggest you to use GridPane inplace of StackPane.
GridPane root = new GridPane();
To add the nodes, use
root.add(matrix[x][y], y, x);
P.S. I would also advice you to rename your buttons, to give you more clarity on button representing row's and column's of the matrix. You can use something as, though its totally optional ! :)
matrix[x][y].setText(x + "," + y);

Related

How to combine images in a JFrame?

I have been working on a project that is displaying a grid 16 x 16 of images, based on user interaction this grid follows the user on a dynamically larger base (an example would be a base that is 50 x 50) than the 16 x 16 display.
However, I am using JLabel components to display these images, and every time the user interacts I have to move each of the 256 images and erase the ones that are no longer in the 16 x 16 display grid. This results in a lag that is close to a second per key press and is close to nonfunctional.
What I am looking to try to do is to chain these images together in the total width of the ground and simply move the focus to the portion that is within the 16 x 16 grid, making the process no longer have to use nested for loops for the display.
Is it possible that I could dynamically store and create these chained images for display using a label? If are there other ways to display .png files in Java that could be stored and used in a similar manner?
An example of my current methodology of having to draw every image upon every user interaction:
User user = game.user;
int floorWidth = game.floorWidth;
int floorHeight = game.floorHeight;
int pX = user.getTile().getX();
int pY = user.getTile().getY();
int minX = Math.max(pX - GameConstants.USER_DRAW_DISTANCE, 0);
int maxX = Math.min(floorWidth, pX + GameConstants.USER_DRAW_DISTANCE);
int minY = Math.max(pY - GameConstants.USER_DRAW_DISTANCE, 0);
int maxY = Math.min(floorHeight, pY + GameConstants.USER_DRAW_DISTANCE);
for (int i = minY; i < maxY; i++)
{
for (int x = minX; x < maxX; x++)
{
Tile tile = floor.getTile(x, i);
if (tile.getHasSeen())
{
JLabel cLabel = tile.imageLabel;
cLabel.setLocation(340 + x * 32, 140 + i * 32);
cLabel.setSize(64, 64);
cLabel.setVisible(true);
panel.add(cLabel, 1);
}
}
}
In principle your idea should work. So you're probably doing something else wrong.
I've made an example, where it displays a 16x16 square of JLabels out of 256x256 JLabels. When you move the mouse over the panel, it changes the layout to show a new set of 16x16 JLabels. The change is pretty snappy, definitely not a 1 second delay.
import javax.swing.*;
import java.awt.EventQueue;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.event.*;
import java.util.*;
public class GridViewer{
int x0, y0;
int N = 256;
int display = 16;
int length = 32;
List<JLabel> showing = new ArrayList<>();
List<JLabel> available = new ArrayList<>();
JPanel panel = new JPanel(){
Dimension sz = new Dimension(length*display, length*display);
#Override
public Dimension getPreferredSize(){
return sz;
}
};
public void showGui(){
JFrame frame = new JFrame();
panel.setLayout(null);
panel.addMouseMotionListener( new MouseAdapter(){
Random r = new Random();
#Override
public void mouseMoved(MouseEvent evt){
int x = evt.getX();
int y = evt.getY();
//map to position on the image to the position on the grid.
x0 = x/2;
x0 = Math.min(x0, N-display);
y0 = y/2;
y0 = Math.min(y0, N-display);
updateLayout();
}
});
for(int i = 0; i<N*N; i++){
available.add(createItem(i));
}
updateLayout();
frame.setContentPane(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
/**
* Creates a solid color jlabel, could be used to load an image
* as an icon.
**/
JLabel createItem(int i){
JLabel l = new JLabel("");
int r = (i/256);
int g = (0)&255;
int b = (i%256);
int c = (r << 16 ) + ( g << 8 ) + b;
l.setBackground(new Color(c));
l.setOpaque(true);
l.setSize(length, length);
return l;
}
public void updateLayout(){
for(JLabel l: showing){
panel.remove(l);
}
for(int i = 0; i<display; i++){
for(int j = 0; j<display; j++){
JLabel l = available.get((i + x0) + (j+y0)*N);
panel.add(l);
l.setLocation( i*length, j*length);
showing.add(l);
}
}
}
public static void main(String[] args){
EventQueue.invokeLater( () -> new GridViewer().showGui() );
}
}
Some variations.
Use a GridLayout
Using a layout manager has a lot of advantages. Especially when it comes to using different displays, fonts and platforms? When adding and removing elements, it could make partially showing elements tough.
Use a large JPanel with a ScrollPane
We could create a single JPanel and add all 256x256 components to it, then use a scroll pane to set the view. This would have an advantage of completely separating the layout and the view. Somebody wants a larger window, you don't have to change the layout, the view gets bigger and you just see more of the layout. For 256x256 components, it should perform well but if you have too many components you might want to reconsider it.
Use a JPanel and override paintComponent
This would involve loading your 'png' files as awt Images (probably BufferedImages) and drawing them with the graphics object. You would need to handle all of the layout and rendering. It gives you quite a bit of power over how you want to render your components.

Reading the value of a Math.random generated button label

I am working on an exercise that is asking me to do the following;
Create a GridPane
Set the pane’s horizontal and vertical gap to zero
Set the pane’s grid line visibility to true
Use nested FOR loops to create and add buttons to the pane (loops
starts from 0 to 10)
Each button must be labeled with any number between 0 to 99
Color the buttons based on the following rules:
a. If the color’s label is divisible by 2, then change the color to Blue
b. If the color’s label is divisible by 3, then change the color to
Yellow
c. If the color’s label is divisible by 6, then change the color to Green
Add the pane to a scene
Add the scene to a stage, then display the Stage
I have everything set up, just not sure how to read the value generated by Math.random and do assign a specific color to that button.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.layout.GridPane;
import javafx.scene.control.Button;
import javafx.scene.paint.Color;
public class Exercise8GridPane extends Application {
#Override
public void start(Stage primary) {
primary.setTitle("Exercise 8");
GridPane gp = new GridPane();
gp.setHgap(0);
gp.setVgap(0);
gp.setGridLinesVisible(true);
for (int k = 0; k < 10; k++) {
for (int l = 0; l < 10; l++) {
Button btn = new Button(String.valueOf((int)(Math.random() * 100)));
// if / 3 == 0){
btn.setStyle("-fx-base:red;-fx-text-fill:yellow");
gp.add(btn, l, k);
}
}
Scene s = new Scene(gp);
primary.setScene(s);
primary.show();
}
public static void main(String[] args) {
launch(args);
}
}
The java.lang.Math.random() returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0. This new pseudorandom-number generator is used thereafter for all calls to this method and is used nowhere else.
There are countless ways to read it.
I would recommend doing something like
int RED = (int) (Math.random() * 256);
// Note that Math.random() returns a value less than 1.0
int BLUE = ...
It's difficult to get three values from one number, so I think this will work well.

Generating Random Graphics + Questions About Learning Java

Before anything: Is it alright to submit a question to Stack Overflow when you're trying to learn to code? I've really put about 20 hours into this problem and am entirely stuck, but if I should remain stuck for the experience of realizing how to craft my own solutions, please say the word Stack Overlords.
I am attempting to create a function that creates ten circles of a semi-random size and location and a random color.
The size and location are semi-random because the circle's radius must be between 5 - 50 pixels; the location must be within the Jpanel.
The color can be anything. The production of the circles must stop at ten and all the circles must be static in the same Jpanel at once.
I've finished the problem almost entirely asides from being able to get the ten circles to remain static within the Jpanel after they've been generated.
I've tried applying a basic for-loop around various sections of the code I thought could produce the desired result. My for-loop is shown below.
for(int i = 0; i < 10; ++i) {
}
package assignment3;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
import javax.swing.JFrame;
public class Random_Circles extends JPanel{
private static final long serialVersionUID = 1L;
// Below is the input for our random size.
public static int RandomSize() {
double randomDouble = Math.random();
randomDouble = randomDouble * 50 + 1;
int randomInt = (int) randomDouble;
return randomInt;
}
// Below is the input for our random X-coordinate.
public static int RandomPosition1() {
double randomDouble = Math.random();
randomDouble = randomDouble * 900 + 1;
int randomInt = (int) randomDouble;
return randomInt;
}
// Below is the input for our random Y-coordinate.
public static int RandomPosition2() {
double randomDouble = Math.random();
randomDouble = randomDouble * 400 + 1;
int randomInt = (int) randomDouble;
return randomInt;
}
// I don't really know what this does, but I've gotta do it apparently.
Random rand = new Random();
// Below is the input for our random color.
public void paintComponent(Graphics RC) {
super.paintComponent(RC);
this.setBackground(Color.white);
// Random Size
int RS;
RS = RandomSize();
// X-coordinate
int RP1;
RP1 = RandomPosition1();
// Y-coordinate
int RP2;
RP2 = RandomPosition2();
// Color inputs
float r = rand.nextFloat();
float g = rand.nextFloat();
float b = rand.nextFloat();
Color randomColor = new Color(r, g, b);
// Color function
RC.setColor(randomColor);
// Location and size function
RC.fillOval(RP1, RP2, RS, RS);
}
}
Main function that produces Jpanel, calls previous code.
package assignment3;
import javax.swing.JFrame;
import assignment3.Random_Circles;
public class Random_Circles_Exe {
public static void main(String[] args) {
JFrame f = new JFrame("Random Cirlces");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Random_Circles r = new Random_Circles();
f.add(r);
f.setSize(1000,500);
f.setVisible(true);
}
}
Expected: Ten circles with the required parameters appearing and remaining in the JPanel.
Actual: Ten circles being generated the second the function runs, but with each new circle the old one expires. With re-sizing the JPanel ( just by clicking and dragging its border ), more circles are generated.

new line when i display 10 ellipse

I am new in processing and java, I have some exercise to display 100 ellipses but the screen size is (900, 600), and I want break 100 in 10 lines of 10, but I don't know how to break line in processing , I already use translate(https://processing.org/reference/translate_.html),but it doesn't work.
//function
void draw(){
smooth();
noStroke();
fill(23,43,208,200);// cor azul
ellipse(posX,posY,12,10);
noStroke();
fill(242,76,39);//cor vermelho
ellipse(posX,posY,12,10);
}
for (int i=1; i<ellipses.length; i++)
{
for (int j=i; j<ellipses.length; j++)
{
if(j%10==0)
ellipses[i].draw();//calling function
}
}
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.shape.Ellipse;
import javafx.stage.Stage;
public class T15DrawEllipses extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Group group = new Group();
Scene scene = new Scene(group, 900, 600);
for (int row = 0; row < 10; row++) {
for (int col = 0; col < 10; col++) {
Ellipse e = new Ellipse();
e.setCenterX(44 + col * 90);
e.setCenterY(29 + row * 60);
e.setRadiusX(45);
e.setRadiusY(30);
group.getChildren().add(e);
}
}
primaryStage.setScene(scene);
primaryStage.show();
}
}
A complete example of 10 rows/columns with ellipses.
The best thing you can do when you have questions like this is to get out a piece of graph paper, and draw out a bunch of examples until you notice a pattern. What is the X,Y position of every cirlce you want to draw? What is the X value of the first row, the second row, the third row? What is the Y value of the first column, the second column, the third column?
You should also get into the habit of breaking your problem down into smaller pieces and taking those pieces on one at a time. For example, instead of trying to draw 100 circles in a grid, why don't you just try to draw 10 circles in a single row? Create a function that draws a row of circles. Then try calling that function multiple times to create your grid of circles.
If you get stuck on a specific step, you can ask a more specific question along with a MCVE. Good luck.

Java Lines Confusion

I am having a problem with my java code. I'm trying to make it so the top left quadrant produces a set number of lines input by a user through JOption Pane which are in random colors and in random positions. The programs builds successfully but it does not produce the number of lines the user input, nor does it set a random color (This it at the very bottom of my code). Can someone please explain how to fix this problem? Thanks very much.
Edit: fixed the curve braces but still will not work.
Edit: Everything works now except the random colors
import javax.swing.*; //for JFrame
import java.awt.*; //for Graphics and Container
import java.util.Random;
import javax.swing.JOptionPane;
// other import statements here
public class RandomGraphics
{
// constants are used to draw the grid, and for you to put shapes in the grid
public static final int MIDX = 400;
public static final int MIDY = 300;
public static final int MAXX = 799;
public static final int MAXY = 599;
public static final int COLOR = (int) (Math.random() * 256);
// make another constant for the color value that will
// be used to generate a random color
public static void main( String[] args )throws InterruptedException
{
//*** This next section sets up the graphics window.
//*** You are not required to understand it
Container contentPane;
Graphics g;
JFrame win = new JFrame("Random Graphics");
win.setSize(825,650);
win.setLocation(0,0);
win.setVisible(true);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = win.getContentPane();
contentPane.setBackground(Color.white);
g = contentPane.getGraphics();
Thread.sleep(50);
//*** done setting up graphics window
// Draws Grid - DO NOT CHANGE
// After you use JOptionPane to get the number of lines, you can move this
// section of code to just after that, so the lines will not disappear
g.drawRect(0,0,MAXX+1,MAXY+1);
g.drawLine(0,MIDY,MAXX,MIDY); // horizontal line
g.drawLine(MIDX,0,MIDX,MAXY); // vertical line
// Create Random object
Random r = new Random();
// Top left quadrant:
// Use a JOptionPane to ask the user to enter the number of lines 1 to 100.
int count = 0;
do
{
String morelines = JOptionPane.showInputDialog("Enter a number of lines between 1 to 100");
count = Integer.parseInt(morelines);
}
while(count > 100 || count < 1);
for(int i = 1; i >= count; i++)
{
g.setColor(new Color (r.nextInt(COLOR), r.nextInt(COLOR), r.nextInt(COLOR)));
g.drawLine(r.nextInt(MIDX), r.nextInt(MIDY), r.nextInt(MIDX), r.nextInt(MIDY));
}
g = contentPane.getGraphics();
Graphics objects are not persistent, the programmer needs to draw the GUI to them when asked to do so. For tips, see the Performing Custom Painting Lesson of the tutorial.
Beside the 'always include curly braces around loops advice', note..
for(int i = 1; i >= count; i++)
Should be..
for(int i = 1; i <= count; i++)
But don't ignore the advice about custom painting. The app. will not render reliably until that is fixed.
for(int i = 1; i >= count; i++)
g.setColor(new Color (r.nextInt(COLOR), r.nextInt(COLOR), r.nextInt(COLOR)));
g.drawLine(r.nextInt(MIDX), r.nextInt(MIDY), r.nextInt(MIDX), r.nextInt(MIDY));
Looking at your indenting, it looks like you want g.setColor(...) and g.drawLine(...) to be inside your for loop. You need to enclose them in curly braces {}, otherwise only the statement immediately following your for loop will be inside the loop.

Categories