Swing:GroupLayoutを簡単に作るためのビルダ
あまりにSwingのGroupLayoutがわかりにくいので、これを簡単にするためのビルダを作ってみた。
実行サンプル
まずは実行サンプルだ。
以下のようなコードで、
import javax.swing.*;
import javax.swing.GroupLayout.*;
public class GroupLayoutBuilderTest {
public static void main(String[]args) {
JFrame frame = new JFrame();
new GroupLayoutBuilder()
.addRow(Alignment.BASELINE, new JLabel("ユーザ名を入力"), null, new JTextField())
.addRow(Alignment.BASELINE, new JLabel("パスワード"), new JButton("詳細"), new JTextField(), new JLabel("test"))
.setColAlign(Alignment.TRAILING, Alignment.LEADING)
.build(frame.getContentPane());
frame.setBounds(200, 200, 400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
次の結果になる。
コード
本体コードは以下だ。
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.stream.*;
import javax.swing.*;
import javax.swing.GroupLayout.*;
/*
* {@link GroupLayout}を簡単に作るためのビルダ
*/
public class GroupLayoutBuilder {
/** 全行コンテナ */
private Rows rows = new Rows();
/** 列アラインメント */
private Aligns colAligns = new Aligns(Alignment.LEADING);
/** 各列アラインメントを指定する。指定の無いときは{@link Alignment.LEADING}になる。 */
public GroupLayoutBuilder setColAlign(Alignment...colAligns) {
this.colAligns = new Aligns(colAligns);
return this;
}
/** 行コンポーネントを追加する */
public GroupLayoutBuilder addRow(Component...cols) {
return addRow(Alignment.LEADING, cols);
}
/**
* 行アラインメント付きで行コンポーネントを追加する
* 上下に余裕がある場合に引き伸ばされたくない場合は{@link Alignment.BASELINE}
* を指定すること。
* @param align 行アラインメント
* @param cols 列コンポーネント
* @return 本オブジェクト
*/
public GroupLayoutBuilder addRow(Alignment align, Component...cols) {
rows.add(new Row(align, cols));
return this;
}
/* GroupLayoutのオプション */
private boolean autoCreateGaps = true;
private boolean autoCreateContainerGaps = true;
/**
* コンポーネント間のギャップを自動的に作成するか。デフォルトはtrue
* @param value コンポーネント間のギャップを自動的に作成するか
* @return 本オブジェクト
*/
public GroupLayoutBuilder setAutoCreateGaps(boolean value) {
this.autoCreateGaps = value;
return this;
}
/**
* 他のコンテナと、このコンテナのボーダーに接するコンポーネント間のギャップを、
* 自動的に作成するか。デフォルトはtrue
* @param value ギャップを自動的に作成するか
* @return 本オブジェクト
*/
public GroupLayoutBuilder setAutoCreateContainerGaps(boolean value) {
this.autoCreateContainerGaps = value;
return this;
}
/**
* ビルドする
* @param <T> ターゲットコンテナの型
* @param target ターゲットとするコンテナ
* @return ターゲットとするコンテナ
*/
public <T extends Container>T build(T target) {
// 各行を異なる列数にはできない。統一するために空のラベルを挿入
int maxColCount = rows.maxColCount();
rows.getRowStream().forEach(row->row.forceColCount(maxColCount));
// ターゲットに対するレイアウトを作成し、ターゲットに設定する
GroupLayout layout = new GroupLayout(target);
layout.setAutoCreateGaps(this.autoCreateGaps);
layout.setAutoCreateContainerGaps(this.autoCreateContainerGaps);
target.setLayout(layout);
// 垂直グループを作成する
makeVerticalGroup(layout);
// 水平グループを作成する
makeHorizontalGroup(layout);
return target;
}
/**
* 垂直グループを作成する
* @param layout
*/
void makeVerticalGroup(GroupLayout layout) {
// 垂直グループを作成し、レイアウトに設定
SequentialGroup rowSeq = layout.createSequentialGroup();
layout.setVerticalGroup(rowSeq);
// 各行について処理
rows.getRowStream().forEach(row-> {
ParallelGroup rowGroup = layout.createParallelGroup(row.align);
rowSeq.addGroup(rowGroup);
row.stream().forEach(c->rowGroup.addComponent(c));
});
}
/** 水平グループを作成する */
void makeHorizontalGroup(GroupLayout layout) {
// 水平グループを作成し、レイアウトに設定
SequentialGroup colSeq = layout.createSequentialGroup();
layout.setHorizontalGroup(colSeq);
int maxCols = rows.maxColCount();
IntStream.range(0, rows.maxColCount()).forEach(col-> {
ParallelGroup colGroup = layout.createParallelGroup(colAligns.get(col));
rows.getColStream(col).forEach(c-> {
colGroup.addComponent(c);
});
colSeq.addGroup(colGroup);
});
}
/** アラインメント */
static class Aligns {
Alignment defaultAlign;
List<Alignment>list = new ArrayList<>();
public Aligns(Alignment defaultAlign) {
this.defaultAlign = defaultAlign;
}
public Aligns(Alignment[]values) {
list = Arrays.stream(values).collect(Collectors.toList());
}
public Alignment get(int index) {
if (list.size() <= index) return Alignment.LEADING;
return list.get(index);
}
}
/** 全行コンテナ */
static class Rows {
List<Row>rows = new ArrayList<>();
/** 行を追加する */
void add(Row row) {
rows.add(row);
}
/** 指定列のセルストリームを取得する */
Stream<Component>getColStream(int colIndex) {
return rows.stream().map(row->row.get(colIndex));
}
/** 全行ストリームを取得する */
Stream<Row>getRowStream() {
return rows.stream();
}
/** 最大列数を取得する */
int maxColCount() {
return rows.stream().mapToInt(r->r.colCount()).max().getAsInt();
}
}
/** 行コンテナ */
static class Row {
Alignment align;
List<Component>cols;
/** 列コンポーネントを指定する。nullの部分には空のラベルを入れる */
Row(Alignment align, Component...cols) {
this.align = align;
this.cols = Arrays.stream(cols)
.map(c-> c == null? newEmpty():c)
.collect(Collectors.toList());
}
/** 列ストリームを取得する */
Stream<Component>stream() {
return cols.stream();
}
/** 指定列数に強制する */
void forceColCount(int colCount) {
while (cols.size() < colCount)
cols.add(newEmpty());
}
/** 列数 */
int colCount() {
return cols.size();
}
/** 指定列のコンポーネントを取得する */
Component get(int colIndex) {
if (cols.size() <= colIndex) return null;
return cols.get(colIndex);
}
private Component newEmpty() {
return new JLabel("");
}
}
}
ディスカッション
コメント一覧
まだ、コメントがありません