Java repaint() not working when called from a different class - java

My repaint works when called in the same class but not from another class. I haven't been able to find this issue elsewhere. I have put my code below. Thank you! The code is for making a calculator in a JFrame with 2 JPanels, one showing the user's input and one with all the buttons. I want to call repaint so the drawString() method changes as the user enters their input.
public class Calculator
{
public static void main(String[] args)
{
Calculator c = new Calculator();
}
public Calculator()
{
JFrame frame = new JFrame("Calculator");
frame.setSize(800, 800);
frame.setResizable(false);
Buttons b = new Buttons();
Display d = new Display();
frame.setLayout(new GridLayout(2, 1));
frame.add(d);
frame.add(b);
frame.setVisible(true);
}
public class Buttons extends JPanel implements ActionListener
{
private int z;
public JButton[] buttons;
public Display d;`enter code here`
public String[] values;
public String clickedButton;
public Buttons()
{
setBackground(Color.BLACK);
setLayout(new GridLayout(5, 4));
values = new String[100];
for(int i = 0; i < values.length; i++)
{
values[i] = new String("");
}
addButtons();
}
public void addButtons()
{
Font courier = new Font("Courier", Font.BOLD, 20);
buttons = new JButton[20];
for(int i = 0; i < buttons.length; i++)
{
buttons[i] = new JButton(Integer.toString(i));
buttons[i].setBackground(Color.BLUE);
buttons[i].setForeground(Color.WHITE);
buttons[i].setFont(courier);
buttons[i].setFocusable(false);
buttons[i].addActionListener(this);
buttons[i].setBorder(BorderFactory.createLineBorder(new Color(0, 100, 175, 255)));
add(buttons[i]);
}
buttons[10].setVisible(false);
buttons[10].setEnabled(false);
buttons[11].setVisible(false);
buttons[11].setEnabled(false);
buttons[12].setText("C");
buttons[13].setText("+");
buttons[14].setText("-");
buttons[15].setText("*");
buttons[16].setText("/");
buttons[17].setText("+/-");
buttons[18].setText("^");
buttons[19].setText("=");
}
public void actionPerformed(ActionEvent e)
{
String action = e.getActionCommand();
d = new Display();
for(int i = 0; i < 10; i++)
{
if(action.equals(Integer.toString(i)))
{
values[d.i]+=Integer.toString(i);
System.out.println("should be repainting");
d.repaint();
}
}
}
}
public class Display extends JPanel
{
public Buttons b;
public Font courier;
public int i;
public Display()
{
i = 0;
b = new Buttons();
setBackground(Color.BLACK);
courier = new Font("Courier", Font.BOLD, 50);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
g.setFont(courier);
g.drawString(b.values[i], 50, 50);
repaint();
}
}
}

You seem to be creating a new Display every time and telling that to repaint instead of the real one. Move your Display d variable into the Calculator class as a field, and don't declare new ones.
You create the original Display object as a local variable so it can't be accessed from elsewhere, so make this part use the class field instead:
Display d = new Display();
Also, this line in actionPerformed is creating a new instance and should be removed:
d = new Display();

Don't call repaint from within a paint method. This will cause the API to schedule anther paint request, which will eventually consume all your CPU cycles
You actually have two instances of Display, one which is on the screen, one which is not
While there are a few ways to fix this, one of the simpler would be to simply pass the instance of Display created to in Calculators constructor to Buttons, for example...
public class Calculator {
public static void main(String[] args) {
Calculator c = new Calculator();
}
public Calculator() {
JFrame frame = new JFrame("Calculator");
frame.setSize(800, 800);
frame.setResizable(false);
Display d = new Display();
Buttons b = new Buttons(d);
frame.setLayout(new GridLayout(2, 1));
frame.add(d);
frame.add(b);
frame.setVisible(true);
}
public class Buttons extends JPanel implements ActionListener {
private int z;
private JButton[] buttons;
private String[] values;
private String clickedButton;
private Display d;
public Buttons(Display d) {
this.d = d;
setBackground(Color.BLACK);
setLayout(new GridLayout(5, 4));
values = new String[100];
for (int i = 0; i < values.length; i++) {
values[i] = new String("");
}
addButtons();
}
Then buttons can use that instance to display what ever it needs to display
private int index = 0;
public void actionPerformed(ActionEvent e) {
String action = e.getActionCommand();
for (int i = 0; i < 10; i++) {
if (action.equals(Integer.toString(i))) {
values[index] += Integer.toString(i);
d.setValue(values[index]);
index++;
}
}
}
}
public class Display extends JPanel {
public Font courier;
private String value;
public Display() {
setBackground(Color.BLACK);
courier = new Font("Courier", Font.BOLD, 50);
}
public void setValue(String value) {
this.value = value;
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.setFont(courier);
if (value != null) {
g.drawString(value, 50, 50);
}
}
}
}

