2013-07-06 15 views
6

Başka bir GUI nesnesinin durumuna bağlı olarak diğer GUI nesnelerinin davranışını değiştirmek genellikle gereklidir. Örneğin. Bir düğmeye basıldığında, bir etiket ismini değiştirmelidir. Ancak, JButton myButton = new JButton(myButtonAction); gibi bir AbstractAction nesnesini kullandığımda, AbstractAction öğesinden devraldığı nesnede GUI nesnelerine başvuruma ihtiyacım var. GUI'de sadece AbstractAction nesnelerini oluşturmalı ve gerekli tüm GUI referanslarını AbstractAction nesnelerine aktarmalı mıyım yoksa kötü stil olarak kabul edilebilir mi?Java: Bir GUI bileşenlerini bir AbstractAction nesnesinden nasıl başvuruyorsunuz?

daha somut hale getirmek için:

// AbstractAction 
    public class MyAction extends AbstractAction { 
     public MyAction(String name, 
          String description, Integer mnemonic, JLabel) { 
      super(name); 
      putValue(SHORT_DESCRIPTION, description); 
      putValue(MNEMONIC_KEY, mnemonic); 
     } 
     public void actionPerformed(ActionEvent e) { 

       // do something  
      } 
     } 
    } 

public class GUI{ 
    public Action myAction = null; 

    public GUI(){  
     JLabel label = new JLabel("text"); 
     //This is not a good idea: 
     myAction = new MyAction("some text" , desc, new Integer(KeyEvent.VK_Q), label); 

     JButton myButton = new JButton(myAction); 
    } 
} 
+0

Başka bir örnek için yanıt vermek üzere düzenleme konusuna bakın. –

cevap

6

Sen mümkün olduğunca bağlantı gevşetmek istiyor, senin soru anlaşılacağı gibi sıkın ve bunu yapmak için, sana göre daha soyutlama yapması gerektiğini düşünüyorum bölümleri daha da tam teşekküllü bir MVC programına ayırmak. Daha sonra dinleyici (Eylem) modeli değiştirebilir ve GUI'niz olan görünüm modelin değişikliklerini dinleyebilir ve buna göre yanıt verebilir. Örneğin

:

import java.awt.BorderLayout; 
import java.awt.Component; 
import java.awt.Dimension; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 

import javax.swing.*; 
import javax.swing.event.SwingPropertyChangeSupport; 

public class MvcEg { 

    private static void createAndShowGui() { 
     View view = new MvcEgView(); 
     Model model = new MvcEgModel(); 
     new MvcEgControl(model, view); 

     JFrame frame = new JFrame("MvcEg"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(view.getMainPanel()); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowGui(); 
     } 
     }); 
    } 
} 

interface View { 

    void setMyButtonAction(Action action); 

    Component getMainPanel(); 

    void setStatusLabelText(String text); 

} 

@SuppressWarnings("serial") 
class MvcEgView implements View { 
    private static final int PREF_W = 500; 
    private static final int PREF_H = 400; 
    private static final String STATUS_TEXT = "Status: "; 
    private JPanel mainPanel = new JPanel() { 
     @Override 
     public Dimension getPreferredSize() { 
     return new Dimension(PREF_W, PREF_H); 
     } 
    }; 
    private JLabel statusLabel = new JLabel(STATUS_TEXT, SwingConstants.CENTER); 
    private JButton myButton = new JButton(); 

    public MvcEgView() { 
     JPanel btnPanel = new JPanel(new GridBagLayout()); 
     btnPanel.add(myButton); 

     mainPanel.setLayout(new BorderLayout()); 
     mainPanel.add(btnPanel, BorderLayout.CENTER); 
     mainPanel.add(statusLabel, BorderLayout.SOUTH); 
    } 

    @Override 
    public void setMyButtonAction(Action action) { 
     myButton.setAction(action); 
    } 

    @Override 
    public void setStatusLabelText(String text) { 
     statusLabel.setText(STATUS_TEXT + text); 
    } 

    @Override 
    public Component getMainPanel() { 
     return mainPanel; 
    } 
} 

interface Model { 
    public static final String MOD_FIVE_STATUS = "mod five status"; 

    void incrementStatus(); 

    ModFiveStatus getModFiveStatus(); 

    void removePropertyChangeListener(PropertyChangeListener listener); 

    void addPropertyChangeListener(PropertyChangeListener listener); 

    void setModFiveStatus(ModFiveStatus modFiveStatus); 

} 

class MvcEgModel implements Model { 
    private ModFiveStatus modFiveStatus = ModFiveStatus.ZERO; 
    private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
     this); 

    @Override 
    public void incrementStatus() { 
     int value = modFiveStatus.getValue(); 
     value++; 
     value %= ModFiveStatus.values().length; 
     setModFiveStatus(ModFiveStatus.getValuesStatus(value)); 
    } 

    @Override 
    public void setModFiveStatus(ModFiveStatus modFiveStatus) { 
     ModFiveStatus oldValue = this.modFiveStatus; 
     ModFiveStatus newValue = modFiveStatus; 
     this.modFiveStatus = modFiveStatus; 
     pcSupport.firePropertyChange(MOD_FIVE_STATUS, oldValue, newValue); 
    } 

    @Override 
    public ModFiveStatus getModFiveStatus() { 
     return modFiveStatus; 
    } 

    @Override 
    public void addPropertyChangeListener(PropertyChangeListener listener) { 
     pcSupport.addPropertyChangeListener(listener); 
    } 

    @Override 
    public void removePropertyChangeListener(PropertyChangeListener listener) { 
     pcSupport.removePropertyChangeListener(listener); 
    } 

} 

