問題点
Javaでカレンダーを製作した際、GridLayoutでグリッド数を指定していても、2027年2月など特定年月ではレイアウトが崩れてしまいました。 発生する年月を調べたところ、どうやら1日が月曜日で、28日までしかない日で発生する。 この時28日は日曜日なので、必要な行数は曜日を出力する部分も含めると6(列数は曜日数の7で固定)だが、プログラムを実行すると、列が6で折り返され、6*6の形で出力される。・問題のコード
Test.java
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test extends JFrame {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("TEST");
frame.setSize(600, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(new TestPanel());
frame.setVisible(true);
}
}
class TestPanel extends JPanel implements ActionListener {
String[] week = {"Su","Mo","Tu","We","Th","Fr","Sa"};
JButton dayButton[];
JPanel datePanel;
int lastDay = 28;
TestPanel() {
dayButton = new JButton[lastDay+1];
this.setLayout(new GridLayout(6,7));
//カレンダーの曜日を出力
for (int i = 0; i < week.length; i++) {
this.add(new JLabel(week[i]));
}
//空白を出力
this.add(new JLabel(""));
//月の1日~最終日まで出力
for (int i = 1; i <= lastDay; i++) {
dayButton[i] = new JButton(String.valueOf(i));
dayButton[i].addActionListener(this);
dayButton[i].setContentAreaFilled(false);
this.add(dayButton[i]);
};
}
@Override
public void actionPerformed(ActionEvent e) {
for (int i = 1; i <= lastDay; i++) {
if (e.getSource() == dayButton[i]) {
System.out.println(i);
}
}
}
}
解決
調べたところ、GridLayoutは追加されたコンポーネントの数によって自動で行列数を変化させるとのこと。なので、setLayoutするときに、行数を指定せず(0,7)と記述し自動調整に任せたところ、うまく動作するようになりました。
this.setLayout(new GridLayout(0,7));
また、同様の事例が発生する条件を調べる。
・setLayout(new GridLayout(5,6)で、コンポーネント数が25のとき、実行時には5×5になる
・setLayout(new GridLayout(4,5)で、コンポーネント数が16のとき、実行時には4×4になる
・setLayout(new GridLayout(3,4)で、コンポーネント数が9のとき、実行時には3×3になる
…
どうも、GridLayoutの最終行のコンポーネント数が1つであり、行を一つ削除すると行数と列数が同値となる場合に、GridLayoutで行列を指定していても自動調整されるようです。