Related

How can I enable/disable a JTextField with a JCheckBox? or what's wrong with my code?

I'm newbie in programming java, I have an array of JCheckBox next to an array of JTextfield.
I need to make a CheckBox Deactivate a JTextField when it's checked, but I don't have success in this
How can I make it works with actionlisteners?
This is my code:
public class Checklist_Complete extends JFrame {
private JLabel description;
private JButton send;
private JTextField text[]=new JTextField[10];
private JCheckBox cb[]=new JCheckBox[10];
public Checklist_Complete() {
setTitle("Activities");
setSize(500,300);
setupWidgets();
setVisible(true);
}
private void setupWidgets() {
JPanel pn_center = new JPanel(new GridLayout(10,1));
JPanel pn_west = new JPanel(new GridLayout(10,1));
description = new JLabel("List your activities and uncheck the irrelevant ones");
send = new JButton("Send Checklist");
for (int i=0; i<10; i++) {
text[i] = new JTextField();
cb[i] = new JCheckBox("", true);
}
add(description, BorderLayout.NORTH);
add(pn_center, BorderLayout.CENTER);
add(pn_west, BorderLayout.WEST);
add(send, BorderLayout.SOUTH);
for (int i=0; i<10; i++){
pn_center.add(text[i]);
pn_west.add(cb[i]);
}
}
private void setupEvents() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
for (int i=0; i<10; i++) {
cb[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
if(cb[i].isSelected()){
text[i].setEnabled(false);
} else{
text[i].setEnabled(true);
}
}
});
}
}
public static void main(String[] args) {
new Checklist_Complete();
}
}
Here is a quick solution with an ItemListener.
private void setupEvents() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
for (int i=0; i<10; i++) {
final int finalI = i;
cb[i].addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
text[finalI].setEnabled(e.getStateChange() == ItemEvent.SELECTED);
}
});
}
}
You can also do it with an ActionListener but the solution is a bit of a hack, and it is not as elegant. I am posting this because you can solve your issue like this also:
private void setupEvents() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
for (int i=0; i<10; i++) {
final int finalI = i;
cb[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
text[finalI].setEnabled(!text[finalI].isEnabled() && e.getID() == ActionEvent.ACTION_PERFORMED);
}
});
}
}
Problems:
You never call setupEvents() and so the code in this method is never called
You will need to make local fields final if you want to use them within an inner anonymous class.
So:
private void setupEvents() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
for (int i=0; i<10; i++) {
final int finalIndex = i;
cb[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
if(cb[finalIndex].isSelected()){
text[finalIndex].setEnabled(false);
} else{
text[finalIndex].setEnabled(true);
}
}
});
}
}
I would do things a little differently, and to my eye cleaner. e.g.,
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class CheckList2 extends JPanel {
public static final int TEXT_FIELD_COUNT = 10;
private List<JTextField> fields = new ArrayList<>();
private JButton sendBtn = new JButton(new SendAction("Send Checklist"));
public CheckList2() {
JPanel checkPanel = new JPanel();
checkPanel.setLayout(new GridLayout(0, 1, 1, 1));
for (int i = 0; i < TEXT_FIELD_COUNT; i++) {
JCheckBox checkBox = new JCheckBox("", true);
// final so can use within item listener
final JTextField textField = new JTextField(20);
textField.setEnabled(false);
fields.add(textField);
checkBox.addItemListener(itemEvent -> {
// set textfield enabled based on checkbox state
textField.setEnabled(itemEvent.getStateChange() == ItemEvent.DESELECTED);
});
JPanel rowPanel = new JPanel();
rowPanel.add(checkBox);
rowPanel.add(Box.createHorizontalStrut(3));
rowPanel.add(textField);
checkPanel.add(rowPanel);
}
setLayout(new BorderLayout());
add(checkPanel, BorderLayout.CENTER);
add(sendBtn, BorderLayout.PAGE_END);
}
private class SendAction extends AbstractAction {
public SendAction(String name) {
super(name);
int mnemonic = name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
for (JTextField jTextField : fields) {
System.out.println(jTextField.getText());
}
System.out.println();
}
}
private static void createAndShowGui() {
CheckList2 mainPanel = new CheckList2();
JFrame frame = new JFrame("CheckList2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

need help accessing variable inside inner class for loop

I am having problem accessing the variable int i inside the inner class
Code:
public class OnColumnSelectPanel {
JFrame jFrame;
JPanel mainJPanel;
//JPanel jPanel1;
//JTextField jTextField;
//JButton jButton;
//JComboBox jComboBox [];
MigLayout layout;
MigLayout frameLayout;
//column names
ColumnNames cn = new ColumnNames();
List<String> listedColumnNames = cn.getColumnNames();
String columnNames[] = listedColumnNames.toArray(new String[0]);
public OnColumnSelectPanel(int n) {
//jPanel1 = new JPanel();
jFrame = new JFrame("Create Structure of Columns");
// mainJPanel = new JPanel();
layout = new MigLayout("flowy", "[center]rel[grow]", "[]10[]");
frameLayout = new MigLayout("flowx", "[center]rel[grow]", "[]10[]");
//mainJPanel.setLayout(new BoxLayout(mainJPanel, BoxLayout.X_AXIS));
//MigLayout mainJPanelLayout = new MigLayout("flowy", "[]rel[grow]", "[]5[]");
// declare & initialize array
JPanel jPanel[] = new JPanel[n];
JComboBox jComboBox[] = new JComboBox[n];
JButton jButton[] = new JButton[n];
final int num = 0;
for (int i = 0; i < n; i++) {
//assign array
jComboBox[i] = new JComboBox(columnNames);
jButton[i] = new JButton("add Sub Heading");
jPanel[i] = new JPanel();
System.out.println("Loop number: " + i);
jButton[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
for (int j = 0; j < n; j++) {
if (j <= n) {
jComboBox[j] = new JComboBox(columnNames);
jPanel[j].add(jComboBox[j]);
jFrame.revalidate();
} else {
JOptionPane.showMessageDialog(null, "You have exceeded your limit");
}
}
}
});
//set layout
jPanel[i].setLayout(layout);
//jPanel[i].setPreferredSize(new Dimension(50, 400));
//mainJPanel.setLayout(mainJPanelLayout);
jFrame.setLayout(frameLayout);
System.out.println(" height " + jPanel[i].getHeight());
jPanel[i].add(jComboBox[i], new CC().newline());
//jPanel.add(jTextField);
jPanel[i].add(jButton[i]);
//mainJPanel.add(jPanel[i], "spany");
jPanel[i].repaint();
jFrame.add(jPanel[i]);
jFrame.pack();
jPanel[i].revalidate();
jFrame.revalidate();
//mainJPanel.revalidate();
//jFrame.revalidate();
}
//mainJPanel.setSize(600, 400);
//jFrame.add(jPanel1);
jFrame.setVisible(true);
jFrame.setSize(600, 400);
jFrame.setAlwaysOnTop(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Output Frame
As you can see the output image. The problem here is that when i click on the add subheading button, combobox is added to every jpanel. this is because i can;t pass the value i to the inner class.
It would be interesting to know possible solutions for this.
FYI I am using Mig Layout.
Thanks in advance.
Only effectively final variables can be accessed from anonymous classes.
i is modified by the loop, so it is not effectively final.
A workaround would look like this:
for (int i = 0; i < n; i++) {
...
final int effectivelyFinal = i;
jButton[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
...
// use effectivelyFinal instead of i
});
}
But as other suggested, it would be way better to extract the anonymous class into a real class and pass all required parameters using the constructor. This can look like this:
class MyListener implements ActionListener {
private final int index;
// add more fields for other required parameters
public MyListener(int index) {
this.index = index;
}
#Override
public void actionPerformed(ActionEvent e) {
// use index
}
}
Usage:
jButton[i].addActionListener(new MyListener(i));

Why do the panels disappear when i press UP?

This is my code for a game im making. At the moment im not worried about how the game functions I've been more so worried about the fact that each time I hit the UP button the panels disappear and sometimes when i hit the LEFT button as well. Is there an explanation to this can anyone help me understand why this happens?? I have a feeling it has something to do with my if statements but im not really sure. also, im messing around with the key listener and if you could give me some advice on key listeners like some dos and donts I really appreciate the help!!
import javax.swing.*;
import java.applet.*;
import java.awt.event.*;
import java.awt.*;
public class Game extends Applet implements ActionListener,KeyListener {
Image image;
MediaTracker tr;
JLabel label,computerLabel;
JPanel panel,computerPanel;
Button start,up,down;
Label result;
Dimension SIZE = new Dimension(50,50);
int x = 0;
int y = 0;
int w = 100;
int q = 100;
int WIDTH = 50;
int HEIGHT = 50;
//Player Integers
int zeroPosX,zeroPosY,xLeft,xUp;
//Computer integers
int compZeroPosX,compZeroPosY,compXLeft,compXUp;
//--------------------------------------
public void init() {
setLayout(new FlowLayout());
start = new Button("Start");
up = new Button("UP");
down = new Button("LEFT");
//PlayerPiece stuff
ImageIcon icon = new ImageIcon("playerpiece.png");
label = new JLabel(icon);
panel = new JPanel();
label.setVisible(true);
panel.add(label);
panel.setPreferredSize(SIZE);
//ComputerPiece Stuff
ImageIcon computerIcon = new ImageIcon("computerPiece.png");
computerPanel = new JPanel();
computerLabel = new JLabel(computerIcon);
computerLabel.setVisible(true);
computerPanel.add(computerLabel);
computerPanel.setPreferredSize(SIZE);
//===============================================
result = new Label("=========");
addKeyListener(this);
setSize(650,650);
up.addActionListener(this);
down.addActionListener(this);
start.addActionListener(this);
label.setSize(WIDTH,HEIGHT);
label.setLocation(0,0);
add(computerPanel);
add(panel);
add(start);
add(up);
add(down);
add(result);
}
//--------------------------------------
public void paint(Graphics g) {
Graphics2D firstLayer = (Graphics2D)g;
Graphics2D secondLayer = (Graphics2D)g;
Graphics2D thirdLayer = (Graphics2D)g;
secondLayer.setColor(Color.BLACK);
for(x=100; x<=500; x+=100)
for(y=100; y <=500; y+=100)
{
firstLayer.fillRect(x,y,WIDTH,HEIGHT);
}
for(w=150; w<=500; w+=100)
for(q=150; q <=500; q+=100)
{
secondLayer.fillRect(w,q,WIDTH,HEIGHT);
}
}
//--------------------------------------
public void actionPerformed(ActionEvent ae) {
int [] range = {50,0,0,0,0};
int selection = (int)Math.random()*5 ;
//~~~~~~~~~~~~~~~~~~~~~~~~~
//PlayerPositioning
zeroPosX = panel.getX();
zeroPosY = panel.getY();
xLeft = zeroPosX - 50;
xUp = zeroPosY - 50;
//ComputerPositioning
compZeroPosX = computerPanel.getX();
compZeroPosY = computerPanel.getY();
compXLeft = compZeroPosX - range[selection];
compXUp = compZeroPosY - range[selection];
//~~~~~~~~~~~~~~~~~~~~~~~~~~
Button user = (Button)ae.getSource();
//Starting the game
if(user.getLabel() == "Start") {
result.setText("=========");
//playersetup
label.setLocation(0,0);
panel.setLocation(300,500);
//============================
//npc setup
computerLabel.setLocation(0,0);
computerPanel.setLocation(500,300);
}
if(compZeroPosX >= 150) {
if(compZeroPosY >= 150) {
if(zeroPosX >= 150) {
if(zeroPosY >=150) {
if(user.getLabel() == "UP") {
panel.setLocation(zeroPosX,xUp);
}
else
computerPanel.setLocation(compZeroPosX,compXUp);
if(user.getLabel() == "LEFT") {
panel.setLocation(xLeft,zeroPosY);
}
else
computerPanel.setLocation(compXLeft,compZeroPosY);
if(panel.getX() < 150)
result.setText("GAME-OVER");
if(panel.getY() < 150)
result.setText("GAME-OVER");
}
}
}
}
}
#Override
public void keyPressed(KeyEvent kp) {
int keycode = kp.getKeyCode();
switch (keycode) {
case KeyEvent.VK_W:
panel.setLocation(xLeft,zeroPosY);
break;
}
}
#Override
public void keyReleased(KeyEvent kr) {
}
#Override
public void keyTyped(KeyEvent kt) {
}
}
Issues and suggestions:
You're mixing AWT (e.g., Applet, Button, Label) with Swing (e.g., JPanel, JLabel) dangerously and without need. Stick with Swing and get rid of all vestiges of AWT.
You're painting directly in a top-level window, here the Applet, a dangerous thing to do. Don't. Follow the Swing graphics tutorials and do your drawing in a JPanel's paintComponent method.
You're not calling the super method within your painting method override, another dangerous thing to do, and another indication that you're trying to do this without reading the important relevant tutorials.
Don't compare Strings using == or !=. Use the equals(...) or the equalsIgnoreCase(...) method instead. Understand that == checks if the two object references are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here.
You're trying to directly set the location of a component such as a JPanel without regard for the layout managers. Don't do this. Instead move logical (non-component) entities and display the movement in your graphics.
You can find links to the Swing tutorials and to other Swing resources here: Swing Info
Later we can talk why you should avoid applets of all flavors...
Myself, I'd move ImageIcons around a grid of JLabels and not directly use a painting method at all. For example,
To see, run the following code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class Game2 extends JPanel {
private static final String CPU_PATH = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4f/"
+ "Gorilla-thinclient.svg/50px-Gorilla-thinclient.svg.png";
private static final String PERSON_PATH = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d8/"
+ "Emblem-person-blue.svg/50px-Emblem-person-blue.svg.png";
private static final int SQR_WIDTH = 50;
private static final int SIDES = 10;
private static final Dimension SQR_SIZE = new Dimension(SQR_WIDTH, SQR_WIDTH);
private static final Color DARK = new Color(149, 69, 53);
private static final Color LIGHT = new Color(240, 220, 130);
private JLabel[][] labelGrid = new JLabel[SIDES][SIDES];
private Icon playerIcon;
private Icon computerIcon;
public Game2() throws IOException {
// would use images instead
playerIcon = createIcon(PERSON_PATH);
computerIcon = createIcon(CPU_PATH);
JPanel buttonPanel = new JPanel();
buttonPanel.add(new JButton(new StartAction("Start", KeyEvent.VK_S)));
buttonPanel.add(new JButton(new UpAction("Up", KeyEvent.VK_U)));
buttonPanel.add(new JButton(new LeftAction("Left", KeyEvent.VK_L)));
JPanel gameBrd = new JPanel(new GridLayout(SIDES, SIDES));
gameBrd.setBorder(BorderFactory.createLineBorder(Color.BLACK));
for (int i = 0; i < labelGrid.length; i++) {
for (int j = 0; j < labelGrid[i].length; j++) {
JLabel label = new JLabel();
label.setPreferredSize(SQR_SIZE);
label.setOpaque(true);
Color c = i % 2 == j % 2 ? DARK : LIGHT;
label.setBackground(c);
gameBrd.add(label);
labelGrid[i][j] = label;
}
}
setLayout(new BorderLayout());
add(buttonPanel, BorderLayout.PAGE_START);
add(gameBrd);
// random placement, just for example
labelGrid[4][4].setIcon(computerIcon);
labelGrid[5][5].setIcon(playerIcon);
}
private Icon createIcon(String path) throws IOException {
URL url = new URL(path);
BufferedImage img = ImageIO.read(url);
return new ImageIcon(img);
}
private abstract class MyAction extends AbstractAction {
public MyAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
}
private class StartAction extends MyAction {
public StartAction(String name, int mnemonic) {
super(name, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO start game code
}
}
// move all icons up
private class UpAction extends MyAction {
public UpAction(String name, int mnemonic) {
super(name, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
// collection to hold label that needs to be moved
Map<JLabel, Icon> labelMap = new HashMap<>();
for (int i = 0; i < labelGrid.length; i++) {
for (int j = 0; j < labelGrid[i].length; j++) {
Icon icon = labelGrid[i][j].getIcon();
if (icon != null) {
int newI = i == 0 ? labelGrid.length - 1 : i - 1;
labelGrid[i][j].setIcon(null);
labelMap.put(labelGrid[newI][j], icon);
}
}
}
// move the icon after the iteration complete so as not to move it twice
for (JLabel label : labelMap.keySet()) {
label.setIcon(labelMap.get(label));
}
}
}
// move all icons left
private class LeftAction extends MyAction {
public LeftAction(String name, int mnemonic) {
super(name, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
Map<JLabel, Icon> labelMap = new HashMap<>();
for (int i = 0; i < labelGrid.length; i++) {
for (int j = 0; j < labelGrid[i].length; j++) {
Icon icon = labelGrid[i][j].getIcon();
if (icon != null) {
int newJ = j == 0 ? labelGrid[i].length - 1 : j - 1;
labelGrid[i][j].setIcon(null);
labelMap.put(labelGrid[i][newJ], icon);
}
}
}
for (JLabel label : labelMap.keySet()) {
label.setIcon(labelMap.get(label));
}
}
}
private static void createAndShowGui() {
Game2 mainPanel = null;
try {
mainPanel = new Game2();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("Game2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}

Java - adding JButton array to JFrame

I am trying to add a 2D JButton array to a JFrame, I don't get any errors, just the JButtons don't show up.
Creating the JButtons:
public class TTTGrid {
private static JFrame frame;
private static int[][] coords;
private static int width, height;
public TTTGrid(JFrame frame,int[][] coords, int width, int height){
this.frame = frame;
this.coords = coords;
this.width = width;
this.height = height;
}
static JButton map[][] = new JButton[3][3];
public void Draw(){
for(int i = 0; i<coords.length; i++){
for(int j = 0; j<coords[i].length; j++){
map[i][j] = new JButton();
map[i][j].setBounds(i*100, j*100, width, height);
frame.add(map[i][j]);
}
}
}
}
Where the draw method is called:
public class TTTthread extends TTT implements Runnable {
int[][] map = new int[3][3];
TTTGrid grid = new TTTGrid(frame, map, 100, 100);
#Override
public void run() {
try {
while (true) {
grid.Draw();
Thread.sleep(20);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
If your code is running like I think it's running, you appear to be trying to add 9 JButtons to your GUI 50 times a second! That's a heck of a lot of buttons -- are you sure that this is what you want to be doing? Your code also runs far afoul of Swing threading rules by making Swing calls (a lot of Swing calls!) off of the Swing event thread.
Your main solution is likely to
Add your 9 JButtons to a JPanel that uses a GridLayout(3, 3)
Do this only once not 50 times a second
Then add that JPanel to your GUI, BorderLayout.CENTER and to be sure not to use null layouts.
Not try to set the bounds, size or locations of these JButtons, but rather to let the layout managers to the work
Get rid of that while loop and instead change your code to be more event-driven using Swing's event driven model.
Strive to use mostly non-static variables and methods so that your classes become true OOPS-compliant classes, allowing them to take advantage of the benefits of OOPS programming, including reducing program complexity and interconnectedness (reduce coupling).
For example
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;
public class MyTttFoo extends JPanel {
// it's OK for constants to be static
private static final long serialVersionUID = 1L;
private static final int ROWS = 3;
// use a larger Font to make buttons larger
private static final Font BTN_FONT = new Font(Font.SANS_SERIF, Font.BOLD, 60);
private static final String BLANK = " ";
private static final String X = "X";
private static final String O = "O";
// but not most variables
private JButton[][] buttonGrid = new JButton[ROWS][ROWS];
public MyTttFoo() {
setBackground(Color.black);
// use layout managers to help you create your GUI
setLayout(new GridLayout(ROWS, ROWS, 1, 1));
ActionListener btnListener = new ButtonListener();
// create your buttons and add them only **once**
for (int row = 0; row < buttonGrid.length; row++) {
for (int col = 0; col < buttonGrid[row].length; col++) {
JButton button = new JButton(BLANK);
button.setFont(BTN_FONT);
button.addActionListener(btnListener);
add(button); // add button to a gridlayout using component
buttonGrid[row][col] = button; // and assign into the array
}
}
}
private class ButtonListener implements ActionListener {
private boolean xTurn = true;
#Override
public void actionPerformed(ActionEvent e) {
AbstractButton btn = (AbstractButton) e.getSource();
String txt = btn.getText();
if (txt.equals(BLANK)) {
if (xTurn) {
btn.setText(X);
} else {
btn.setText(O);
}
xTurn = !xTurn;
}
}
}
private static void createAndShowGui() {
MyTttFoo mainPanel = new MyTttFoo();
JFrame frame = new JFrame("MyTttFoo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Update JLabel every X seconds from ArrayList<List> - Java

I have a simple Java program that reads in a text file, splits it by " " (spaces), displays the first word, waits 2 seconds, displays the next... etc... I would like to do this in Spring or some other GUI.
Any suggestions on how I can easily update the words with spring? Iterate through my list and somehow use setText();
I am not having any luck. I am using this method to print my words out in the consol and added the JFrame to it... Works great in the consol, but puts out endless jframe. I found most of it online.
private void printWords() {
for (int i = 0; i < words.size(); i++) {
//How many words?
//System.out.print(words.size());
//print each word on a new line...
Word w = words.get(i);
System.out.println(w.name);
//pause between each word.
try{
Thread.sleep(500);
}
catch(InterruptedException e){
e.printStackTrace();
}
JFrame frame = new JFrame("Run Text File");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel textLabel = new JLabel(w.name,SwingConstants.CENTER);
textLabel.setPreferredSize(new Dimension(300, 100));
frame.getContentPane().add(textLabel, BorderLayout.CENTER);
//Display the window. frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
}
I have a window that get's created with JFrame and JLable, however, I would like to have the static text be dynamic instead of loading a new spring window. I would like it to flash a word, disappear, flash a word disappear.
Any suggestions on how to update the JLabel? Something with repaint()? I am drawing a blank.
Thanks!
UPDATE:
With the help from the kind folks below, I have gotten it to print correctly to the console. Here is my Print Method:
private void printWords() {
final Timer timer = new Timer(500, null);
ActionListener listener = new ActionListener() {
private Iterator<Word> w = words.iterator();
#Override
public void actionPerformed(ActionEvent e) {
if (w.hasNext()) {
_textField.setText(w.next().getName());
//Prints to Console just Fine...
//System.out.println(w.next().getName());
}
else {
timer.stop();
}
}
};
timer.addActionListener(listener);
timer.start();
}
However, it isn't updating the lable? My contructor looks like:
public TimeThis() {
_textField = new JTextField(5);
_textField.setEditable(false);
_textField.setFont(new Font("sansserif", Font.PLAIN, 30));
JPanel content = new JPanel();
content.setLayout(new FlowLayout());
content.add(_textField);
this.setContentPane(content);
this.setTitle("Swing Timer");
this.pack();
this.setLocationRelativeTo(null);
this.setResizable(false);
//_textField.setText("loading...");
}
Getting there... I'll post the fix once I, or whomever assists me, get's it working. Thanks again!
First, build and display your GUI. Once the GUI is displayed, use a javax.swing.Timer to update the GUI every 500 millis:
final Timer timer = new Timer(500, null);
ActionListener listener = new ActionListsner() {
private Iterator<Word> it = words.iterator();
#Override
public void actionPerformed(ActionEvent e) {
if (it.hasNext()) {
label.setText(it.next().getName());
}
else {
timer.stop();
}
}
};
timer.addActionListener(listener);
timer.start();
Never use Thread.sleep(int) inside Swing Code, because it blocks the EDT; more here,
The result of using Thread.sleep(int) is this:
When Thread.sleep(int) ends
Example code:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import javax.swing.*;
//http://stackoverflow.com/questions/7943584/update-jlabel-every-x-seconds-from-arraylistlist-java
public class ButtonsIcon extends JFrame implements Runnable {
private static final long serialVersionUID = 1L;
private Queue<Icon> iconQueue = new LinkedList<Icon>();
private JLabel label = new JLabel();
private Random random = new Random();
private JPanel buttonPanel = new JPanel();
private JPanel labelPanel = new JPanel();
private Timer backTtimer;
private Timer labelTimer;
private JLabel one = new JLabel("one");
private JLabel two = new JLabel("two");
private JLabel three = new JLabel("three");
private final String[] petStrings = {"Bird", "Cat", "Dog",
"Rabbit", "Pig", "Fish", "Horse", "Cow", "Bee", "Skunk"};
private boolean runProcess = true;
private int index = 1;
private int index1 = 1;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ButtonsIcon t = new ButtonsIcon();
}
});
}
public ButtonsIcon() {
iconQueue.add(UIManager.getIcon("OptionPane.errorIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.informationIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.warningIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.questionIcon"));
one.setFont(new Font("Dialog", Font.BOLD, 24));
one.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
two.setFont(new Font("Dialog", Font.BOLD, 24));
two.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
three.setFont(new Font("Dialog", Font.BOLD, 10));
three.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
labelPanel.setLayout(new GridLayout(0, 3, 4, 4));
labelPanel.add(one);
labelPanel.add(two);
labelPanel.add(three);
//labelPanel.setBorder(new LineBorder(Color.black, 1));
labelPanel.setOpaque(false);
JButton button0 = createButton();
JButton button1 = createButton();
JButton button2 = createButton();
JButton button3 = createButton();
buttonPanel.setLayout(new GridLayout(0, 4, 4, 4));
buttonPanel.add(button0);
buttonPanel.add(button1);
buttonPanel.add(button2);
buttonPanel.add(button3);
//buttonPanel.setBorder(new LineBorder(Color.black, 1));
buttonPanel.setOpaque(false);
label.setLayout(new BorderLayout());
label.add(labelPanel, BorderLayout.NORTH);
label.add(buttonPanel, BorderLayout.SOUTH);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
label.setPreferredSize(new Dimension(d.width / 3, d.height / 3));
add(label, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
startBackground();
startLabel2();
new Thread(this).start();
printWords(); // generating freeze Swing GUI durring EDT
}
private JButton createButton() {
JButton button = new JButton();
button.setBorderPainted(false);
button.setBorder(null);
button.setFocusable(false);
button.setMargin(new Insets(0, 0, 0, 0));
button.setContentAreaFilled(false);
button.setIcon(nextIcon());
button.setRolloverIcon(nextIcon());
button.setPressedIcon(nextIcon());
button.setDisabledIcon(nextIcon());
nextIcon();
return button;
}
private Icon nextIcon() {
Icon icon = iconQueue.peek();
iconQueue.add(iconQueue.remove());
return icon;
}
// Update background at 4/3 Hz
private void startBackground() {
backTtimer = new javax.swing.Timer(750, updateBackground());
backTtimer.start();
backTtimer.setRepeats(true);
}
private Action updateBackground() {
return new AbstractAction("Background action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
label.setIcon(new ImageIcon(getImage()));
}
};
}
// Update Label two at 2 Hz
private void startLabel2() {
labelTimer = new javax.swing.Timer(500, updateLabel2());
labelTimer.start();
labelTimer.setRepeats(true);
}
private Action updateLabel2() {
return new AbstractAction("Label action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
two.setText(petStrings[index]);
index = (index + 1) % petStrings.length;
}
};
}
// Update lable one at 3 Hz
#Override
public void run() {
while (runProcess) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
one.setText(petStrings[index1]);
index1 = (index1 + 1) % petStrings.length;
}
});
try {
Thread.sleep(300);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Note: blocks EDT
private void printWords() {
for (int i = 0; i < petStrings.length; i++) {
String word = petStrings[i].toString();
System.out.println(word);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
three.setText(word);
}
three.setText("<html> Concurency Issues in Swing<br>"
+ " never to use Thread.sleep(int) <br>"
+ " durring EDT, simple to freeze GUI </html>");
}
public BufferedImage getImage() {
int w = label.getWidth();
int h = label.getHeight();
GradientPaint gp = new GradientPaint(0f, 0f, new Color(
127 + random.nextInt(128),
127 + random.nextInt(128),
127 + random.nextInt(128)),
w, w,
new Color(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
g2d.setColor(Color.BLACK);
return bi;
}
}
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.*;
class TimeThis extends JFrame {
private static final long serialVersionUID = 1L;
private ArrayList<Word> words;
private JTextField _textField; // set by timer listener
public TimeThis() throws IOException {
_textField = new JTextField(5);
_textField.setEditable(false);
_textField.setFont(new Font("sansserif", Font.PLAIN, 30));
JPanel content = new JPanel();
content.setLayout(new FlowLayout());
content.add(_textField);
this.setContentPane(content);
this.setTitle("Swing Timer");
this.pack();
this.setLocationRelativeTo(null);
this.setResizable(false);
_textField.setText("loading...");
readFile(); // read file
printWords(); // print results
}
public void readFile(){
try {
BufferedReader in = new BufferedReader(new FileReader("adameve.txt"));
words = new ArrayList<Word>();
int lineNum = 1; // we read first line in start
// delimeters of line in this example only "space"
char [] parse = {' '};
String delims = new String(parse);
String line = in.readLine();
String [] lineWords = line.split(delims);
// split the words and create word object
//System.out.println(lineWords.length);
for (int i = 0; i < lineWords.length; i++) {
Word w = new Word(lineWords[i]);
words.add(w);
}
lineNum++; // pass the next line
line = in.readLine();
in.close();
} catch (IOException e) {
}
}
private void printWords() {
final Timer timer = new Timer(100, null);
ActionListener listener = new ActionListener() {
private Iterator<Word> w = words.iterator();
#Override
public void actionPerformed(ActionEvent e) {
if (w.hasNext()) {
_textField.setText(w.next().getName());
//Prints to Console just Fine...
//System.out.println(w.next().getName());
}
else {
timer.stop();
}
}
};
timer.addActionListener(listener);
timer.start();
}
class Word{
private String name;
public Word(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static void main(String[] args) throws IOException {
JFrame ani = new TimeThis();
ani.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ani.setVisible(true);
}
}
I got it working with this code... Hope it can help someone else expand on their Java knowledge. Also, if anyone has any recommendations on cleaning this up. Please do so!
You're on the right track, but you're creating the frame's inside the loop, not outside. Here's what it should be like:
private void printWords() {
JFrame frame = new JFrame("Run Text File");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel textLabel = new JLabel("", SwingConstants.CENTER);
textLabel.setPreferredSize(new Dimension(300, 100));
frame.getContentPane().add(textLabel, BorderLayout.CENTER);
//Display the window. frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
for (int i = 0; i < words.size(); i++) {
//How many words?
//System.out.print(words.size());
//print each word on a new line...
Word w = words.get(i);
System.out.println(w.name);
//pause between each word.
try{
Thread.sleep(500);
}
catch(InterruptedException e){
e.printStackTrace();
}
textLabel.setTest(w.name);
}
}

Categories