Java Swing Uygulamasında MVC Yapısını Kullanmak
06-01-2015Java swing uygulamalarında MVC yapısını kullanmak için genelde Observer tasarım deseni kullanılır. Swing kütüphanesi geliştirilirken MVC'nin farklı bir implementasyonu kullanılmıştır. Controller ile View tek bir sınıfta tutulurken, delegate olarak bilinir, Model ise ayrı bir sınıf tarafından temsil edilmiştir. Aşağıdaki listede bu mantıkla yaratılmış önemli sınıflar bulunmaktadır:
Component | Model Interface | Model Type |
JButton | ButtonModel | GUI |
JCheckBox | ButtonModel | GUI/data |
JRadioButton | ButtonModel | GUI/data |
JMenu | ButtonModel | GUI |
JMenuItem | ButtonModel | GUI |
JCheckBoxMenuItem | ButtonModel | GUI/data |
JRadioButtonMenuItem | ButtonModel | GUI/data |
Dikkat ederseniz bu tabloda Model Type sütünu bulunmaktadır. Bu sütundaki değerler GUI (UI), data ve bu ikisinin karışımı şeklinde ifade edilmiştir. MVC Swing'te bir model iki farklı türde olabilmektedir: UI-Model ve Data-Model.
GUI-Model: Bir Swing component'inin, örneğin JButton, durumunu temsil eder. Örneğin focus, enablement, selection vs. Bu türe örnek olarak tabloda görüldüğü gibi ButtonModel sınıfını söyleyebiliriz.
Data-Model: Swing elementlerinde gösterilecek veriyi temsil eder. Örneğin bir form uygulamasında kullanıcı kayıt işlemleri yapılıyor olsun. Textbox'lara girilen değerleri tutan User isminde bir sınıf yaratabiliriz. Bu sınıf data-model olur. Data-model, view component (örn JButton)'ine bağlı değildir. Bu sayede data-model sınıfını değiştirmeden bir başka view component ile kullanabiliriz.
Not: Swing uygulamaları geliştirirken MVC yapısını tam anlamıyla kullanabilmek zordur. Çünkü Swing kütüphanesi yukarıda belirtildiği gibi MVC yapısının modifiye edilmiş şeklini kullanmaktadır.
Not: MVC yapısında birden fazla View sınıfı bulunabilir. Buna karşın tek bir tane controller ve model bulunmalıdır.
Not: Bir uygulama birden fazla MVC yapısından oluşabilir.
Örnek Uygulama
JTable nesnesinin içeriğini scroll bar'ı aşağı kaydırdıkça güncelleyen bir uygulama tasarlayacağız.
Gerekli Sınıflar
Controller Sınıfı (TableController)
Model Sınıfı (TableModel)
View Sınıfı (TableView)
Initialize Sınıfı (RunProgram)
Dao Sınıfı (Article)
Main Sınıfı
TableModel Sınıfı
import javax.swing.*; import java.util.ArrayList; import java.util.List; import java.util.Observable; /** * Tabmodel is an observable class which notifies its observer objects * This class refers to MVC Model module. */ public class TableModel extends Observable { private List<Article> articleList; public void createArticleList(int firstResult, int maxResult) { List<Article> articleList=getArticleList(firstResult,maxResult); setChanged(); notifyObservers(articleList); } private List<Article> getArticleList(int firstResult,int maxResult){ int lastResult=firstResult+maxResult; if(lastResult>1000){ lastResult=1000; } return articleList.subList(firstResult,lastResult); } public void initArticleList(){ articleList=new ArrayList<Article>(); for(int i=0; i<1000; i++){ Article article=new Article(); article.setId(i); article.setTitle(i+ ". başlık"); article.seturl(i+". arama başlığı"); articleList.add(article); } } }
TableView Sınıfı
import javax.swing.*; import javax.swing.table.DefaultTableModel; import java.awt.*; import java.awt.event.AdjustmentListener; import java.util.*; import java.util.List; /** * TableView MVC'nin View modulunu temsil eder */ public class TableView extends JFrame implements Observer { private JTable table; private JScrollPane scrollPane; public TableView() { createTable(); } private void createTable() { Vector<String> columnNames = new Vector<String>(); columnNames.add("ID"); columnNames.add("TITLE"); columnNames.add("TITLE SEARCH"); tableModel.setColumnIdentifiers(columnNames); table = new JTable(tableModel); table.setAutoCreateRowSorter(true); table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width; table.getColumnModel().getColumn(0).setMaxWidth(50); scrollPane = new JScrollPane(table); add(scrollPane); setTitle("Article List"); setSize(screenWidth / 2, 600); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); } private void addRowsToTable(java.util.List<Article> articleList) { int i = getTableRowCount(); for (Article tempArticle : articleList) { Vector<String> vector = new Vector<String>(); vector.add(String.valueOf(tempArticle.getId())); vector.add(tempArticle.getTitle()); vector.add(tempArticle.geturl()); tableModel.insertRow(i, vector); i++; } } //Tabloda kac tane row varsa o sayiyi donderir public int getTableRowCount() { return tableModel.getRowCount(); } public void addScrollPaneAdjustmentListener(AdjustmentListener adjustmentListener) { scrollPane.getVerticalScrollBar().addAdjustmentListener(adjustmentListener); } public int getVisibleRowCount() { if (table != null) { Dimension paneSize = scrollPane.getSize(); return paneSize.height / table.getRowHeight(); } else { return 0; } } //instance table model DefaultTableModel tableModel = new DefaultTableModel() { @Override public boolean isCellEditable(int row, int column) { //all cells false return false; } }; @Override public void update(Observable o, Object arg) { if (o instanceof TableModel) { List<Article> articleList = (List<Article>) arg; addRowsToTable(articleList); } } }
TableController Sınıfı
import javax.swing.*; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; /** * TableController MVC'nin Controller modulunu temsil eder */ public class TableController { private TableView view; private TableModel model; public TableController(TableView view, TableModel model) { this.view = view; this.model = model; this.view.addScrollPaneAdjustmentListener(new ScrollPaneAdjustmentListener()); this.model.initArticleList(); //Ilk olarak 40 tane item gosterilmesi saglanir. 40 yerine dilediginiz ilk degeri verebilirsiniz this.model.createArticleList(0, 40); view.setVisible(true); } private class ScrollPaneAdjustmentListener implements AdjustmentListener { @Override public void adjustmentValueChanged(AdjustmentEvent e) { JScrollBar scrollBar = (JScrollBar) e.getAdjustable(); int extent = scrollBar.getModel().getExtent(); //Scrollbar en altta olup olmadigi kontrol edilir if (scrollBar.getValue() + extent == scrollBar.getMaximum()) { int maxResult = view.getVisibleRowCount(); int firstResult = view.getTableRowCount(); model.createArticleList(firstResult, maxResult); } } } }
RunProgram Sınıfı
/** * RunProgram sinifi MVC'i initialize eder */ public class RunProgram { public void start() { TableView view=new TableView(); TableModel model=new TableModel(); model.addObserver(view); TableController controller=new TableController(view,model); } }
Article Sınıfı
/** * Article sinifi */ public class Article { private int id; private String title; private String url; private String topic; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String geturl() { return url; } public void seturl(String url) { this.url = url; } public String getTopic() { return topic; } public void setTopic(String topic) { this.topic = topic; } }
Main Sınıfı
import javax.swing.*; /** * Main sinifi */ public class Main { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { RunProgram program=new RunProgram(); program.start(); } }); } }
Not: Buradaki Article sınıfı Model sınıfı içerisinde kullanılmaktadır ve ui-data'yı temsil etmektedir.
Sonuç
MVC ile uygulamalar geliştirirken farklı implemantasyonları kullanılabilmektedir. Biz bu uygulamamızda Model ve View'i Observer tasarım deseni aracılığı ile birbirinden bağımsız yapan şekli kullandık. Model ve View örnekte görüldüğü gibi Controller sınıfı aracılığı ile etkileşimde bulunurlar. Model veriyi güncelledikten sonra setChanged() metodu ve notifyObservers() metodunu kullanarak View sınıfını günceller. View sınıfı güncellenen veriyi almak için Observer interface'i içerisinde tanımlanmış olan update() metodunu kullanır, direkt etkileşim halinde olmazlar. Bu sayede model sınıfını dilediğimiz view sınıfları ile kullanabiliriz.
Bu konu ile ilgili detaylı bilgi için: http://www.codesenior.com/en/tutorial/Java-Swing-MVC-Usage
Uygulamayı indirmek için tıklayınız