简体   繁体   English

无法更新面板上的UI

[英]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. 如果您在下面查看我的代码,我想做的就是修改我的addExpense()方法以生成一个新的ExpensePanel并将其添加到我的一个面板(面板3)和向量中,并更新面板3和也更新统计信息。

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);
    }
}

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. 您的问题是您的ExpensePanel类具有两个 JPanel,一个将组件添加到被调用的exp中,另一个将this或JPanel作为类的对象,而没有添加任何组件。 Well you're adding the second JPanel to your GUI so nothing gets shown. 好吧,您正在向您的GUI添加第二个JPanel,因此什么也不会显示。 Note also that exp is declared in the constructor and so its scope is limited to the constructor only. 还要注意,exp是在构造函数中声明的,因此它的范围仅限于构造函数。

One possible solution: get rid of exp and add everything to this . 一种可能的解决方案:删除exp并将所有内容添加到this Note that you could use the this. 请注意,您可以使用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. 这种形式的表达,例如this.add(someComponent)可以明确显示您的意图,但在这种情况下,它是不必要的,并且添加的额外单词收效甚微,因此我通常避免这样做。

ie, 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. 另一种可能的解决方案是保留exp JPanel,但使用getter方法将其提升为实例字段,然后让ExpensesPanel扩展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. 因为您永远不会在更改其Color状态后使用g2d绘制或清除(实际上是clearRect(...) )。

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. 请检查有关此内容的教程和API-您正在做大量的猜测工作,但从未成功。

As well as @Hovercraft Full Of Eels answer, you should also make changes to GUI components via something like... 除了@Hovercraft Full Of Eels答案外,您还应该通过类似以下方式更改GUI组件:

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

This updates it from the Event Dispatch Thread (EDT). 这将从事件调度线程(EDT)更新它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM