Swing: Membuat Layout Manager Sendiri


Pada saat masih bekerja dulu, saya ditugaskan sebagai programmer di sebuah proyek berbasis Applet (Swing). Dan layaknya sebagai programmer baru, saya banyak membuat tampilan form atau melakukan modifikasi minor pada form yang sudah dibuat programmer lain. Dan itu semua harus aku lakukan melalui coding, tanpa bantuan visual editor. Dapat dibayangkan betapa banyak waktu yang terbuang untuk men-kode GridBagLayout dan memodifikasi kode yang sudah ada. Salah satu solusi yang aku tempuh dikemudian hari adalah dengan membuat generator (masih bukan editorđŸ˜‰ berbasis template. Tapi aku merasa masih ada yang kurang, pasti ada cara yang lebih baik untuk menghasilkan kode program Swing yang simple dan mudah di-maintain. Dan mungkin saja, jika aku masih bekerja, aku akan mencoba membuat layout manager. Tampilan untuk aplikasi cenderung memiliki pola yang sama dan sederhana, lagipula applet akan jarang di-resize, sehingga mungkin membuat layout manager bisa menjadi sebuah solusi yang baik. Berikut ini adalah contoh sebuah layout manager sederhana:

package latihan;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager2;
import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class DialogLayout implements LayoutManager2 {

  public static enum FunctionalType  {
    LABEL, INPUT, BUTTON
  }
  
  private Map<Component, ComponentInfo> mapComponent;
  private int currentLinePosition;
  private FunctionalType lastFunctionalType;
    
  public DialogLayout() {
    mapComponent = new HashMap<Component,ComponentInfo>();
    currentLinePosition = 0;
    lastFunctionalType = null;
  }
  
  @Override
  public void addLayoutComponent(Component comp, Object constraints) {
    if (constraints instanceof FunctionalType) {
      if (lastFunctionalType==FunctionalType.INPUT) {
        currentLinePosition++;
      }
      ComponentInfo cInfo = new ComponentInfo(currentLinePosition, (FunctionalType) constraints);
      mapComponent.put(comp, cInfo);
      lastFunctionalType = cInfo.getFunctionalType();
    } else {
      throw new IllegalArgumentException("Constraints for DialogLayout must be FunctionalType");
    }
  }

  @Override
  public float getLayoutAlignmentX(Container target) {
    return 0;
  }

  @Override
  public float getLayoutAlignmentY(Container target) {
    return 0;
  }

  @Override
  public void invalidateLayout(Container target) {
  }

  @Override
  public Dimension maximumLayoutSize(Container target) {
    return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  }

  @Override
  public void addLayoutComponent(String name, Component comp) {
  }

  @Override
  public void layoutContainer(Container parent) {
    Component[] components = parent.getComponents();
    
    int totalWidth = parent.getWidth() - 15 ;
    int totalHeight = parent.getHeight();
    
    int labelLocation = 5;
    double labelWidth = 0.2 * totalWidth;
    
    int inputLocation = 5+(int)labelWidth+5;
    double inputWidth = 0.8 * totalWidth;
    
    Dimension size = new Dimension();
    Point location = new Point();
    int lineLocation;
    double preferredHeight = 20;
    
    // simpan Component yang berfungsi sebagai BUTTON untuk
    // diproses belakangan (sehingga bisa CENTER)
    List<Component> lstButtons = new ArrayList<Component>(); 
    int totalButtonsWidth = 0;
    int lineButtonsLocation = 0;
    
    for (Component c : components) {
      ComponentInfo cInfo = mapComponent.get(c);
      
        lineLocation = (int)(5 + cInfo.getLinePosition() * (preferredHeight+5)) ;
      
      if (cInfo.getFunctionalType()==FunctionalType.LABEL) {
        location.setLocation(labelLocation, lineLocation);
        size.setSize(labelWidth, preferredHeight);
      } else if (cInfo.getFunctionalType()==FunctionalType.INPUT) {
        location.setLocation(inputLocation, lineLocation);
        size.setSize(inputWidth, preferredHeight);
      } else if (cInfo.getFunctionalType()==FunctionalType.BUTTON) {
        lstButtons.add(c);
        totalButtonsWidth += c.getPreferredSize().getWidth();
        lineButtonsLocation = lineLocation;
      }
      
      c.setLocation(location);
      c.setSize(size);
      
    }
    
    int startLocation = (totalWidth - totalButtonsWidth)/2;
    
    for (Component c : lstButtons) {
      c.setSize(c.getPreferredSize());
      c.setLocation(startLocation, lineButtonsLocation);
      startLocation+=c.getPreferredSize().getWidth()+5;
    }
  }

  @Override
  public Dimension minimumLayoutSize(Container parent) {
    return new Dimension(500,500);
  }

  @Override
  public Dimension preferredLayoutSize(Container parent) {
    return new Dimension(500,500);
  }

  @Override
  public void removeLayoutComponent(Component comp) {
  }

  protected class ComponentInfo {
    private int linePosition;
    private FunctionalType functionalType;
    
    public ComponentInfo(int linePosition, FunctionalType type) {
      this.linePosition = linePosition;
      this.functionalType = type;
    }
    public int getLinePosition() {
      return linePosition;
    }
    public void setLinePosition(int linePosition) {
      this.linePosition = linePosition;
    }
    public FunctionalType getFunctionalType() {
      return functionalType;
    }
    public void setFunctionalType(FunctionalType functionalType) {
      this.functionalType = functionalType;
    }
  }
}
    

Untuk membuat tampilan form baru, seseorang hanya perlu memberikan kode seperti:

DialogLayout layout = new DialogLayout();
setLayout(layout);

add(lblNama, LABEL);
add(txtNama, INPUT);
add(lblAlamat, LABEL);
add(txtAlamat, INPUT);
add(lblTelepon, LABEL);
add(txtTelepon, INPUT);
add(btnTambah, BUTTON);
add(btnEdit, BUTTON);
add(btnHapus, BUTTON);
    

Kode program menjadi sangat sederhana dan mudah ditelurusi. Misalnya, aku bisa langsung tahu bahwa field Telepon akan ditampilkan setelah field Alamat dan sebelum kumpulan button. Selain itu, keuntungan lainnya adalah jika designer UI merasa ingin merubah peletakan dan jarak antar-komponen, programmer hanya perlu mengubah class DialogLayout saja, dan saat program dijalankan semua tampilan akan mengikuti perubahan tersebut.

Perihal Solid Snake
I'm nothing...

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: