Java Swing Uygulamasında MVC Yapısını Kullanmak

06-01-2015

Java 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

© 2019 Tüm Hakları Saklıdır. Codesenior.COM