Java Swing – 编写一个Ui,它将根据对自定义数据对象的更改重新绘制自身

首先要做的事情 – 我之前发过一个问题,其中我曾要求帮助解释为什么我的代码不能正常工作,而这个问题是根据我在该问题中得到的建议行事。

我的用例就是这个。

我正在编写一个MethodEditor模块,其中每个Method都由一个有2个数据成员的自定义数据对象表示 –

  1. 输入变量名称列表
  2. String(此方法设置的结果变量的名称)。

这些Method对象是在JDialog上填写一些数据的结果。
这些Method对象存储在一个容器中,该容器有一个数据成员,它是List容器驻留在一个控制器JPanel ,调用上述JDialog

从UI的角度来看,我想以Jbutton的forms显示每个Method对象,点击其中JDialog将打开并允许用户编辑它。

MethodEditor作用于List并为List每个Method生成一个MethodEditor的垂直排列,1。 该List从前面提到的控制器JPane传递给JPane

我在之前的问题中将MethodEditor实现为JPanel ,它将PropertyChangeListener添加到List并且每次有PropertyChange事件时都会自行repaint但我的方法不起作用,重绘不会发生。

有没有其他方法来实现我的用例,或者我可以对我之前的问题中发布的代码做什么修复?

之前已经提到过您的问题,因为它的解决方案。 您必须实际在PropertyChangeListener中向观察者面板添加或删除组件。 除非在调用这些方法之前明确地执行此操作,否则调用revalidate()repaint()不会神奇地添加或删除组件。

