Java half of JButtons stop working in JPanel - java

I'm trying to make a unit conversion program using Jbuttons in a jpanel. So far when I run the program however, the first window pops up, I select "Length". Now, it shows 8 buttons on each side, after selecting one of those, half of the buttons will no longer work, only the right column of each side works.
public class Gui extends JFrame {
private JButton Subject[] = new JButton[8];
private String SubjNames[] = {"Length", "Mass", "Currency", "Temperature", "Time", "Speed", "Data", "Cooking"};
private JButton Length1[] = new JButton[8];
private JButton Length2[] = new JButton[8];
private String LengNames[] = {"inches", "feet", "yards", "miles", "millimeters", "centimeters", "meters", "kilometers"};
private JTextField convertedFrom;
private JTextField amountFrom;
private JTextField convertedTo;
private JTextField amountTo;
private String from;
private String CTo;
private String ATo;
private int SubjectLocX = 40;
private int SubjectLocY = 50;
private int Length1LocX = 40;
private int Length1LocY = 150;
private int Length2LocX = 330;
private int Length2LocY = 150;
private int t = 0;
public Gui (){
super("Converter");
setLayout(null);
System.out.println("yes");
for (int i = 0; i<8; i++) {
Subject[i] = new JButton(SubjNames[i]);
Subject[i].setLocation(SubjectLocX,SubjectLocY);
Subject[i].setSize(200,50);
add(Subject[i]);
if (i < 3) {
SubjectLocX = 40;
SubjectLocY += 100;
} else if (i == 3) {
SubjectLocX = 330;
SubjectLocY = 50;
} else if (i > 3) {
SubjectLocY += 100;
}
}
HandlerClass handler = new HandlerClass();
for (int i = 0; i<8; i++) {
Subject[i].addActionListener(handler);
}
for (int i = 0; i<8; i++) {
Length1[i] = new JButton(SubjNames[i]);
Length2[i] = new JButton(SubjNames[i]);
}
for (int i = 0; i<8; i++) {
Length1[i].addActionListener(handler);
Length2[i].addActionListener(handler);
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600,500);
setLocation(400,200);
setVisible(true);
}
public void Step2() {
for (int i = 0; i<8; i++) {
remove(Subject[i]);
}
for (int i = 0; i<8; i++) {
remove(Length1[i]);
remove(Length2[i]);
}
HandlerClass handler = new HandlerClass();
convertedFrom = new JTextField(from, 20);
convertedFrom.setEditable(false);
convertedFrom.setLocation(40,50);
convertedFrom.setSize(200,30);
add(convertedFrom);
convertedTo = new JTextField(CTo, 20);
convertedTo.setEditable(false);
convertedTo.setLocation(330,50);
convertedTo.setSize(200,30);
add(convertedTo);
amountFrom = new JTextField("amount", 20);
amountFrom.setLocation(40,100);
amountFrom.setSize(200,30);
add(amountFrom);
amountTo = new JTextField(ATo, 20);
amountTo.setEditable(false);
amountTo.setLocation(330,100);
amountTo.setSize(200,30);
add(amountTo);
for (int i = 0; i<8; i++) {
Length1[i].setLocation(Length1LocX, Length1LocY);
Length1[i].setSize(90, 50);
add(Length1[i]);
if (i < 3) {
Length1LocX = 40;
Length1LocY += 100;
} else if (i == 3) {
Length1LocX = 150;
Length1LocY = 150;
} else if (i > 3) {
Length1LocY += 100;
}
Length2[i].setLocation(Length2LocX, Length2LocY);
Length2[i].setSize(90, 50);
add(Length2[i]);
if (i < 3) {
Length2LocX = 330;
Length2LocY += 100;
} else if (i == 3) {
Length2LocX = 440;
Length2LocY = 150;
} else if (i > 3) {
Length2LocY += 100;
}
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600,600);
setLocation(400,200);
setVisible(true);
}
private class HandlerClass implements ActionListener {
public void actionPerformed(ActionEvent event) {
for (int i = 0; i<8; i++) {
if (event.getSource() == Length1[i]) {
from = event.getActionCommand();
}
if (event.getSource() == Length2[i]) {
CTo = event.getActionCommand();
}
}
Step2();
}
}
}`
(Note: I didn't include imports or main method in code above, but is in real program). The constructor creates the JButtons and actionlisteners. The step2() method is where the Buttons size and location and window is created and recreated. (Length1 and Length2 JButtons are what is messing up here). I don't know why half the buttons stop working after the second time though.

When you select one of the 16 buttons, method Step2() will be called again and this will relocate your buttons, without resetting your locationvalues. When you reset the locationvariables in the Step2() method, the buttons will work. Like this:
step2()
Length1LocX = 40;
Length1LocY = 150;
Length2LocX = 330;
Length2LocY = 150;
[rest of method....]
But off course you don't want to call step2() every time a button is clicked.....

You are creating and adding JTextField UI items, and adding them multiple times at the same location, and never removing them:
convertedFrom
amountFrom
convertedTo
amountTo
These will be stacked on top or underneath previous ones; the user may add text to the top ones and the program may write to or read from the obscured ones beneath, which will stop the program from functioning as intended.

Related

How to add multiple rectangles to a jframe(trying to code 2048 in an easy way)

I made the game already and wanted to make my GUI look better with rectangles not with jlabels and now I´ve come to realize that only the last rectangle that is drawn is shown on the GUI
I already tried it with different layouts
my GUI class:
public class GUI_N
{
private Spiel spiel;
private KeyEvent e;
private String beste;
private int beste1;
private DrawingComponent[][] feld;
GUI_N(){
feld = new DrawingComponent[4][4];
spiel = new Spiel();
beste1 = 0;
beste = "Highscore: "+beste1;
JFrame g=new JFrame("2048 - Main");
g.setSize(500,500);
g.setFocusable(true); //wichtig für KeyListener
g.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int i = 0;
int j = 0;
int h = 0;
int l = 0;
while(i<4)
{
while(j<4)
{
if(i==0){
h = 50;
}else if(i==1){
h = 100;
}else if(i==2){
h = 150;
}else if(i==3){
h = 200;
}
if(j==0){
l = 50;
}else if(j==1){
l = 100;
}else if(j==2){
l = 150;
}else if(j==3){
l = 200;
}
feld[i][j] = new DrawingComponent(l,h,50,50);
feld[i][j].setBounds(l,h,50,50);
j++;
}
j=0;
i++;
}
i = 0;
j = 0;
while(i<4)
{
while(j<4)
{
g.add(feld[i][j]);
j++;
}
j=0;
i++;
}
//g.getContentPane().setBackground(new Color(20, 40, 50));
g.setVisible(true);
}
public static void main(String[] args) {
new GUI_N();
}
}
my rectangle class:
public class DrawingComponent extends JComponent
{
private Graphics2D g2;
private int wert;
private int x;
private int y;
private int w;
private int h;
public DrawingComponent(int px,int py,int pw,int ph)
{
x=px;
y=py;
w=pw;
h=ph;
}
public void paintComponent(Graphics g)
{
g2 = (Graphics2D) g;
Rectangle rect1 = new Rectangle(x,y,w,h);
g2.setColor(Color.RED);
g2.fill(rect1);
}
public void setWert(int x)
{
wert = x;
}
public int getWert()
{
return wert;
}
}
as I said only the last drawn rectangle is shown.
How do I achieve this?
Right now you're adding the rectangles directly to your frame. You should have a JPanel layer in between, to which you can give a LayoutManager (GridLayout would be a good one to look at) to arrange all your rectangles.
So you would have something like this:
JFrame g = new JFrame("2048 - Main");
// GridLayout (on next line) takes number of rows and columns
JPanel panel = new JPanel(new GridLayout(4, 4));
// ... add all the rectangles to the panel here
g.add(panel);
And then you would add your rectangles to the panel, not the frame. As you add them, they will automatically go into place in the grid.
panel.add(feld[i][j]);
Also, if you use GridLayout, it will resize and fit the components to the grid dynamically, so it may save you some code as well, since you wouldn't need to hardcode their sizes in the GUI class.

JFrame defined in one class, JComponent extended in another

Relatively new to Java, coding for a school project.
I'm using JFrame and JComponent, drawing patterns and strings and all that fun stuff.
Currently, I have a class written that extends JComponent. This is the class where I am defining most of my shapes. The issue is that I initialized my Jframe
(Code: JFrame myFrame = new JFrame() ) in the main of one class, but I need to access myFrame.getWidth() in the JComponent class that I'm working in.
How can I access variables getWidth() and getHeight() in "public class MyJComponent extends JComponent" , when I defined myFrame in 'public class Lab2' ??
Edit for code:
public class Lab2 {
public static void main(String[] args) {
System.out.println("Hello Java");
JFrame myFrame = new JFrame();
myFrame.setSize(500, 500);
myFrame.setTitle("Color Test");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyJComponent myComponent = new MyJComponent(500, 500);
myFrame.add(myComponent);
myFrame.getContentPane().setBackground(Color.white); //sets background color.
myFrame.setVisible(true); // setVisible() *after* add() is the norm
//Deciding geometry of hidden shape. paintComponent is called once per run, this is called afterwards.
}
}
/**/
public class MyJComponent extends JComponent {
int[] circleX;
int[] circleY;
int[] circleR;
final int MIN_RADIUS = 5;
final int MAX_RADIUS = 15;
final int MIN_SEPARATION = 1;
final int MAX_ATTEMPTS = 5000;
final int MAX_CIRCLES = 1000;
Random rand;
int initialWidth;
int initialHeight;
int numCircles; // actual number of circles drawn
// are circles at index i and index j separated by *<= tolerance* pixels?
boolean twoCirclesOverlap(int i, int j, int tolerance) {
double distanceBetweenCenters =
Math.sqrt((circleX[i] - circleX[j]) * (circleX[i] - circleX[j]) +
(circleY[i] - circleY[j]) * (circleY[i] - circleY[j]));
return (distanceBetweenCenters <= (circleR[i] + circleR[j] + tolerance));
}
// are any existing circles separated from the proposed one at index i by *<= tolerance* pixels?
boolean anyCirclesOverlap(int i, int tolerance) {
for (int j = 0; j < i; j++) {
if (twoCirclesOverlap(i, j, tolerance)) {
return true;
}
}
return false;
}
// attempt to randomly place the largest-possible circle that does not overlap any existing one
boolean tryToPlaceCircle(int i) {
for (int j = 0; j < MAX_ATTEMPTS; j++) {
// pick a random position, set initial radius to minimum
circleX[i] = rand.nextInt(initialWidth);
circleY[i] = rand.nextInt(initialHeight);
circleR[i] = MIN_RADIUS;
// grow circle until it touches another or reaches max size
while (!anyCirclesOverlap(i, MIN_SEPARATION) && circleR[i] < MAX_RADIUS)
circleR[i]++;
// it was touching from the start -- must try again
if (circleR[i] == MIN_RADIUS) {
continue;
}
// grew to max size -- well done
else if (circleR[i] == MAX_RADIUS) {
return true;
}
// grew some, but then touched
else {
circleR[i]--; // retract to the step before touch
return true;
}
}
// all attempts failed
return false;
}
MyJComponent(int width, int height) {
circleX = new int[MAX_CIRCLES];
circleY = new int[MAX_CIRCLES];
circleR = new int[MAX_CIRCLES];
initialWidth = width;
initialHeight = height;
rand = new Random();
numCircles = 0;
while (numCircles < MAX_CIRCLES && tryToPlaceCircle(numCircles)) {
numCircles++;
}
}
//Override paintComponent
public void paintComponent(Graphics g) {
for (int i = 0; i < numCircles; i++) {
g.drawOval(circleX[i] - circleR[i], circleY[i] - circleR[i], 2 * circleR[i], 2 * circleR[i]);
}
}
//Shape decision
public void shapeDecision() {
double randomShapeDecider = Math.random();
if (randomShapeDecider > .50) {
//shape is circle, define it's properties
hiddenCircleDiameter = myFrame.getWidth();
}
else {
//shape is rectangle
hiddenRectangleWidth = myFrame.getWidth();
}
}
}

Double dimensional array with colours doesn't paint in paintComponent

I've been working on a dots look-a-like, but I'm having trouble painting the dots on the board. The array seems to work but it doesn't want to paint it.
Sorry, some of my variables are in Dutch but that shouldn't really pose too many confusion.
public class Bord extends JFrame{
Slang slang = new Slang();
Tile[][] tile = new Tile[6][6];
private JPanel menuPanel;
private JPanel gridPanel;
private JLabel levelTitel;
private JLabel levelNummer;
private JLabel scoreTitel;
private JLabel scoreNummer;
private JLabel targetTitel;
private JLabel targetNummer;
private JLabel timeTitel;
private JLabel timeNummer;
private JLabel pauzeKnop;
public Bord() {
super("Dots");
//setLocationRelativeTo(this);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
maakAttributen();
maakListeners();
maakLayout();
pack();
setSize(650, 750);
setVisible(true);
getContentPane();
repaint();
//TODO automatic size
}
public void maakAttributen() {
levelTitel = new JLabel("level");
levelNummer = new JLabel("1");
scoreTitel = new JLabel("score");
scoreNummer = new JLabel("2");
targetTitel = new JLabel("target");
targetNummer = new JLabel("3");
timeTitel = new JLabel("time");
timeNummer = new JLabel("4");
//TODO image in knop zetten
pauzeKnop = new JLabel("PAUZE");
}
public void maakListeners() {
}
public void maakLayout() {
JPanel menuPanel = new JPanel(new GridLayout(0, 5, 5, 5));
JPanel gridPanel = new JPanel(new GridLayout(0, 7, 5, 5));
add(menuPanel, BorderLayout.PAGE_START);
add(gridPanel, BorderLayout.CENTER);
//menu attributen aan menu toevoegen
menuPanel.add(levelTitel);
menuPanel.add(scoreTitel);
menuPanel.add(targetTitel);
menuPanel.add(timeTitel);
menuPanel.add(pauzeKnop);
menuPanel.add(levelNummer);
menuPanel.add(scoreNummer);
menuPanel.add(targetNummer);
menuPanel.add(timeNummer);
//grid met dots toevoegen
for (int x = 0; x < 6; x++) {
for (int y = 0; y < 6; y++) {
RandomKleur kleur = new RandomKleur();
tile[x][y] = new Tile(kleur.getKleur());
gridPanel.add(new myDots());
}
}
}
private class myDots extends JPanel {
#Override
protected void paintComponent(Graphics g) {
int h = getHeight();
int w = getWidth();
super.paintComponent(g);
for (int x = 0; x < 6; x++) {
for (int y =0; y < 6; y++) {
g.setColor(tile[x][y].getKleur());
g.fillOval(h / 2, w / 2, 33, 33);
}
}
}
}
}
I've tried debugging it and it gives some kind of null pointer exception sometimes.
You basic painting logic is wrong. You are adding 36 Dot panels to the frame, but then in the painting logic you are repainting all 36 dots on top of one another so only the last dot painted will display. The paintComponent() method should only be painting a single dot.
You need to change your MyDots class to accept a Tile as a parameter and then save the Tile object as an instance variable of the class. Then the code would be something like:
for (int x = 0; x < 6; x++) {
for (int y = 0; y < 6; y++) {
RandomKleur kleur = new RandomKleur();
tile[x][y] = new Tile(kleur.getKleur());
//gridPanel.add(new myDots());
gridPanel.add(new myDots(tile[x][y]));
}
}
I don't know if you even need the tile array, because now the MyDots class has the tile information.
Then Your painting logic should be something like:
//for (int x = 0; x < 6; x++) {
//for (int y =0; y < 6; y++) {
//g.setColor(tile[x][y].getKleur());
g.setColor(tile.getKleur()); // where "tile" is the instance variable
g.fillOval(h / 2, w / 2, 33, 33);
//}
//}
Who knows why you get the NPE, because the exception is not related to the code you posted.
By the way class name should start with an upper case character. It should be "MyDot".
Edit:
Do I have to create a new method in MyDots?
You need to create a constructor for your class:
public class MyDots
{
private Tile tile;
public MyDots(Tile tile)
{
this.tile = tile;
}
#Override
protectect paintComponent(Graphics g)
...
}

2d icon arrays JAVA and printing out in JOptionpane box

How would I create a 2d icon array and print it out in a JOptionPane box. so Far I have this, but when I print it out it shows a bunch of BlockEmpty.png
public class iconarray{
public static void main (String [] args)
{
Icon blockempty = new ImageIcon("BlockEmpty.png");
Icon Board [] [] = new Icon [8] [8];
String GameBoard = "";
for (int count2 = 2; count2 <= 7; count2++)
{
for (int count3 = 1; count3 <= 7; count3++)
{
Board[count2][count3] = blockempty;
}
}
for (int count2 = 2; count2 <= 7; count2++)
{
for (int count3 = 1; count3 <= 7; count3++)
{
GameBoard = GameBoard + Board[count2][count3];
}
GameBoard = GameBoard + "\n";
}
JOptionPane.showMessageDialog(null, "", "Connect 4", JOptionPane.PLAIN_MESSAGE, blockempty);
}
}
In order to display a Icon or Image, you first need some way to render it. Icons and Images don't have the means to render them selves (per se), but require another component that can render them.
Something else a lot of people forget, is JOptionPane is capable of display components.
For example:
Icon brick = new ImageIcon(BoardOption.class.getResource("/images.jpg"));
JPanel wall = new JPanel(new GridLayout(8, 8, 0, 0));
JLabel bricks[][] = new JLabel[8][8];
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
bricks[y][x] = new JLabel(brick);
wall.add(bricks[y][x]);
}
}
JOptionPane.showMessageDialog(null, wall, "Another brick in the wall", JOptionPane.PLAIN_MESSAGE, null);
Take a look at How to use icons for more details.

ActionListener: Disabling Buttons

I am currently working on a Java class that produces a simple JFrame/JButton layout of Tic-Tac-Toe. Implementing ActionListener, I intended on having the selected JButton set its title to "X" or "O" (based on a boolean statement of whether or not it is X's turn to pick a JButton) and become disabled (so it cannot be played on top of in following turns). The current application I have created does this, but it will sometimes not change the JButton text or disable the button until I click another button. There does not seem to be any kind of cohesive order at which this happens when I click one of the JButtons. I have spent hours trying to fix this issue with no avail. Is there an issue with how I coded my actionPerformed method or how I added it to my JButtons?
Here is the code to my class:
import javax.swing.*;
import java.awt.event.*;
import javax.swing.*;
public class TTT extends JFrame implements ActionListener{
// private fields
private JButton[] buttonArray;
private JLabel prompt;
private boolean turnX;
private String letter;
public TTT() {
// Instantiates JFrame window and adds lines to board
super.setSize(235, 280);
super.setTitle("Tic-Tac-Toe");
// Instantiates JButton array
buttonArray = new JButton[9];
// Loop that creates the JButton squares
for(int y = 30; y <= 140; y += 55) {
for(int x = 30; x <= 140; x += 55) {
for(int index = 0; index < buttonArray.length; index++) {
buttonArray[index] = new JButton();
buttonArray[index].setSize(50, 50);
buttonArray[index].setLocation(x, y);
buttonArray[index].addActionListener(this);
super.add(buttonArray[index]);
}
}
}
prompt = new javax.swing.JLabel("X's TURN");
prompt.setVerticalAlignment(JLabel.BOTTOM);
super.add(prompt);
turnX = true;
super.setVisible(true);
}
public void actionPerformed(java.awt.event.ActionEvent a) {
// Calculate whose turn it is
if(turnX){
letter = "X";
prompt.setText("O's TURN");
turnX = false;
} else if(!turnX){
letter = "O";
prompt.setText("X's TURN");
turnX = true;
}
JButton pressedButton = (JButton)a.getSource();
pressedButton.setText(letter);
pressedButton.setEnabled(false);
super.repaint();
}
public static void main(String[] args) {
new TTT();
}
}
With this code:
for(int y = 30; y <= 140; y += 55) {
for(int x = 30; x <= 140; x += 55) {
for(int index = 0; index < buttonArray.length; index++) {
You are adding 82(!) JButtons (one on top of the other in groups of 9). So, what was actually happening was that one was changed (disabled etc), but on calling repaint, the order of painting them might change, so the one whose ActionListener was triggered was painted underneath one of the 8 that were still enabled and blank.
You can correct it like this:
...
int index = 0; // <-- Add this line
for(int y = 30; y <= 140; y += 55) {
for(int x = 30; x <= 140; x += 55) {
// <-- remove the third for-loop
buttonArray[index] = new JButton();
buttonArray[index].setSize(50, 50);
buttonArray[index].setLocation(x, y);
buttonArray[index].addActionListener(this);
super.add(buttonArray[index]);
index++; // <-- increment 'index'
}
}
...
You could also remove the super.repaint() line, since it is redundant.
Not directly related to your problem, but Swing related stuff should (for various reasons) be called from the Event Dispatching Thread (EDT). One way to achieve this, is by using SwingUtilities.invokeLater(), so it might be a good idea to replace new TTT(); with this:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TTT();
}
});

Categories

Resources