はのは、私は、Java SwingのGUIを構築しています、と私はボタンが含まれている別のパネルを含む、パネルが含まれているフレームを持っているとしましょう。 (パネルは再利用可能であると仮定し、私は個々のクラスにそれらを作りました。)子GUIコンポーネントはどのようにして(MVCを使用して)親にアクセスする必要がありますか?
Frame → FirstPanel → SecondPanel → Button
は、現実には、子どもたちの行はより複雑かもしれないが、私はちょうど簡単なこの例を維持したいです。私はボタンがその親要素の一つ(例えば、フレームのサイズを変更)を制御したい場合は
、必ずしも直接他の内部ではない2つのGUIクラス間の機能を実装するための最良の方法は何ですか?
getParent()
メソッドを一緒にストリング化するか、またはFrame
のインスタンスをその子孫まで一貫して通過させて、SecondPanel
からアクセスできるようにするのは嫌いです。基本的には、私のクラスをデイジーチェーン化する必要はありません。これは、ボタンがモデルと直接ではない親コンポーネントを更新する必要があるインスタンス
ですか?次に、親にモデルの変更が通知され、それに応じて更新されます。
私は一緒にコンパイルし、私の問題を説明するために自分自身で実行する必要があります少し例を入れています。これはJFrameの別のJPanelのJPanelの2つのJButtonです。ボタンは、JFrameのサイズを制御します。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MVCExample
{
public static void main(String[] args)
{
Model model = new Model();
Controller ctrl = new Controller();
ctrl.registerModel(model);
View view = new View(ctrl);
view.setVisible(true);
model.init();
}
/**
* Model class
*/
static class Model
{
private ArrayList<PropertyChangeListener> listeners =
new ArrayList<PropertyChangeListener>();
private Dimension windowSize;
public Dimension getWindowSize(){ return windowSize; }
public void setWindowSize(Dimension windowSize)
{
if(!windowSize.equals(getWindowSize()))
{
firePropertyChangeEvent(getWindowSize(), windowSize);
this.windowSize = windowSize;
}
}
public void init()
{
setWindowSize(new Dimension(400, 400));
}
public void addListener(PropertyChangeListener listener)
{
listeners.add(listener);
}
public void firePropertyChangeEvent(Object oldValue, Object newValue)
{
for(PropertyChangeListener listener : listeners)
{
listener.propertyChange(new PropertyChangeEvent(
this, null, oldValue, newValue));
}
}
}
/**
* Controller class
*/
static class Controller implements PropertyChangeListener
{
private Model model;
private View view;
public void registerModel(Model model)
{
this.model = model;
model.addListener(this);
}
public void registerView(View view)
{
this.view = view;
}
// Called from view
public void updateWindowSize(Dimension windowSize)
{
model.setWindowSize(windowSize);
}
// Called from model
public void propertyChange(PropertyChangeEvent pce)
{
view.processEvent(pce);
}
}
/**
* View classes
*/
static class View extends JFrame
{
public View(Controller ctrl)
{
super("JFrame");
ctrl.registerView(this);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().add(new FirstPanel(ctrl));
pack();
}
public void processEvent(PropertyChangeEvent pce)
{
setPreferredSize((Dimension)pce.getNewValue());
pack();
}
}
static class FirstPanel extends JPanel
{
public FirstPanel(Controller ctrl)
{
setBorder(BorderFactory.createTitledBorder(
BorderFactory.createLineBorder(
Color.RED, 2), "First Panel"));
add(new SecondPanel(ctrl));
}
}
static class SecondPanel extends JPanel
{
private Controller controller;
private JButton smallButton = new JButton("400x400");
private JButton largeButton = new JButton("800x800");
public SecondPanel(Controller ctrl)
{
this.controller = ctrl;
setBorder(BorderFactory.createTitledBorder(
BorderFactory.createLineBorder(
Color.BLUE, 2), "Second Panel"));
add(smallButton);
add(largeButton);
smallButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
controller.updateWindowSize(new Dimension(400, 400));
}
});
largeButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
controller.updateWindowSize(new Dimension(800, 800));
}
});
}
}
}
私が気に入らないのは、フレームがイベントを受信するためにフレームを登録できるように、コントローラがJFrameに存在する必要があるということです。しかしコントローラはパネルがモデルと通信できるように、SecondPanel(112行目、131行目、143行目)まで完全に渡す必要があります。
私はここで何か非効率的なことが起こっているように感じます(そして、クラスはあまりにも緊密に結合します)。私の問題が明確でない場合は教えてください。
これは興味深いアプローチです。私はもっと慎重に考えなければならないでしょう。 – Knave