例如:

 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.GridLayout; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.IndexedPropertyChangeEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.swing.*; import javax.swing.event.SwingPropertyChangeSupport; public class ListenToTest { public static final String[] ITEMS = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; private JPanel mainPanel = new JPanel(); private ObserverPanel observerPanel = new ObserverPanel(); private ListenToModel model = new ListenToModel(); public ListenToTest() { observerPanel.setModel(model); for (String item : ITEMS) { model.addItem(item); } JPanel btnPanel = new JPanel(); btnPanel.add(new JButton(new AddAction("Add"))); btnPanel.add(new JButton(new RemoveAction("Remove"))); mainPanel.setLayout(new BorderLayout()); mainPanel.add(new JScrollPane(observerPanel.getMainComponent())); mainPanel.add(btnPanel, BorderLayout.PAGE_END); } public JComponent getMainComponent() { return mainPanel; } private class AddAction extends AbstractAction { public AddAction(String title) { super(title); } @Override public void actionPerformed(ActionEvent arg0) { String text = JOptionPane.showInputDialog(mainPanel, "Enter a String"); if (text != null) { model.addItem(text); } } } private class RemoveAction extends AbstractAction { public RemoveAction(String title) { super(title); } @Override public void actionPerformed(ActionEvent arg0) { int index = observerPanel.getSelectedIndex(); if (index >= 0) { model.removeItem(index); } } } private static void createAndShowGui() { ListenToTest mainPanel = new ListenToTest(); JFrame frame = new JFrame("ListenToModelTest"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(mainPanel.getMainComponent()); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); } } class ObserverPanel { public static final Font LABEL_FONT = new Font(Font.SANS_SERIF, Font.BOLD, 18); protected static final Color SELECTED_COLOR = new Color(150, 150, 255); private JPanel mainPanel = new JPanel(); private ListenToModel model; private GridLayout gridLayout = new GridLayout(0, 1); private int selectedIndex = -1; public ObserverPanel() { mainPanel.setLayout(gridLayout); mainPanel.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { Point p = e.getPoint(); Component[] components = mainPanel.getComponents(); for (int i = 0; i < components.length; i++) { if (mainPanel.getComponentAt(p).equals(components[i])) { selectedIndex = i; components[i].setBackground(SELECTED_COLOR); } else { components[i].setBackground(null); } } } }); } public int getSelectedIndex() { return selectedIndex; } public void setModel(ListenToModel model) { this.model = model; model.addPropertyChangeListener(new ObserverPanelListener()); } public JComponent getMainComponent() { return mainPanel; } private class ObserverPanelListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(ListenToModel.ADD)) { JLabel label = createLabel(evt); for (Component comp : mainPanel.getComponents()) { comp.setBackground(null); } int index = ((IndexedPropertyChangeEvent)evt).getIndex(); mainPanel.add(label, index); label.setBackground(SELECTED_COLOR); selectedIndex = index; } else if (evt.getPropertyName().equals(ListenToModel.REMOVE)) { int index = ((IndexedPropertyChangeEvent)evt).getIndex(); mainPanel.remove(index); for (Component comp : mainPanel.getComponents()) { comp.setBackground(null); } selectedIndex = -1; } else if (evt.getPropertyName().equals(ListenToModel.REMOVE_ALL)) { mainPanel.removeAll(); selectedIndex = -1; } mainPanel.revalidate(); mainPanel.repaint(); } private JLabel createLabel(PropertyChangeEvent evt) { String newValue = evt.getNewValue().toString(); JLabel label = new JLabel(newValue); label.setFont(LABEL_FONT); int eb = 20; label.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.blue), BorderFactory.createEmptyBorder(eb , eb, eb, eb))); label.setFocusable(true); label.setOpaque(true); return label; } } } class ListenToModel implements Iterable { public static final String ADD = "add"; public static final String REMOVE = "remove"; public static final String REMOVE_ALL = "remove all"; private SwingPropertyChangeSupport spcSupport = new SwingPropertyChangeSupport( this); private List modelNucleus = new ArrayList(); public void addItem(String item) { modelNucleus.add(item); spcSupport.fireIndexedPropertyChange(ADD, modelNucleus.size() - 1, null, item); } public void addItem(int index, String item) { if (index < 0 || index > modelNucleus.size()) { // TODO: throw an exception } else { modelNucleus.add(index, item); spcSupport.fireIndexedPropertyChange(REMOVE, index, null, item); } } public void removeItem(int index) { if (index < 0 || index >= modelNucleus.size()) { // TODO: throw an exception } else { String oldValue = modelNucleus.remove(index); spcSupport.fireIndexedPropertyChange(REMOVE, index, oldValue, null); } } public void removeAll() { modelNucleus.clear(); spcSupport.firePropertyChange(REMOVE_ALL, null, null); } public void addPropertyChangeListener(PropertyChangeListener listener) { spcSupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { spcSupport.removePropertyChangeListener(listener); } @Override public Iterator iterator() { return modelNucleus.iterator(); } } 

我真的输了(从你最后三个问题),

也许,我们可以想象你有一个GUI有三个独立的Models ,在这种情况下,如果你想改变GUI中的元素数量,或者更改一个JComponent属性,这并不重要,

PropertyChangeListener输出可以很好地保证输出可以在EDT上完成

 import java.awt.BorderLayout; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.LinkedList; import java.util.Queue; import javax.swing.*; public class MVC_ProgressBarThread { private MVC_ProgressBarThread() { MVC_View view = new MVC_View(); MVC_Model model = new MVC_Model(); MVC_Control control = new MVC_Control(view, model); view.setControl(control); JFrame frame = new JFrame("MVC_ProgressBarThread"); frame.getContentPane().add(view); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { MVC_ProgressBarThread mVC_ProgressBarThread = new MVC_ProgressBarThread(); } }); } } class MVC_View extends JPanel { private static final long serialVersionUID = 1L; private MVC_Control control; private JProgressBar progressBar = new JProgressBar(); private JButton startActionButton = new JButton("Press Me and Run this Madness"); private JLabel myLabel = new JLabel("Nothing Special"); public MVC_View() { startActionButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { buttonActionPerformed(); } }); JPanel buttonPanel = new JPanel(); startActionButton.setFocusPainted(false); buttonPanel.add(startActionButton); setLayout(new BorderLayout(10, 10)); add(buttonPanel, BorderLayout.NORTH); progressBar.setStringPainted(true); add(progressBar, BorderLayout.CENTER); myLabel.setIcon(UIManager.getIcon("OptionPane.questionIcon")); myLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); add(myLabel, BorderLayout.SOUTH); } public void setControl(MVC_Control control) { this.control = control; } private void buttonActionPerformed() { if (control != null) { control.doButtonAction(); } } public void setProgress(int progress) { progressBar.setValue(progress); } public void setProgressLabel(String label) { progressBar.setString(label); } public void setIconLabel(Icon icon) { myLabel.setIcon(icon); } public void start() { startActionButton.setEnabled(false); } public void done() { startActionButton.setEnabled(true); setProgress(100); setProgressLabel(" Done !!! "); setIconLabel(null); } } class MVC_Control { private MVC_View view; private MVC_Model model; public MVC_Control(final MVC_View view, final MVC_Model model) { this.view = view; this.model = model; model.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent pce) { if (MVC_Model.PROGRESS.equals(pce.getPropertyName())) { view.setProgress((Integer) pce.getNewValue()); } if (MVC_Model.PROGRESS1.equals(pce.getPropertyName())) { view.setProgressLabel((String) pce.getNewValue()); } if (MVC_Model.PROGRESS2.equals(pce.getPropertyName())) { view.setIconLabel((Icon) pce.getNewValue()); } } }); } public void doButtonAction() { view.start(); SwingWorker swingworker = new SwingWorker() { @Override protected Void doInBackground() throws Exception { model.reset(); model.startSearch(); return null; } @Override protected void done() { view.done(); } }; swingworker.execute(); } } class MVC_Model { public static final String PROGRESS = "progress"; public static final String PROGRESS1 = "progress1"; public static final String PROGRESS2 = "progress2"; private static final int MAX = 11; private static final long SLEEP_DELAY = 1000; private int progress = 0; private String label = "Start"; private PropertyChangeSupport pcs = new PropertyChangeSupport(this); private PropertyChangeSupport pcs1 = new PropertyChangeSupport(this); private PropertyChangeSupport pcs2 = new PropertyChangeSupport(this); private final String[] petStrings = {"Bird", "Cat", "Dog", "Rabbit", "Pig", "Fish", "Horse", "Cow", "Bee", "Skunk"}; private int index = 1; private Queue iconQueue = new LinkedList(); private Icon icon = (UIManager.getIcon("OptionPane.questionIcon")); public void setProgress(int progress) { int oldProgress = this.progress; this.progress = progress; PropertyChangeEvent evt = new PropertyChangeEvent(this, PROGRESS, oldProgress, progress); pcs.firePropertyChange(evt); } public void setProgressLabel(String label) { String oldString = this.label; this.label = label; PropertyChangeEvent evt = new PropertyChangeEvent(this, PROGRESS1, oldString, label); pcs1.firePropertyChange(evt); } public void setIconLabel(Icon icon) { Icon oldIcon = this.icon; this.icon = icon; PropertyChangeEvent evt = new PropertyChangeEvent(this, PROGRESS2, oldIcon, icon); pcs2.firePropertyChange(evt); } public void reset() { setProgress(0); } public void addPropertyChangeListener(PropertyChangeListener listener) { pcs.addPropertyChangeListener(listener); pcs1.addPropertyChangeListener(listener); pcs2.addPropertyChangeListener(listener); } public void startSearch() { iconQueue.add(UIManager.getIcon("OptionPane.errorIcon")); iconQueue.add(UIManager.getIcon("OptionPane.informationIcon")); iconQueue.add(UIManager.getIcon("OptionPane.warningIcon")); iconQueue.add(UIManager.getIcon("OptionPane.questionIcon")); for (int i = 0; i < MAX; i++) { int newValue = (100 * i) / MAX; setProgress(newValue); setProgressLabel(petStrings[index]); index = (index + 1) % petStrings.length; setIconLabel(nextIcon()); try { Thread.sleep(SLEEP_DELAY); } catch (InterruptedException e) { } } } private Icon nextIcon() { Icon icon1 = iconQueue.peek(); iconQueue.add(iconQueue.remove()); return icon1; } } 

请validationPropertyChangeEvent是否不会触发。 如果它确实触发,但重绘不会发生,可能有助于推迟重绘有点像这样:

 //change this button.repaint(); // to this SwingUtilties.invokeLater(new Runnable() { public void run() { button.repaint(); }}); 

如果更改事件没有触发 – 请忽略所有’请’;)