JList 未在单独的窗格上更新(Swing,Java)
JList not updating on separate pane (Swing, Java)
在我的第一个名为 Password Vault 的选项卡上,我有一个 JList,其中包含存储密码的 "websites" 列表。在第二个选项卡上,我有一个添加 "password" 功能。当我添加密码时,JList 仅在窗格上更新。当我切换回另一个选项卡 "password vault" 时,它还没有更新。当我重新启动程序时,它已更新。我使用了一个字段,所以这不是局部变量的问题。
public final class PasswordManagerView1 extends JFrame
implements PasswordManagerView, ListSelectionListener {
/**
* JList.
*/
private JList<String> list;
/**
* JButtons.
*/
private JButton enter, unlock, reset, buttonAddEnter;
/**
* Controller.
*/
private PasswordManagerController controller;
/**
* Dimensions.
*/
private Dimension maxSize;
/**
* JTabbedPanes.
*/
private JTabbedPane tabbedPane;
/**
* JTextField.
*/
private JTextField passwordDisplay, textField;
/**
* PasswordField.
*/
private JPasswordField passwordField, resetField, passwordFieldadd;
/**
* Useful Constants.
*/
private static final int MAX_SIZE_HORI = 800, MAX_SIZE_VERTI = 400,
EMPTY_BORDER_SIZE = 5;
/**
* Constructor.
*/
public PasswordManagerView1() {
super("Password Manager");
JTabbedPane tabbedPane = new JTabbedPane();
//Initial JPanel creation
tabbedPane.setBorder(
new EmptyBorder(PasswordManagerView1.EMPTY_BORDER_SIZE,
PasswordManagerView1.EMPTY_BORDER_SIZE,
PasswordManagerView1.EMPTY_BORDER_SIZE,
PasswordManagerView1.EMPTY_BORDER_SIZE));
this.maxSize = new Dimension(PasswordManagerView1.MAX_SIZE_HORI,
PasswordManagerView1.MAX_SIZE_VERTI);
tabbedPane.setPreferredSize(this.maxSize);
this.getContentPane().add(tabbedPane);
//Initial JTabbedPane creation
//Tab creation
JComponent panel1 = this.makePasswordVault();
ImageIcon icon = new ImageIcon("lock-icon.png");
tabbedPane.addTab("Password Vault", icon, panel1,
"View the passwords in the vault");
JComponent panel3 = this.makeAddPanel("Add Password");
tabbedPane.addTab("Add Password", icon, panel3,
"Add passwords to the vault");
//JComponent panel2 = this.makeAddPanel("ALSO ADDS");
//tabbedPane.addTab("Delete Password", icon, panel2,
// "Deletes a password from the vault");
JComponent panel4 = this.makeInfoPanel();
tabbedPane.addTab("Info", icon, panel4,
"View settings and program info");
//Pack up
this.setResizable(false);
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
@Override
public JComponent makeAddPanel(String text) {
JPanel panel = new JPanel();
panel.setLayout(null);
//Creation of string array of with stores
String[] listContentC = this.getStore();
this.list = new JList<>(listContentC);
this.list.setBounds(0, 0, 233, 360);
JScrollPane pane = new JScrollPane(this.list);
pane.setBounds(0, 0, 233, 360);
panel.add(pane);
JLabel labelAdd = new JLabel("Add Password");
labelAdd.setHorizontalAlignment(SwingConstants.CENTER);
labelAdd.setFont(new Font("Times New Roman", Font.PLAIN, 24));
labelAdd.setBounds(427, 38, 163, 31);
panel.add(labelAdd);
this.passwordFieldadd = new JPasswordField();
this.passwordFieldadd.setBounds(536, 100, 116, 22);
panel.add(this.passwordFieldadd);
this.textField = new JTextField();
this.textField.setBounds(375, 100, 116, 22);
panel.add(this.textField);
JLabel lblWebsite = new JLabel("Website");
lblWebsite.setHorizontalAlignment(SwingConstants.CENTER);
lblWebsite.setFont(new Font("Times New Roman", Font.PLAIN, 13));
lblWebsite.setBounds(401, 126, 56, 16);
panel.add(lblWebsite);
JLabel lblPassword = new JLabel("Password");
lblPassword.setHorizontalAlignment(SwingConstants.CENTER);
lblPassword.setFont(new Font("Times New Roman", Font.PLAIN, 13));
lblPassword.setBounds(566, 126, 56, 16);
panel.add(lblPassword);
this.buttonAddEnter = new JButton("Enter");
this.buttonAddEnter.setBounds(465, 161, 97, 25);
panel.add(this.buttonAddEnter);
this.buttonAddEnter.addActionListener(this);
return panel;
}
@Override
public JComponent makeInfoPanel() {
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1, 1));
StringBuilder toPrint = new StringBuilder();
SimpleReader in = new SimpleReader1L("data/Notice.txt");
while (!in.atEOS()) {
toPrint.append(in.nextLine() + "\n");
}
String toPrintString = toPrint.toString();
JTextArea noticeText = new JTextArea(toPrintString);
noticeText.setEditable(false);
JScrollPane noticeTextScroll = new JScrollPane(noticeText);
panel.add(noticeTextScroll);
in.close();
return panel;
}
@Override
public JComponent makePasswordVault() {
JPanel panel = new JPanel();
panel.setLayout(null);
/*
* Ask for help on this.
*
* I would have liked to create the listContentC by passing nothing into
* the controller and then the controller using the model to extract the
* data from a text file. However, my array was always initialized to
* something null and caused a runtime error.
*
*
*/
//Creation of string array of with stores
String[] listContentC = this.getStore();
//GUI setup of list
this.list = new JList<>(listContentC);
this.list.setLayoutOrientation(JList.VERTICAL);
this.list.addListSelectionListener(this);
JScrollPane pane = new JScrollPane(this.list);
pane.setBounds(0, 0, 233, 360);
panel.add(pane);
//The label creation (for instructions)
JLabel labelA = new JLabel("the store and press enter!");
labelA.setFont(new Font("Times New Roman", Font.PLAIN, 13));
labelA.setBounds(294, 70, 157, 31);
panel.add(labelA);
JLabel labelB = new JLabel("To view a password, click on");
labelB.setFont(new Font("Times New Roman", Font.PLAIN, 13));
labelB.setBounds(284, 54, 163, 31);
panel.add(labelB);
//Enter button creation
this.enter = new JButton("Enter");
this.enter.setBounds(303, 128, 116, 25);
panel.add(this.enter);
this.enter.setEnabled(false);
this.enter.addActionListener(this);
//Password Display field creation
this.passwordDisplay = new JTextField();
this.passwordDisplay.setBackground(Color.WHITE);
this.passwordDisplay.setEditable(false);
this.passwordDisplay
.setFont(new Font("Times New Roman", Font.PLAIN, 13));
this.passwordDisplay.setHorizontalAlignment(SwingConstants.CENTER);
this.passwordDisplay.setText("");
this.passwordDisplay.setBounds(303, 247, 116, 22);
panel.add(this.passwordDisplay);
this.passwordDisplay.setColumns(10);
//Password Label creation
JLabel passwordLabel = new JLabel("Password:");
passwordLabel.setHorizontalAlignment(SwingConstants.CENTER);
passwordLabel.setFont(new Font("Times New Roman", Font.PLAIN, 13));
passwordLabel.setBounds(336, 218, 56, 16);
panel.add(passwordLabel);
//Master password notice
JLabel mastPass = new JLabel("Enter master password to unlock vault:");
mastPass.setFont(new Font("Times New Roman", Font.PLAIN, 13));
mastPass.setBounds(532, 54, 218, 31);
panel.add(mastPass);
//Password Field
this.passwordField = new JPasswordField();
this.passwordField.setBounds(532, 128, 116, 24);
panel.add(this.passwordField);
//Unlock button
this.unlock = new JButton("Unlock");
this.unlock.setFont(new Font("Times New Roman", Font.PLAIN, 13));
this.unlock.setBounds(660, 127, 97, 25);
panel.add(this.unlock);
this.unlock.addActionListener(this);
//New setup label
JLabel labelC = new JLabel("Reset/Set up new master pass:");
labelC.setHorizontalAlignment(SwingConstants.CENTER);
labelC.setFont(new Font("Times New Roman", Font.PLAIN, 13));
labelC.setBounds(532, 217, 218, 16);
panel.add(labelC);
//New setup label
JLabel defaultLabel = new JLabel("Default Password = \"password\"");
defaultLabel.setHorizontalAlignment(SwingConstants.CENTER);
defaultLabel.setFont(new Font("Times New Roman", Font.PLAIN, 13));
defaultLabel.setBounds(560, 77, 171, 16);
panel.add(defaultLabel);
this.resetField = new JPasswordField();
this.resetField.setBounds(532, 246, 116, 24);
panel.add(this.resetField);
this.reset = new JButton("Update");
this.reset.setFont(new Font("Times New Roman", Font.PLAIN, 13));
this.reset.setBounds(660, 245, 97, 25);
this.reset.setEnabled(false);
panel.add(this.reset);
this.reset.addActionListener(this);
return panel;
}
@Override
public String[] getStore() {
int storeCount = 0;
SimpleReader in = new SimpleReader1L("data/store.txt");
while (!in.atEOS()) {
storeCount++;
in.nextLine();
}
in.close();
String[] listContentC = new String[storeCount];
SimpleReader in2 = new SimpleReader1L("data/store.txt");
for (int i = 0; i < storeCount; i++) {
listContentC[i] = in2.nextLine();
}
in2.close();
return listContentC;
}
@Override
public void registerObserver(PasswordManagerController controller) {
this.controller = controller;
}
@Override
public void updateEnterButtonVaultTab(boolean result) {
this.enter.setEnabled(result);
}
@Override
public void actionPerformed(ActionEvent event) {
//Wait cursor
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
//What button was pressed
Object source = event.getSource();
if (source == this.enter) {
int index = this.list.getSelectedIndex();
System.out.println(index);
if (this.list.getSelectedIndex() != -1) {
this.controller.processEnterEvent(this.list.getSelectedValue());
}
} else if (source == this.unlock) {
this.controller
.processUnlockEvent(this.passwordField.getPassword());
} else if (source == this.reset) {
this.controller.processResetEvent(this.resetField.getPassword());
} else if (source == this.buttonAddEnter) {
this.controller.processAddEvent(this.textField.getText(),
this.passwordFieldadd.getPassword());
//needs done in model
this.updateListModel();
}
this.setCursor(Cursor.getDefaultCursor());
}
@Override
public void updateListModel() {
//MOVE TO THE MODEL
String[] temp = this.getStore();
DefaultListModel<String> temp2 = new DefaultListModel<>();
for (int i = 0; i < temp.length; i++) {
temp2.addElement(temp[i]);
}
this.list.setModel(temp2);
}
@Override
public JTabbedPane getTabbedPane() {
return this.tabbedPane;
}
@Override
public void setTabbedPane(JTabbedPane tabbedPane) {
this.tabbedPane = tabbedPane;
}
@Override
public void updatePasswordField() {
this.passwordField.setText("");
}
@Override
public void updateResetPasswordDisplay() {
this.resetField.setText("");
}
@Override
public void displayWrongPass() {
JOptionPane.showMessageDialog(this, "Wrong password entered!");
}
@Override
public void displayUpdatedPass() {
JOptionPane.showMessageDialog(this, "Master password updated!");
}
@Override
public void updateResetButton(boolean result) {
this.reset.setEnabled(result);
}
@Override
public void updatePasswordDisplay(char[] password) {
StringBuilder passwordCreation = new StringBuilder();
for (int i = 0; i < password.length; i++) {
passwordCreation.append(password[i]);
}
this.passwordDisplay.setText(passwordCreation.toString());
}
@Override
public JComponent makeTextPanel(String text) {
// TODO Auto-generated method stub
return null;
}
@Override
public void valueChanged(ListSelectionEvent arg0) {
}
}
仅从学术的角度来看,我建议图形元素和下层数据模型之间的这种关系应该作为观察者模式来实现(https://en.wikipedia.org/wiki/Observer_pattern)。当您开始拥有 5 或 6 个 GUI 元素都对同一共享数据结构中的更改做出反应时,您向我们展示的方式可能很快就会变得混乱且难以维护。
您的构造函数调用了 makePasswordPanel(),其中包含以下行:
this.list = new JList<>(listContentC);
然后构造函数调用 makeAddPanel(),其中包含以下行:
this.list = new JList<>(listContentC);
现在您已经丢弃了第一个列表的句柄,并用对新列表的引用替换了它。然后在您的 updateListModel 中,更改 this.list 的模型(即 makeAddPanel 列表)。无法同时更新密码面板的模型,因为您已放弃对该面板的引用。
同样,要显示多个JList,都显示相同的内容,那么都应该共享相同的模型。如果这样做,那么对一个 JList 所做的更改将反映在所有其他 JList 中,因为更改实际上并不是对 JList 本身(它只显示模型的内容)而是对共享模型进行的。要理解这一点,您需要阅读 MVC 或模型-视图-控制器设计模式,因为 Swing 组件使用此的 变体 。
例如,请看下面的代码,我创建了 3 个 JPanel,每个都有自己的 JList,但它们都共享相同的 DefaultListModel<String>
。请注意,我的所有 3 个 JPanel 都从父级 class 扩展,该父级 class 实际持有 JList 并在其构造函数中接受模型。然后,如果我在一个 JPanel 中添加列表项或在另一个 JPanel 中删除它们,它们都会显示在 3 个 JPanel 的所有列表中。另请查看我如何将代码最小化以接近编译所需的最小代码,运行,并显示问题或解决方案,minimal code example program 或 MCVE:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class PanelsWithSharedList extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = 250;
private JTabbedPane tabbedPane = new JTabbedPane();
private DefaultListModel<String> listModel = new DefaultListModel<>();
public PanelsWithSharedList() {
for (int i = 0; i < 10; i++) {
listModel.addElement("List element " + (i + 1));
}
setLayout(new BorderLayout());
add(tabbedPane);
tabbedPane.add("Panel 1", new ListShowingPanel1(listModel));
tabbedPane.add("Panel 2", new ListShowingPanel2(listModel));
tabbedPane.add("Panel 3", new ListShowingPanel3(listModel));
}
@Override
public Dimension getPreferredSize() {
Dimension superSz = super.getPreferredSize();
if (isPreferredSizeSet()) {
return superSz;
}
int prefW = Math.max(superSz.width, PREF_W);
int prefH = Math.max(superSz.height, PREF_H);
return new Dimension(prefW, prefH);
}
private static void createAndShowGui() {
PanelsWithSharedList mainPanel = new PanelsWithSharedList();
JFrame frame = new JFrame("Panels With Shared List");
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());
}
}
@SuppressWarnings("serial")
abstract class AbstractListShowingPanel extends JPanel {
private JList<String> list;
public AbstractListShowingPanel(DefaultListModel<String> listModel) {
list = new JList<>(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
public JList<String> getList() {
return list;
}
public DefaultListModel<String> getModel() {
return (DefaultListModel<String>) list.getModel();
}
}
@SuppressWarnings("serial")
class ListShowingPanel1 extends AbstractListShowingPanel {
private JTextField textField = new JTextField(10);
public ListShowingPanel1(DefaultListModel<String> listModel) {
super(listModel);
add(new JScrollPane(getList()));
add(new JLabel("Text to add:"));
Action action = new AddTextAction();
textField.setAction(action);
add(textField);
add(new JButton(action));
}
private class AddTextAction extends AbstractAction {
public AddTextAction() {
super("Add Text");
putValue(MNEMONIC_KEY, KeyEvent.VK_A);
}
@Override
public void actionPerformed(ActionEvent e) {
getModel().addElement(textField.getText());
textField.selectAll();
}
}
}
@SuppressWarnings("serial")
class ListShowingPanel2 extends AbstractListShowingPanel {
public ListShowingPanel2(DefaultListModel<String> listModel) {
super(listModel);
add(new JScrollPane(getList()));
add(new JButton(new DeleteItemAction()));
}
private class DeleteItemAction extends AbstractAction {
public DeleteItemAction() {
super("Delete Selected Item");
putValue(MNEMONIC_KEY, KeyEvent.VK_D);
}
public void actionPerformed(ActionEvent e) {
JList<String> list = getList();
String selection = list.getSelectedValue();
if (selection != null) {
getModel().removeElement(selection);
}
}
}
}
@SuppressWarnings("serial")
class ListShowingPanel3 extends AbstractListShowingPanel {
public ListShowingPanel3(DefaultListModel<String> listModel) {
super(listModel);
setLayout(new BorderLayout());
add(new JScrollPane(getList()));
}
}
在我的第一个名为 Password Vault 的选项卡上,我有一个 JList,其中包含存储密码的 "websites" 列表。在第二个选项卡上,我有一个添加 "password" 功能。当我添加密码时,JList 仅在窗格上更新。当我切换回另一个选项卡 "password vault" 时,它还没有更新。当我重新启动程序时,它已更新。我使用了一个字段,所以这不是局部变量的问题。
public final class PasswordManagerView1 extends JFrame
implements PasswordManagerView, ListSelectionListener {
/**
* JList.
*/
private JList<String> list;
/**
* JButtons.
*/
private JButton enter, unlock, reset, buttonAddEnter;
/**
* Controller.
*/
private PasswordManagerController controller;
/**
* Dimensions.
*/
private Dimension maxSize;
/**
* JTabbedPanes.
*/
private JTabbedPane tabbedPane;
/**
* JTextField.
*/
private JTextField passwordDisplay, textField;
/**
* PasswordField.
*/
private JPasswordField passwordField, resetField, passwordFieldadd;
/**
* Useful Constants.
*/
private static final int MAX_SIZE_HORI = 800, MAX_SIZE_VERTI = 400,
EMPTY_BORDER_SIZE = 5;
/**
* Constructor.
*/
public PasswordManagerView1() {
super("Password Manager");
JTabbedPane tabbedPane = new JTabbedPane();
//Initial JPanel creation
tabbedPane.setBorder(
new EmptyBorder(PasswordManagerView1.EMPTY_BORDER_SIZE,
PasswordManagerView1.EMPTY_BORDER_SIZE,
PasswordManagerView1.EMPTY_BORDER_SIZE,
PasswordManagerView1.EMPTY_BORDER_SIZE));
this.maxSize = new Dimension(PasswordManagerView1.MAX_SIZE_HORI,
PasswordManagerView1.MAX_SIZE_VERTI);
tabbedPane.setPreferredSize(this.maxSize);
this.getContentPane().add(tabbedPane);
//Initial JTabbedPane creation
//Tab creation
JComponent panel1 = this.makePasswordVault();
ImageIcon icon = new ImageIcon("lock-icon.png");
tabbedPane.addTab("Password Vault", icon, panel1,
"View the passwords in the vault");
JComponent panel3 = this.makeAddPanel("Add Password");
tabbedPane.addTab("Add Password", icon, panel3,
"Add passwords to the vault");
//JComponent panel2 = this.makeAddPanel("ALSO ADDS");
//tabbedPane.addTab("Delete Password", icon, panel2,
// "Deletes a password from the vault");
JComponent panel4 = this.makeInfoPanel();
tabbedPane.addTab("Info", icon, panel4,
"View settings and program info");
//Pack up
this.setResizable(false);
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
@Override
public JComponent makeAddPanel(String text) {
JPanel panel = new JPanel();
panel.setLayout(null);
//Creation of string array of with stores
String[] listContentC = this.getStore();
this.list = new JList<>(listContentC);
this.list.setBounds(0, 0, 233, 360);
JScrollPane pane = new JScrollPane(this.list);
pane.setBounds(0, 0, 233, 360);
panel.add(pane);
JLabel labelAdd = new JLabel("Add Password");
labelAdd.setHorizontalAlignment(SwingConstants.CENTER);
labelAdd.setFont(new Font("Times New Roman", Font.PLAIN, 24));
labelAdd.setBounds(427, 38, 163, 31);
panel.add(labelAdd);
this.passwordFieldadd = new JPasswordField();
this.passwordFieldadd.setBounds(536, 100, 116, 22);
panel.add(this.passwordFieldadd);
this.textField = new JTextField();
this.textField.setBounds(375, 100, 116, 22);
panel.add(this.textField);
JLabel lblWebsite = new JLabel("Website");
lblWebsite.setHorizontalAlignment(SwingConstants.CENTER);
lblWebsite.setFont(new Font("Times New Roman", Font.PLAIN, 13));
lblWebsite.setBounds(401, 126, 56, 16);
panel.add(lblWebsite);
JLabel lblPassword = new JLabel("Password");
lblPassword.setHorizontalAlignment(SwingConstants.CENTER);
lblPassword.setFont(new Font("Times New Roman", Font.PLAIN, 13));
lblPassword.setBounds(566, 126, 56, 16);
panel.add(lblPassword);
this.buttonAddEnter = new JButton("Enter");
this.buttonAddEnter.setBounds(465, 161, 97, 25);
panel.add(this.buttonAddEnter);
this.buttonAddEnter.addActionListener(this);
return panel;
}
@Override
public JComponent makeInfoPanel() {
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1, 1));
StringBuilder toPrint = new StringBuilder();
SimpleReader in = new SimpleReader1L("data/Notice.txt");
while (!in.atEOS()) {
toPrint.append(in.nextLine() + "\n");
}
String toPrintString = toPrint.toString();
JTextArea noticeText = new JTextArea(toPrintString);
noticeText.setEditable(false);
JScrollPane noticeTextScroll = new JScrollPane(noticeText);
panel.add(noticeTextScroll);
in.close();
return panel;
}
@Override
public JComponent makePasswordVault() {
JPanel panel = new JPanel();
panel.setLayout(null);
/*
* Ask for help on this.
*
* I would have liked to create the listContentC by passing nothing into
* the controller and then the controller using the model to extract the
* data from a text file. However, my array was always initialized to
* something null and caused a runtime error.
*
*
*/
//Creation of string array of with stores
String[] listContentC = this.getStore();
//GUI setup of list
this.list = new JList<>(listContentC);
this.list.setLayoutOrientation(JList.VERTICAL);
this.list.addListSelectionListener(this);
JScrollPane pane = new JScrollPane(this.list);
pane.setBounds(0, 0, 233, 360);
panel.add(pane);
//The label creation (for instructions)
JLabel labelA = new JLabel("the store and press enter!");
labelA.setFont(new Font("Times New Roman", Font.PLAIN, 13));
labelA.setBounds(294, 70, 157, 31);
panel.add(labelA);
JLabel labelB = new JLabel("To view a password, click on");
labelB.setFont(new Font("Times New Roman", Font.PLAIN, 13));
labelB.setBounds(284, 54, 163, 31);
panel.add(labelB);
//Enter button creation
this.enter = new JButton("Enter");
this.enter.setBounds(303, 128, 116, 25);
panel.add(this.enter);
this.enter.setEnabled(false);
this.enter.addActionListener(this);
//Password Display field creation
this.passwordDisplay = new JTextField();
this.passwordDisplay.setBackground(Color.WHITE);
this.passwordDisplay.setEditable(false);
this.passwordDisplay
.setFont(new Font("Times New Roman", Font.PLAIN, 13));
this.passwordDisplay.setHorizontalAlignment(SwingConstants.CENTER);
this.passwordDisplay.setText("");
this.passwordDisplay.setBounds(303, 247, 116, 22);
panel.add(this.passwordDisplay);
this.passwordDisplay.setColumns(10);
//Password Label creation
JLabel passwordLabel = new JLabel("Password:");
passwordLabel.setHorizontalAlignment(SwingConstants.CENTER);
passwordLabel.setFont(new Font("Times New Roman", Font.PLAIN, 13));
passwordLabel.setBounds(336, 218, 56, 16);
panel.add(passwordLabel);
//Master password notice
JLabel mastPass = new JLabel("Enter master password to unlock vault:");
mastPass.setFont(new Font("Times New Roman", Font.PLAIN, 13));
mastPass.setBounds(532, 54, 218, 31);
panel.add(mastPass);
//Password Field
this.passwordField = new JPasswordField();
this.passwordField.setBounds(532, 128, 116, 24);
panel.add(this.passwordField);
//Unlock button
this.unlock = new JButton("Unlock");
this.unlock.setFont(new Font("Times New Roman", Font.PLAIN, 13));
this.unlock.setBounds(660, 127, 97, 25);
panel.add(this.unlock);
this.unlock.addActionListener(this);
//New setup label
JLabel labelC = new JLabel("Reset/Set up new master pass:");
labelC.setHorizontalAlignment(SwingConstants.CENTER);
labelC.setFont(new Font("Times New Roman", Font.PLAIN, 13));
labelC.setBounds(532, 217, 218, 16);
panel.add(labelC);
//New setup label
JLabel defaultLabel = new JLabel("Default Password = \"password\"");
defaultLabel.setHorizontalAlignment(SwingConstants.CENTER);
defaultLabel.setFont(new Font("Times New Roman", Font.PLAIN, 13));
defaultLabel.setBounds(560, 77, 171, 16);
panel.add(defaultLabel);
this.resetField = new JPasswordField();
this.resetField.setBounds(532, 246, 116, 24);
panel.add(this.resetField);
this.reset = new JButton("Update");
this.reset.setFont(new Font("Times New Roman", Font.PLAIN, 13));
this.reset.setBounds(660, 245, 97, 25);
this.reset.setEnabled(false);
panel.add(this.reset);
this.reset.addActionListener(this);
return panel;
}
@Override
public String[] getStore() {
int storeCount = 0;
SimpleReader in = new SimpleReader1L("data/store.txt");
while (!in.atEOS()) {
storeCount++;
in.nextLine();
}
in.close();
String[] listContentC = new String[storeCount];
SimpleReader in2 = new SimpleReader1L("data/store.txt");
for (int i = 0; i < storeCount; i++) {
listContentC[i] = in2.nextLine();
}
in2.close();
return listContentC;
}
@Override
public void registerObserver(PasswordManagerController controller) {
this.controller = controller;
}
@Override
public void updateEnterButtonVaultTab(boolean result) {
this.enter.setEnabled(result);
}
@Override
public void actionPerformed(ActionEvent event) {
//Wait cursor
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
//What button was pressed
Object source = event.getSource();
if (source == this.enter) {
int index = this.list.getSelectedIndex();
System.out.println(index);
if (this.list.getSelectedIndex() != -1) {
this.controller.processEnterEvent(this.list.getSelectedValue());
}
} else if (source == this.unlock) {
this.controller
.processUnlockEvent(this.passwordField.getPassword());
} else if (source == this.reset) {
this.controller.processResetEvent(this.resetField.getPassword());
} else if (source == this.buttonAddEnter) {
this.controller.processAddEvent(this.textField.getText(),
this.passwordFieldadd.getPassword());
//needs done in model
this.updateListModel();
}
this.setCursor(Cursor.getDefaultCursor());
}
@Override
public void updateListModel() {
//MOVE TO THE MODEL
String[] temp = this.getStore();
DefaultListModel<String> temp2 = new DefaultListModel<>();
for (int i = 0; i < temp.length; i++) {
temp2.addElement(temp[i]);
}
this.list.setModel(temp2);
}
@Override
public JTabbedPane getTabbedPane() {
return this.tabbedPane;
}
@Override
public void setTabbedPane(JTabbedPane tabbedPane) {
this.tabbedPane = tabbedPane;
}
@Override
public void updatePasswordField() {
this.passwordField.setText("");
}
@Override
public void updateResetPasswordDisplay() {
this.resetField.setText("");
}
@Override
public void displayWrongPass() {
JOptionPane.showMessageDialog(this, "Wrong password entered!");
}
@Override
public void displayUpdatedPass() {
JOptionPane.showMessageDialog(this, "Master password updated!");
}
@Override
public void updateResetButton(boolean result) {
this.reset.setEnabled(result);
}
@Override
public void updatePasswordDisplay(char[] password) {
StringBuilder passwordCreation = new StringBuilder();
for (int i = 0; i < password.length; i++) {
passwordCreation.append(password[i]);
}
this.passwordDisplay.setText(passwordCreation.toString());
}
@Override
public JComponent makeTextPanel(String text) {
// TODO Auto-generated method stub
return null;
}
@Override
public void valueChanged(ListSelectionEvent arg0) {
}
}
仅从学术的角度来看,我建议图形元素和下层数据模型之间的这种关系应该作为观察者模式来实现(https://en.wikipedia.org/wiki/Observer_pattern)。当您开始拥有 5 或 6 个 GUI 元素都对同一共享数据结构中的更改做出反应时,您向我们展示的方式可能很快就会变得混乱且难以维护。
您的构造函数调用了 makePasswordPanel(),其中包含以下行:
this.list = new JList<>(listContentC);
然后构造函数调用 makeAddPanel(),其中包含以下行:
this.list = new JList<>(listContentC);
现在您已经丢弃了第一个列表的句柄,并用对新列表的引用替换了它。然后在您的 updateListModel 中,更改 this.list 的模型(即 makeAddPanel 列表)。无法同时更新密码面板的模型,因为您已放弃对该面板的引用。
同样,要显示多个JList,都显示相同的内容,那么都应该共享相同的模型。如果这样做,那么对一个 JList 所做的更改将反映在所有其他 JList 中,因为更改实际上并不是对 JList 本身(它只显示模型的内容)而是对共享模型进行的。要理解这一点,您需要阅读 MVC 或模型-视图-控制器设计模式,因为 Swing 组件使用此的 变体 。
例如,请看下面的代码,我创建了 3 个 JPanel,每个都有自己的 JList,但它们都共享相同的 DefaultListModel<String>
。请注意,我的所有 3 个 JPanel 都从父级 class 扩展,该父级 class 实际持有 JList 并在其构造函数中接受模型。然后,如果我在一个 JPanel 中添加列表项或在另一个 JPanel 中删除它们,它们都会显示在 3 个 JPanel 的所有列表中。另请查看我如何将代码最小化以接近编译所需的最小代码,运行,并显示问题或解决方案,minimal code example program 或 MCVE:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class PanelsWithSharedList extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = 250;
private JTabbedPane tabbedPane = new JTabbedPane();
private DefaultListModel<String> listModel = new DefaultListModel<>();
public PanelsWithSharedList() {
for (int i = 0; i < 10; i++) {
listModel.addElement("List element " + (i + 1));
}
setLayout(new BorderLayout());
add(tabbedPane);
tabbedPane.add("Panel 1", new ListShowingPanel1(listModel));
tabbedPane.add("Panel 2", new ListShowingPanel2(listModel));
tabbedPane.add("Panel 3", new ListShowingPanel3(listModel));
}
@Override
public Dimension getPreferredSize() {
Dimension superSz = super.getPreferredSize();
if (isPreferredSizeSet()) {
return superSz;
}
int prefW = Math.max(superSz.width, PREF_W);
int prefH = Math.max(superSz.height, PREF_H);
return new Dimension(prefW, prefH);
}
private static void createAndShowGui() {
PanelsWithSharedList mainPanel = new PanelsWithSharedList();
JFrame frame = new JFrame("Panels With Shared List");
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());
}
}
@SuppressWarnings("serial")
abstract class AbstractListShowingPanel extends JPanel {
private JList<String> list;
public AbstractListShowingPanel(DefaultListModel<String> listModel) {
list = new JList<>(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
public JList<String> getList() {
return list;
}
public DefaultListModel<String> getModel() {
return (DefaultListModel<String>) list.getModel();
}
}
@SuppressWarnings("serial")
class ListShowingPanel1 extends AbstractListShowingPanel {
private JTextField textField = new JTextField(10);
public ListShowingPanel1(DefaultListModel<String> listModel) {
super(listModel);
add(new JScrollPane(getList()));
add(new JLabel("Text to add:"));
Action action = new AddTextAction();
textField.setAction(action);
add(textField);
add(new JButton(action));
}
private class AddTextAction extends AbstractAction {
public AddTextAction() {
super("Add Text");
putValue(MNEMONIC_KEY, KeyEvent.VK_A);
}
@Override
public void actionPerformed(ActionEvent e) {
getModel().addElement(textField.getText());
textField.selectAll();
}
}
}
@SuppressWarnings("serial")
class ListShowingPanel2 extends AbstractListShowingPanel {
public ListShowingPanel2(DefaultListModel<String> listModel) {
super(listModel);
add(new JScrollPane(getList()));
add(new JButton(new DeleteItemAction()));
}
private class DeleteItemAction extends AbstractAction {
public DeleteItemAction() {
super("Delete Selected Item");
putValue(MNEMONIC_KEY, KeyEvent.VK_D);
}
public void actionPerformed(ActionEvent e) {
JList<String> list = getList();
String selection = list.getSelectedValue();
if (selection != null) {
getModel().removeElement(selection);
}
}
}
}
@SuppressWarnings("serial")
class ListShowingPanel3 extends AbstractListShowingPanel {
public ListShowingPanel3(DefaultListModel<String> listModel) {
super(listModel);
setLayout(new BorderLayout());
add(new JScrollPane(getList()));
}
}