2016-08-17 3 views
0

私の最初の「パスワードボールト」タブでは、パスワードを保存する「ウェブサイト」のリストを持つJListがあります。 2番目のタブには「パスワード」機能が追加されています。パスワードを追加すると、JListはペインでのみ更新されます。もう一度他のタブ「パスワードボールト」に切り替えると、更新されていません。プログラムを再起動すると、更新されました。フィールドを使用するので、ローカル変数の問題ではありません。JListが別のペインで更新されない(Swing、Java)

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) { 

} 

} 
+2

[MCVE]を投稿したり、[:また私は、コンパイル、実行、および問題や解決策を示し、minimal code example programまたはMCVEするために必要な最小に近くなるようにコードを最小限に抑える方法をチェックしてくださいショート、自己包含、正しい例](http://www.sscce.org/)。 I. MCVE/SSCCEには、コンパイルに必要なインポート、それを実行する 'main(String [])'メソッド、そして問題を示すために明示的に必要とされないコードをすべて削除する必要があります。 –

+2

私はAndrewThompsonの提案を2番目に挙げます。私は、上記のエラーの明白な原因は見当たりません。そして、おそらく複数のPasswordManagerViewインスタンスを作成しているかもしれません。私たちの推測を避けるために、[mcve]または[sscce](http://sscce.org)を作成してください。 –

+1

面倒な点は、ヌルレイアウトを使用することです。ヌルレイアウトと 'setBounds()'はSwingの初心者にとっては複雑なGUIを作成する最も簡単で最良の方法のように思えるかもしれませんが、Swing GUIを使用すると、より多くの深刻な問題が発生します。 GUIのサイズが変更されたときにコンポーネントのサイズを変更することはありません。これらのコンポーネントは、拡張または維持するロイヤルウィジェットであり、スクロールペインに配置すると完全に失敗し、元のプラットフォームとは異なるすべてのプラットフォームまたは画面解像度で表示されます。 –

答えて

1

この場合も、すべて同じコンテンツを表示する複数のJListsを表示するには、すべて同じモデルを共有する必要があります。これを行うと、実際にJList自体(モデルのコンテンツのみを表示する)ではなく、共有モデルに変更が実際に加えられたため、あるJListに対する変更は他のすべてのJListに反映されます。これを理解するには、Swingコンポーネントがバリアントを使用しているので、MVCまたはModel-View-Controllerのデザインパターンを読みたいと思うでしょう。

たとえば、それぞれ独自のJListを持つ3つのJPanelを作成したが、それらのすべてが同じDefaultListModel<String>を共有しているコードをご覧ください。実際にJListを保持し、そのコンストラクタでモデルを受け入れる親クラスから3つのJPanelがすべて伸びていることに注意してください。次に、1つのJPanelにリスト項目を追加したり、別のJPanelでリスト項目を削除したりすると、それらはすべて3つのJPanelのすべてのリストに表示されます。 、早いほど良いのヘルプについて

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

ただ、ビューの学術的観点から、私はグラフィック要素とその下にあるデータモデル間の関係のこの種は、Observerパターン(https://en.wikipedia.org/wiki/Observer_pattern)として実施されるべきであることを示唆しています。 5つまたは6つのGUI要素がすべて同じ共有データ構造の変更に反応するようになると、すぐにわかりやすく維持しにくくなるかもしれません。

+0

私はコードでrepaint()を呼び出しましたが、どこに置くべきか分かりませんでした。私はそれをあなたの提案に従ってパネル作成に移しましたが、何もしませんでした。ロック解除イベントでupdateListModel()へのメソッド呼び出しを追加して「ロック解除」ボタンを押してリストモデルを更新しようとしましたが、驚いたことに実際にはリストを更新しませんでした – frillybob

+2

はい、再描画は悪い答え、その答えのセクションを削除してください。これは、既定モデルによって既に呼び出されているので、既定モデルを使用してコンポーネントを更新する場合には必要ありません。 –

4

あなたのコンストラクタは、このラインを持っているmakePasswordPanel()を呼び出します。

this.list = new JList<>(listContentC); 

コンストラクタは、この行があるmakeAddPanel()を呼び出します。だから今、あなたがハンドルを捨ててきた

this.list = new JList<>(listContentC); 

を最初のリストを新しいリストへの参照に置き換えます。次にupdateListModelで、this.listのモデルを変更します(これはmakeAddPanelリストです)。パネルへの参照を破棄したので、パスワードパネルのモデルも更新する方法はありません。

+0

良い目、よく目に付いた –

+0

ありがとう、今これを修正するための考えは、グローバルに初期化されたリストと呼ばれるフィールドを作成することです。しかし、私がそれを行うと、そのペインの最新の追加だけが実際にGUIに追加されます。それ以前のものはJListを持っていません。私はどのペインが最初に作成されるかを切り替えることでこれを確認しました。実際にJListを保持するJListを要求するのは、常に最後のペインです。それ以前のウィンドウにはウィンドウが1つもありません。 – frillybob

+1

@frillybob:yes複数のJListを作成しますが、すべてが共有する1つのモデルを作成します。繰り返しますが、将来は、投稿されたコードを簡素化して質問に答えるのを容易にするように努めなければなりません。私たちが主題にコメントしたリンクを読んで、あなたの将来の質問がそれほど難しくないようにしてください。 –

関連する問題