【问题标题】:Tab in JTabbedPane does not reflect changes on button pressJTabbedPane 中的选项卡不反映按钮按下的变化
【发布时间】:2012-06-15 22:44:57
【问题描述】:

在我的 GUI 的选项卡中,允许用户编辑员工的姓名。该名称还用作选项卡的标签,因此当确认更改后,应更新选项卡以反映此更改并将新数据写入数据文件。

员工存储在Employees 类中的HashMap 中。这些选项卡通过迭代员工姓名的ArrayList<String> 来填充,这是通过调用方法Employees.getNames() 获得的。从 GUI 中,用户可以输入新名称,然后按更改名称按钮。按钮的ActionListener调用方法changeName(),将HashMap中的旧名称替换为新名称,并更新数据文件。

这在用户第一次想要更改员工姓名时可以正常工作,但随后的更改会产生错误。似乎包含JTextFieldsJPanel(参见下面的getEmployeeInfoPanel())没有更新参数name。该参数是员工的当前姓名,而新姓名是从JTextField 中获取的。

下面是一个说明这个问题的例子。基本上,这些步骤是:

1. old name = Mary is provided when the program starts
2. User changes name in JTextField, so oldName = Mary and newName = Mary S.
3. At this point, oldName should update to Mary S. as it is the new key.
   However, oldName remains as Mary so the HashMap cannot be  updated again.

这个特定屏幕的层次结构是:

JFrame (entire application)
   |
    -- JPanel EmployeesPanel (this screen)
   |     |
   |      -- JPanel (for custom menu bar)
   |     |
   |      -- JTabbedPane (one tab for each employee)
   |             |
   |              -- JPanel (contains JLabels, JTextField, etc for this employee)
   |
    -- .....

这是来自 GUI 的相关代码:

public class EmployeesPanel {
    private JTabbedPane pane;
    private Employees employees;
    ...
    public EmployeesPanel(JPanel panel, Container cards) {
        ...
        pane = new JTabbedPane();
        getEmployees();
    }

    private void getEmployees() {
                    ...
        employees = new Employees(properties, EMPLOYEES_TXT);
        //ArrayList of all employees' names
        names = employees.getNames();
        for(String name : names) {
            pane.addTab(name, getEmployeeInfoPanel(name));
        }
        pane.addTab("NEW EMPLOYEE", addEmployeePanel());
    }

    public JPanel addEmployeePanel() {
        ...
    }

    private JPanel getEmployeeInfoPanel(final String name) throws EmployeeException {
        JPanel infoPanel = new JPanel();
        infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.PAGE_AXIS));

        JLabel nameLabel = new JLabel("Employee name");
        JLabel wageLabel = new JLabel("Employee wage");
        final JTextField nameField = new JTextField(name, 30);
        final JTextField wageField = new JTextField(employees.getWage(name).toString(), 30);

        JButton changeNameButton = new JButton("CHANGE NAME");
        JButton changeWageButton = new JButton("CHANGE WAGE");

        changeNameButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                try {
                    String newName = nameField.getText();
                    employees.changeName(name, newName);
                    panel.validate();
                } catch (EmployeeException e) {
                    // TODO create popup warning
                }
            }
        });
        ...
        return infoPanel;
    }
}

这里是修改 HashMap 的雇员类的代码:

public void changeName(String oldName, String newName) throws EmployeeException {
    System.out.println("old name = " + oldName + ", new name = " + newName);
    if(employees.containsKey(oldName)) {
        BigDecimal wage = employees.get(oldName);
        employees.remove(oldName);
        employees.put(newName, wage);
        names.remove(oldName);
        names.add(newName);
        prop.remove(oldName);
        prop.setProperty(newName, wage.toString());
        saveProperties();
        System.out.println(names);
    } else {
        throw new EmployeeException("Could not change name because employee does not exist.");
    }
}

这是一个例子。第一个屏幕截图是从程序启动时开始的;员工姓名被填充到相应的选项卡中。第二个屏幕截图是在尝试更改员工姓名之后。如您所见,标签的标签没有改变,我假设调用validate() 会这样做。

(之前)

(按下按钮后)

最后,按两次更改名称按钮产生的输出,显示名称已在 ArrayList 中更改:

old name = Mary, new name = Mary S.
[Jane, Bob, Sue, Mary S.]
old name = Mary, new name = Mary S.
653647 [AWT-EventQueue-0] ERROR employees.EmployeeException - Could not change name because employee does not exist.

【问题讨论】:

  • 我没有看到发生错误的代码。
  • 按下更改名称按钮时发生错误。按钮的 ActionListener 调用方法changeName(),将员工的旧名称替换为新名称。第一次成功替换名称但不更新选项卡,后续任何更改都会报错。​​
  • 如果您按照@trashgod 的建议设置 JTabbedPane 的标题,但仍然有问题,那么我担心您的问题和代码显示不足以猜测问题。
  • 我将编辑我的问题,希望能提供更清晰的说明
  • 您需要创建并发布sscce。所有那些不相关的代码——而你的问题是你根本没有调用setTitleAt()。主。

标签: java swing user-interface jtabbedpane


【解决方案1】:

您可能正在寻找setTitleAt() 方法。

附录:为了比较,这里有一个sscce,它允许多次编辑。

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;

/**
 * @see http://stackoverflow.com/a/11007109/230513
 */
public class TabEdit extends JPanel {

    private static final int MAX = 5;
    private static final String NAME = "Tab ";
    private final JTabbedPane pane = new JTabbedPane();

    public TabEdit() {
        for (int i = 0; i < MAX; i++) {
            pane.add(NAME + String.valueOf(i), new TabContent(i));
        }
        this.add(pane);
    }

    private class TabContent extends JPanel {

        private TabContent(final int i) {
            final JTextField jtf = new JTextField(
                "Please edit the name of " + NAME + String.valueOf(i));
            this.add(jtf);
            jtf.addActionListener(new AbstractAction() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    pane.setTitleAt(i, jtf.getText());
                }
            });
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(320, 120);
        }
    }

    private void display() {
        JFrame f = new JFrame("TabEdit");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TabEdit().display();
            }
        });
    }
}

【讨论】:

  • 感谢您的回复。这解决了我在标签标题方面遇到的问题,但我仍然无法多次更改员工的姓名。
  • @AD:再次,我建议您接受此答案并在新线程中提出您的次要问题。 1+。
  • @AD:我刚刚在文本字段中直接添加了一个动作监听器以利用Enter 键绑定。随意调整此 sscce 以适应未来的任何相关问题。
  • @trashgod 非常感谢,非常感谢您的帮助!
  • @trashgod 通过与您的 sscce 合作,我也能够解决我遇到的主要问题。我没有在ActionListener 中使用final String name 参数作为oldName,而是获得了选项卡的标题,它可以完美运行。再次感谢:)
猜你喜欢
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 2012-08-30
  • 2017-03-28
  • 2023-03-10
  • 1970-01-01
  • 2021-06-09
  • 2012-07-31
相关资源
最近更新 更多