Zy0n
Zy0n

Reputation: 785

Can't update UI on panel

if you have a look at my code below, what im trying to do is modify my addExpense() method to generate a new ExpensePanel and add it to one of my panels (panel 3) and the vector and update the UI on panel 3 and update the stats too.

However after countless modification i can't seem to get it to work. Can anyone lend some insight?

    import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.UIManager;

class Expenses extends JFrame implements ActionListener{

    ExpensesPanel widget;
    public String n;
    public String d;
    public int c;
    public int e;

    public Expenses(){

        // Set Dimension, size, and close operations
        setSize(400,400);
        setTitle("Expenses");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setResizable(true);
        setLocationRelativeTo(null);

        // Set the look and feel of the application to that if the OS
        try{
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch(Exception e){
            System.out.print(e);
        }

        // Add Panel 1, or our main panel
        JPanel p1 = new JPanel();
        getContentPane().add(p1);
        p1.setLayout(new BoxLayout(p1, BoxLayout.Y_AXIS));

        // Add our second panel, panel 2 with a grid layout
        JPanel p2 = new JPanel();
        p2.setLayout(new GridLayout(4,2));
        p1.add(p2);

        // Add our labels
        JLabel label1 = new JLabel("Name: ", JLabel.LEFT);
        JTextField name = new JTextField(JTextField.EAST);
        n = name.getText();
        JLabel label2 = new JLabel("Date: ", JLabel.LEFT);
        JTextField date = new JTextField(JTextField.EAST);
        d = date.getText();
        JLabel label3 = new JLabel("Cost: ", JLabel.LEFT);
        JTextField cost = new JTextField(JTextField.EAST);
        p2.add(label1);
        p2.add(name);
        p2.add(label2);
        p2.add(date);
        p2.add(label3);
        p2.add(cost);
        // Add our buttons
        JButton b1 = new JButton("Add");
        p2.add(b1);
        JButton b2 = new JButton("Clear");
        p2.add(b2);
        // Set the preferred size of our windows
        p2.setMaximumSize(new Dimension(Integer.MAX_VALUE, p2.getPreferredSize().height));

        // Panel 3, this will hold the expenses panel
        final JPanel p3 = new JPanel();
        p3.setLayout(new BoxLayout(p3, BoxLayout.Y_AXIS));
        JScrollPane scroll = new JScrollPane(p3);
        p1.add(scroll);

        // Panel 4, with a 2x2 Grid
        JPanel p4 = new JPanel();
        p4.setLayout(new GridLayout(2,2));
        p1.add(p4);
        // Add labels, and ensure they are not editable
        JLabel p4l1 = new JLabel("Total", JLabel.LEFT);
        JTextField p4t1 = new JTextField(JTextField.EAST);
        p4t1.setEditable(false);
        JLabel p4l2 = new JLabel("Average", JLabel.LEFT);
        JTextField p4t2 = new JTextField(JTextField.EAST);
        p4t2.setEditable(false);
        p4.add(p4l1);
        p4.add(p4t1);
        p4.add(p4l2);
        p4.add(p4t2);
        // Set the preferred size to fit the rest of the window
        p4.setMaximumSize(new Dimension(Integer.MAX_VALUE, p2.getPreferredSize().height));

        // Action listeners for both buttons
        // Action listner for button 1
        b1.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                System.out.println("Button 1 Clicked");
                addExpense(p3);
            }

        });

        // Action Listener for button 2
        b2.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                System.out.println("Button 2 Clicked");
            }

        });

    }

    public void addExpense(JPanel p3){
        Vector expenseHolder = new Vector();
        ExpensesPanel e = new ExpensesPanel(n, d, 2, 1);
        p3.add(e);
        expenseHolder.add(p3);
        p3.revalidate();
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        // TODO Auto-generated method stub

    }

    public static void main(String[] args){
        // Main method
        Expenses e = new Expenses();
        // Set the application to be visible
        e.setVisible(true);
    }
}

class ExpensesPanel extends JPanel{

    public String n;
    public String d;
    public int c;
    public int e;

    public ExpensesPanel(String name, String date, int cost, int expense){
        n = name; d = date; c = cost; e = expense;

        // Create new Panel and set it on horizontal axis
        JPanel exp = new JPanel();
        exp.setLayout(new BoxLayout(exp, BoxLayout.X_AXIS));
        Box horizontalBox;

        // Labels
        JLabel newName = new JLabel("Name: ", JLabel.CENTER);
        JLabel newDate = new JLabel("Date", JLabel.CENTER);
        JLabel newCost = new JLabel("Cost: ", JLabel.CENTER);
        JLabel newExp = new JLabel("Expense: ", JLabel.CENTER);
        exp.add(newName, Box.createHorizontalGlue());
        exp.add(newDate, Box.createHorizontalGlue());
        exp.add(newCost, Box.createHorizontalGlue());
        exp.add(newExp, Box.createHorizontalGlue());

    }

    // Override default paint component
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setBackground(Color.BLUE);
    }
}

Upvotes: 1

Views: 571

Answers (2)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285450

Your problem is that your ExpensePanel class has two JPanels, one you add components to called, exp, and the other, the this or JPanel that is the object of the class, you add no components to. Well you're adding the second JPanel to your GUI so nothing gets shown. Note also that exp is declared in the constructor and so its scope is limited to the constructor only.

One possible solution: get rid of exp and add everything to this. Note that you could use the this. form of expression, such as this.add(someComponent) which explicitly shows your intention, but it's unnecessary and adds extra words with little benefit in this situation, so I generally avoid it.

i.e., change your constructor to:

public ExpensesPanel(String name, String date, int cost, int expense) {
  n = name;
  d = date;
  c = cost;
  e = expense;

  // Create new Panel and set it on horizontal axis
  // JPanel exp = new JPanel();
  setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
  Box horizontalBox;

  // Labels
  JLabel newName = new JLabel("Name: ", JLabel.CENTER);
  JLabel newDate = new JLabel("Date", JLabel.CENTER);
  JLabel newCost = new JLabel("Cost: ", JLabel.CENTER);
  JLabel newExp = new JLabel("Expense: ", JLabel.CENTER);
  add(newName, Box.createHorizontalGlue());
  add(newDate, Box.createHorizontalGlue());
  add(newCost, Box.createHorizontalGlue());
  add(newExp, Box.createHorizontalGlue());
}

The other possible solution is to keep the exp JPanel, but promote it to be an instance field with a getter method, and then not have ExpensesPanel extend JPanel. Either would work, and there are some advantages to the latter which should be discussed at a later time (regarding the advantages of using composition over inheritance).


As an aside, this will do nothing:

public void paintComponent(Graphics g){
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    g2d.setBackground(Color.BLUE);
}

since you never draw or clear (clearRect(...) actually) with g2d after changing its Color state.

Better and much easier is to call in your constructor:

setBackground(Color.blue);

Problem next, this is wrong:

add(newCost, Box.createHorizontalGlue());

That's not how you add glue. Please check the tutorials and API on this -- you're doing an awful lot of guess work which never works.

Upvotes: 1

Ross Drew
Ross Drew

Reputation: 8246

As well as @Hovercraft Full Of Eels answer, you should also make changes to GUI components via something like...

 EventQueue.invokeLater(new Runnable(){
  public void run()
  { 
    //make gui change here
  }
 });

This updates it from the Event Dispatch Thread (EDT).

Upvotes: 1

Related Questions