Java Swing - Написание пользовательского интерфейса, который будет перекрашивать себя на основе изменений в пользовательском объекте данных - PullRequest
2 голосов
/ 19 марта 2012

Перво-наперво - я опубликовал вопрос ранее , в котором я попросил помощи о том, почему мой код не работает, и этот вопрос основан на совете, который я получил в этом вопросе.

Мой пример использования такой:

Я пишу модуль MethodEditor, где каждый Method обозначается пользовательским объектом данных, который имеет 2 члена данных -

  1. Список имен входных переменных
  2. Строка (имя переменной результата, которую устанавливает этот метод).

Эти Method объекты создаются в результатезаполнения некоторых данных в JDialog.
Эти Method объекты хранятся в контейнере, который имеет 1 элемент данных, который является List<Method>. Контейнер находится в контроллере JPanel, из которого вышеупомянутый JDialog вызывается.

С точки зрения пользовательского интерфейса я хочу отобразить каждый Method объект в виде кнопки J, при нажатии которой откроется JDialog и позволит пользователю редактировать его.

MethodEditor действует на Список и генерирует вертикальное расположение кнопок J, 1 для каждого Method в List<Method>.Это List<Method> передается в MethodEditor от вышеупомянутого контроллера JPane.

Я имел в своем предыдущем вопросе реализованный MethodEditor как JPanel, который добавитPropertyChangeListener до List<Method> и repaint сам бы каждый раз, когда происходило событие PropertyChange, но мой подход не работал, перерисовка не происходила.

Есть ли другой способ получить мое использованиеСлучай реализован или есть какое-то исправление, которое я мог бы сделать с моим кодом, опубликованным в предыдущем вопросе ?

Ответы [ 3 ]

3 голосов
/ 19 марта 2012

Ваша проблема уже упоминалась ранее, как и ее решение. Вы должны фактически добавить или удалить компонент на панель наблюдателя из 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<String> {
   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<String> modelNucleus = new ArrayList<String>();

   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<String> iterator() {
      return modelNucleus.iterator();
   }
}
3 голосов
/ 19 марта 2012

Я действительно потерян (из ваших последних трех вопросов),

может быть, мы можем представить, что у вас есть три отдельных Models для одного графического интерфейса, в этом случае не важно, если выхотите изменить количество элементов в графическом интерфейсе или изменить свойства для одного 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<Void, Void> swingworker = new SwingWorker<Void, Void>() {

            @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<Icon> iconQueue = new LinkedList<Icon>();
    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;
    }
}
0 голосов
/ 19 марта 2012

Пожалуйста, убедитесь, что PropertyChangeEvent не срабатывает. Если он срабатывает, но перерисовка не происходит, это может помочь отложить перерисовку примерно так:

//change this
button.repaint();

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

Если событие изменения не сработало - игнорируйте все после «Пожалуйста»;)

...