enum ModFiveStatus { 
    ZERO(0, "Zero"), ONE(1, "One"), TWO(2, "Two"), THREE(3, "Three"), FOUR(4, "Four"); 
    private int value; 
    private String text; 

    private ModFiveStatus(int value, String text) { 
     this.value = value; 
     this.text = text; 
    } 

    public int getValue() { 
     return value; 
    } 

    public String getText() { 
     return text; 
    } 

    public static ModFiveStatus getValuesStatus(int value) { 
     if (value < 0 || value >= values().length) { 
     throw new ArrayIndexOutOfBoundsException(value); 
     } 

     for (ModFiveStatus modFiveStatus : ModFiveStatus.values()) { 
     if (modFiveStatus.getValue() == value) { 
      return modFiveStatus; 
     } 
     } 
     // default that should never happen 
     return null; 
    } 

} 

@SuppressWarnings("serial") 
class MvcEgControl { 
    private Model model; 
    private View view; 

    public MvcEgControl(final Model model, final View view) { 
     this.model = model; 
     this.view = view; 

     view.setMyButtonAction(new MyButtonAction("My Button", KeyEvent.VK_B)); 
     view.setStatusLabelText(model.getModFiveStatus().getText()); 
     System.out.println("model's status: " + model.getModFiveStatus()); 
     System.out.println("model's status text: " + model.getModFiveStatus().getText()); 

     model.addPropertyChangeListener(new ModelListener()); 
    } 

    private class MyButtonAction extends AbstractAction { 


     public MyButtonAction(String text, int mnemonic) { 
     super(text); 
     putValue(MNEMONIC_KEY, mnemonic); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
     model.incrementStatus(); 
     System.out.println("button pressed"); 
     } 
    } 

    private class ModelListener implements PropertyChangeListener { 

     @Override 
     public void propertyChange(PropertyChangeEvent evt) { 
     if (evt.getPropertyName().equals(Model.MOD_FIVE_STATUS)) { 
      String status = model.getModFiveStatus().getText(); 
      view.setStatusLabelText(status); 
      System.out.println("status is: " + status); 
     } 
     } 

    } 

} 

zihnimde anahtar Modeli bakış hiçbir şey bilmiyor olması ve görünümü modeli hakkında çok az (burada hiçbir şey) bilir.

+0

Teşekkürler :-) Ancak, Observer ve PropertyChangeEvent sürümünün artılarını ve eksilerini değerlendiremiyorum. – user1812379

+0

'MyButtonAction'' model.incrementStatus() 'a erişimi olduğunu görüyorum, çünkü 'MyButtonAction' MvcEgControl' içinde bildirildi. Ama 'MyButtonAction' ayrı bir dosyada bildirilmişse bunu nasıl yaparsınız? O zaman modele nasıl erişirsiniz? – trusktr

+1

@trusktr: MyButtonAction öğesinin yapıcısına başka bir parametre, bir Model parametresi verebilir ve onu bir Model sınıfı alanı oluşturmak için kullanabilir ve böylece onun actionPerformed yöntemine genel Model yöntemlerini çağırmak için bir Model referansına izin verebilirsiniz. –

5

Hovercraft'ın önerdiği yaklaşımı güçlendirmek, düğmenizin ve etiketinizin ortak bir modele erişmesine izin verin. Düğmenin Action modeli güncelleştirir ve model, here numaralı hatlarda belirtildiği gibi PropertyChangeListener kullanarak dinleme etiketini bildirir. Swing text bileşenleri tarafından kullanılan ortak bir Document modelinde çalışan javax.swing.text.EditorKit somut uygulamalarında daha ayrıntılı bir örnek görülmektedir.

+0

Teşekkürler. MVC'yi biliyorum, ama uygulamaları güçlü bir şekilde değişebilen soyut bir kavram. MVC'nin bir anti-pattern olduğunu ve MVP'nin tercih edilmesi gerektiğini söyleyen insanlar bile var. Bunun kötü yanı, bunun kesin bir cevabı yok. Örneğimde, bir PropertyChangeListener bunu uygulamak için en kolay yol olurdu? Bazıları da gözlemcileri kullanır. – user1812379

+1

@ user1812379: Kullandığım anahtar, kullandığınız kesin model değil, ara yüzleri kullandığınız ve bağlantıyı en aza indirirken uyumu en üst düzeye çıkarmaya çalıştığınız anahtar. –

+1

Teşekkürler beyler. Benim sorunum bu soyut kavramı somut bir duruma uyarlamak. Belki de trashgod'un bana gösterdiği bu standart gözlemci yaklaşımıyla başlamalıyım. – user1812379

İlgili konular