java - 无法更新面板上的 UI

标签 java swing user-interface

如果你看一下我下面的代码,我想做的是修改我的 addExpense() 方法来生成一个新的 ExpensePanel 并将其添加到我的面板之一(面板 3)和 vector 中并更新 UI面板 3 并更新统计数据。

但是经过无数次修改后我似乎无法让它工作。谁能提供一些见解吗?

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

最佳答案

您的问题是您的 ExpensePanel 类有两个 JPanel,一个是您将组件添加到 Called、exp,另一个是 this 或 JPanel,它是类中,您不添加任何组件。好吧,您正在将第二个 JPanel 添加到 GUI 中,因此不会显示任何内容。另请注意,exp 是在构造函数中声明的,因此其范围仅限于构造函数。

一种可能的解决方案:去掉exp并将所有内容添加到this。请注意,您可以使用 this. 形式的表达,例如 this.add(someComponent) ,它明确地表明了您的意图,但这是不必要的,并且添加了额外的单词,但没有什么好处在这种情况下,所以我通常会避免它。

即将您的构造函数更改为:

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

另一种可能的解决方案是保留 exp JPanel,但将其提升为具有 getter 方法的实例字段,然后不让 ExpensesPanel 扩展 JPanel。两者都可以,并且后者有一些优点,应该稍后讨论(关于使用组合相对于继承的优点)。

<小时/>

顺便说一句,这不会做任何事情:

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

因为在更改颜色状态后,您永远不会使用 g2d 进行绘制或清除(实际上是 clearRect(...))。

更好、更容易的方法是调用构造函数:

setBackground(Color.blue);
<小时/>

接下来的问题,这是错误的:

add(newCost, Box.createHorizontalGlue());

这不是添加胶水的方法。请检查有关此内容的教程和 API——您正在做大量的猜测工作,但这些工作永远不会起作用。

关于java - 无法更新面板上的 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20332725/

相关文章:

java - 如何使用大小调整所有Graphics2D

java - 从不同于 GUI 的类更新 TextField

java - 如何仅使用一个连接在 hibernate 中执行嵌套事务?

java.io.Exception com.android.okhttp 上的流意外结束

java - 当客户的首选尺寸发生变化时,如何让 JScrollPane 滚动条出现?

c++ - 是否有与 VS2008 或 Eclipse CDT 集成到 CPPUnit 的插件?

c++ - 将 QMainWindow 中的 QDockWidget 排列在多列中

java - 可变速率消费者的负载平衡队列

java - 从另一个角度提问

c++ - QT UI 测试的最佳方法