FixedRowColumn付きのFlexGridTableをJavaで作成する

 昔VisualBasic6.0にMSFlexGrid、MSHFlexGridなるコンポーネントがありました。エクセルとアクセスの中間のような仕事に使える便利なツールでしたが、その後のバージョンアップで残念ながらサポートされなくなりました。困った私はJavaで自作できないかと、いろいろ本を探し「Java Gui プログラミングVol.Ⅱ」（大村 忠史 著、カットシステム発行）と出会いました。それを元に固定行・固定列を持つグリッドテーブルを自作しました。最近、ネット上で同様なものを見つけ、感慨深いです。http://www.java2s.com/Code/Java/Swing-Components/FixedTableColumnExample.htm
　今一度自分なりに整理しなおしてみようと思いました。以下はEclipseを使用しています。
０．先ずは初歩ですみません。ウインドウを一つ作成します。
```HFlexGridExample00.java
import javax.swing.JFrame;
class HFlexGridExample00 extends JFrame {
	public static void main(String[] args) {
	    JFrame frame = new HFlexGridExample00("HFlexGridExample00");
	    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
	    frame.setSize(400, 100);
	    frame.setVisible(true);
	}
	HFlexGridExample00(String title) {
	    super(title);
	}
}
```
![fgrid00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3189926/1957f1b9-b6b5-7d66-fd7c-058e3046ce1c.jpeg)
１．次にJTAbleをJScrollPaneに入れ、そのJScrollPaneを乗せます。スクロールバーが現れます。
```
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
class HFlexGridExample01 extends JFrame {
	public static void main(String[] args) {
    	JFrame frame = new 
        HFlexGridExample01("HFlexGridExample01");
	    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
	    frame.setSize(400, 150);
	    frame.setVisible(true);
	}
	
	HFlexGridExample01(String title) {
	    super(title);
	    JTable jt = new JTable(5,7);
	    JScrollPane jsp = new JScrollPane(jt);	// ScrollPaneを作成し、その中に
	    getContentPane().add(jsp);				// jtを収めると以下のことができる
	    								// 単純に getContentPane().add(jt); ではできない	
	    String[] header1 = { "氏名","〒","県","市","備考"};		// これをしないと
	    for(int i=0; i<5; i++) {								// Headerは自動的に
	    	TableColumn col = jt.getColumnModel().getColumn(i);	// A,B,C,D,E,F
	    	col.setHeaderValue(header1[i]);						// となる。
	    }
	    jt.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);		// 縦・横スクロールバーが現れる。
	}
}
```
![fgrid01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3189926/fcc1e620-cff5-96f4-36b7-e591ae24dc2e.jpeg)
２．自由な位置に置けるようにし、少し小さくして内部に収めます。
```HFlexGridExample02.java
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
class HFlexGridExample02 extends JFrame {
	JPanel contentPane, wpane;
	public static void main(String[] args) {
	    JFrame frame = new HFlexGridExample02("HFlexGridExample02");
	    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
	    frame.setSize(400, 150);
	    frame.setVisible(true);
	}
	
	HFlexGridExample02(String title) {
	    super(title);
	    JTable jt = new JTable(5,7);
	    JScrollPane jsp = new JScrollPane(jt);
	    contentPane = (JPanel) getContentPane();
	    contentPane.add(jsp);				// ウィンドウと一体化して分かり辛いので、
	    contentPane.setLayout(null);		// 自由な位置に置けるようにして
	    jsp.setBounds(10, 10, 365, 90);		// 少し小さくして内部に収めた。
	    String[] header1 = { "氏名","〒","県","市","備考"};		// これをしないと
	    for(int i=0; i<5; i++) {								// Headerは自動的に
	    	TableColumn col = jt.getColumnModel().getColumn(i);	// A,B,C,D,E,F,G
	    	col.setHeaderValue(header1[i]);						// となる。
	    }
	    jt.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
	}
}
```
![fgrid02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3189926/4e4e8e40-1a54-a211-2ad5-0207d6a537ca.jpeg)
３．自作のkmgridを使います。直におきます。以下、KMGrid.javaは同じなので省略します。
```HFlexGridExample03.java
import javax.swing.JFrame;
import javax.swing.JPanel;

class HFlexGridExample03 extends JFrame {
	JPanel contentPane, wpane;
	KMGrid kmgrid;
	public static void main(String[] args) {
	    JFrame frame = new HFlexGridExample03("HFlexGridExample03");
	    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
	    frame.setSize(600, 400);
	    frame.setVisible(true);
	}
	
	HFlexGridExample03(String title) {
	    super(title);    
	    kmgrid = new KMGrid(558, 16 + 149 + 16 * 10);// 特注のTableGrid
	    contentPane = (JPanel) getContentPane();
	    contentPane.add(kmgrid);			// ウィンドウと一体化して分かり辛いので、
	    contentPane.setLayout(null);		// 自由な位置に置けるようにして
	    kmgrid.setBounds(10, 10, 560, 336);	// 少し小さくして内部に納めた。
	}
}
```
```KMGrid.java
import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;

import javax.swing.ImageIcon;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

public class KMGrid extends JTextArea {		// implements ChangeListener, PropertyChangeListener
	JScrollPane scrpnw,scrpn,scrpm;
	JTable jtnw,jtn,jtw,jtm;
	DefaultTableColumnModel cmodelnw,cmodeln,cmodelw;
	int fcols=3, FColWidth[] ={22,109,30};	// 左側の固定列は3列としその幅
	int frows=2, FRowHeight[]={22,149};		// 上側の固定行は2行としその高さ
	int MainCols=12;						// = MainCols
	int FColsW,FRowsH;						// 固定行や列の全体の幅と高さ
	int MainRows;
	//String str;
	DefaultTableModel tmodelNW;
	String[] nwCName={"0","1","2"};			// 何でもよい。fcols=3個分取敢えず与える
	Object[] nwData0={"0",new ImageIcon("kmg01.jpg"),"2"};	// 0行1列にjpg画像を設定。
	Object[] nwData1={new ImageIcon("kmg10.png"),new ImageIcon("kmg11.png"),new ImageIcon("kmg12.gif")};
    					// 1行目に3個のpng,gif画像を設定する。
	
	public KMGrid(int GWidth,int GHeight){
		MainRows=10;												// 初期値は1で、実行時に再設定ができる	
		
		FColsW=0;for(int i=0;i<fcols;i++){FColsW +=FColWidth[i];}	// 固定各列幅を足して算出
		FRowsH=0;for(int i=0;i<frows;i++){FRowsH +=FRowHeight[i];}	// 固定各行高を足して算出

		jtnw=new JTable();									// NorthWest 左上角のFixedTable
		jtnw.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);	// 固定部分なので変更できないように
		jtnw.setEnabled(false);								// 編集不可に
		jtnw.setShowGrid(false);							// 画像で設定するので見えないように
		tmodelNW=new NWTablemodel(nwCName,0);				// Defaultからの特注TableModel
		jtnw.setModel(tmodelNW);							// まず空のTableModelを与えておいて
		tmodelNW.addRow(nwData0);							// 固定行0列目を加えて、データを設定
		tmodelNW.addRow(nwData1);							// 固定行1列目　〃
		for(int i=0;i<frows;i++){jtnw.setRowHeight(i,FRowHeight[i]);}// 固定行0,1の高さをセット		
		cmodelnw=(DefaultTableColumnModel)jtnw.getColumnModel();	 // defaultの固定列モデルをゲット
		for(int i=0;i<fcols;i++){					// 各固定列の幅を設定。不要かもだが1ピクセル調整。
			TableColumn colnw=cmodelnw.getColumn(i);
			if(i==0){
				colnw.setMaxWidth(FColWidth[i]+1);colnw.setMinWidth(FColWidth[i]+1);colnw.setWidth(FColWidth[i]+1);
			}else if(i==fcols-1){
				colnw.setMaxWidth(FColWidth[i]-1);colnw.setMinWidth(FColWidth[i]-1);colnw.setWidth(FColWidth[i]-1);
			}else{
				colnw.setMaxWidth(FColWidth[i]);  colnw.setMinWidth(FColWidth[i]);  colnw.setWidth(FColWidth[i]);
			}
		}
		scrpnw=new JScrollPane(jtnw){ 									// NorthWest 左上のScrollPaneに収める
			@Override public void setColumnHeaderView(Component view) {}
		};//*work around setColumnHeader(null);
		scrpnw.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);	// スクロールバー消す
		scrpnw.setVerticalScrollBarPolicy  (JScrollPane.VERTICAL_SCROLLBAR_NEVER);
		add(scrpnw);	// 左上角の部分の設定終了

		jtn=new JTable(frows,MainCols);jtn.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);	// North 上の固定部分
		jtn.setEnabled(false);
		for(int i=0;i<frows;i++){jtn.setRowHeight(i,FRowHeight[i]);}
		cmodeln =(DefaultTableColumnModel)jtn.getColumnModel(); 					// NorthのTableColumnModel
		for(int i=0;i<MainCols;i++){
			TableColumn coln=cmodeln.getColumn(i);
			coln.setCellRenderer(new FixColHeaderRenderer());			
		}
		scrpn=new JScrollPane(jtn){ 													// ScrollPaneに収める
			@Override public void setColumnHeaderView(Component view) {}
		};// work around setColumnHeader(null);
		scrpn.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);	// スクロールバー消す
		scrpn.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
		add(scrpn);		// this.add(scrpn)

		jtm=new JTable(MainRows,MainCols);									// MainTable 真ん中の部分
		jtm.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		jtm.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		jtm.setColumnSelectionAllowed(true);
		jtm.setSelectionBackground(Color.pink);						// 選んだセルはピンクで見易くハイライト
		scrpm=new JScrollPane(jtm){
			@Override public void setColumnHeaderView(Component view) {}
		}; // work around setColumnHeader(null);
		scrpm.setBackground(Color.darkGray);
		scrpm.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		scrpm.setVerticalScrollBarPolicy(  JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		scrpm.getVerticalScrollBar().setBackground(Color.darkGray);
		add(scrpm);															// this.add(scrpm)

		jtw=new JTable(MainRows,fcols);										// West 左のFix部分
		jtw.setAutoCreateColumnsFromModel(false);		
		jtw.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		cmodelw =(DefaultTableColumnModel)jtw.getColumnModel();
		for(int i=0;i<fcols;i++){											// fixedColumn0,1,2の設定
			TableColumn colw=cmodelw.getColumn(i);
			colw.setMaxWidth(FColWidth[i]); colw.setMinWidth(FColWidth[i]);colw.setWidth(FColWidth[i]);
			if(i==1){colw.setCellRenderer(new ColStrRenderer());
			}else{   colw.setCellRenderer(new ColNumRenderer());}
		}
		jtw.setEnabled(false);
		jtw.setPreferredScrollableViewportSize(jtw.getPreferredSize());
		
		scrpm.setRowHeaderView(jtw);
		
		JScrollBar hbar = scrpm.getHorizontalScrollBar();
		hbar.setBackground(Color.darkGray);
		syncScrollingH(scrpn,scrpm,hbar);							// NorthとMainの横スクロールシンクロ

		scrpnw.setBounds(0,0,FColsW+2,FRowsH+2);
		scrpn.setBounds(FColsW,0,GWidth-FColsW-15,FRowsH+2);
		scrpm.setBounds(0,FRowsH+2,GWidth+1,GHeight-FRowsH+1);
	}// kmgrid Main

	private void syncScrollingH(
			final JScrollPane northScrollPane,
			final JScrollPane mainScrollPane,
			final JScrollBar  horizontalScrollBar)
	{
		// When the horizontalBar value changes, change the position of the view in the centerScrollPane to match.
		horizontalScrollBar.addAdjustmentListener(new AdjustmentListener() {
			public void adjustmentValueChanged(AdjustmentEvent e) {
				JViewport viewport = northScrollPane.getViewport();
				viewport.setViewPosition(new Point(e.getValue(), viewport.getViewPosition().y));
				viewport = mainScrollPane.getViewport();
				viewport.setViewPosition(new Point(e.getValue(), viewport.getViewPosition().y));}});
	}

	class NWTablemodel extends DefaultTableModel{
		NWTablemodel(String[] colNames,int row){super(colNames,row);}
		@SuppressWarnings({ "unchecked", "rawtypes" })
		@Override
		public Class getColumnClass(int col){return getValueAt(1,col).getClass();}
		@Override
		public boolean isCellEditable(int row,int col){return false;}
	}

	class FixColHeaderRenderer extends DefaultTableCellRenderer{
		@Override
		public Component getTableCellRendererComponent(
				JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int col)
		{
			setText((String)value);
			setLineWrap(true);
			setWrapStyleWord(true);
			if(row==0){setVerticalAlignment(SwingConstants.CENTER);}
			if(row==1){setVerticalAlignment(SwingConstants.TOP);}
			if(col<3){		setBackground(new Color(255,255,255));
			}else if(col<6){setBackground(new Color(210,255,240));
			}else if(col<9){setBackground(new Color(165,255,225));
			}else{			setBackground(new Color(120,255,200));
			}
			return(this);
		}
	}

	class ColStrRenderer extends DefaultTableCellRenderer{
		@Override
		public Component getTableCellRendererComponent
		(JTable table,Object value,boolean isSelected,boolean hasFocus,
				int row,int col){
			setValue(value);
			setHorizontalAlignment(SwingConstants.LEFT);
			if((row%2)==1){setBackground(new Color(180,230,250));}else{setBackground(Color.white);}
			return(this);
		}
	}

	class ColNumRenderer extends DefaultTableCellRenderer{
		@Override
		public Component getTableCellRendererComponent(
				JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int col)
		{
			setValue(value);
			setHorizontalAlignment(SwingConstants.RIGHT);
			if((row%2)==1){setBackground(new Color(180,230,250));}else{setBackground(Color.white);}
			return(this);
		}
	}
}
```
![fgrid03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3189926/fbdfc725-ac21-275d-23c2-cafd8f723525.jpeg)
４．一度KMGridをJSCrollPaneに入れてそれを乗せてみます。　スクロールバーは現れますが働きません。
```HFlexGridExample04.java
import java.awt.Cursor;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

class HFlexGridExample04 extends JFrame {
	JPanel contentPane, wpane;
	KMGrid kmgrid;
	public static void main(String[] args) {
	    JFrame frame = new HFlexGridExample04("HFlexGridExample04");
	    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
	    frame.setSize(600, 400);
	    frame.setVisible(true);
	}
	
	HFlexGridExample04(String title) {
	    super(title);    
	    kmgrid = new KMGrid(546, 16 + 149 + 16 * 10);	// 特注のTableGrid
	    kmgrid.jtm.setCursor(new Cursor(Cursor.HAND_CURSOR));	
	    				// kmgridの編集可能なjtmにハンドカーソル
	    JScrollPane jsp = new JScrollPane(kmgrid);	// ScrollPaneを作成し、その中に
	    contentPane = (JPanel) getContentPane();
	    contentPane.add(jsp);				// ウィンドウと一体化して分かり辛いので、	    
	    contentPane.setLayout(null);		// 自由な位置に置けるようにして
	    jsp.setBounds(10, 10, 560, 340);	// 少し小さくして内部に納めた。
	    jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
	    jsp.setVerticalScrollBarPolicy(  JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
	    // スクロールバーが現れても働かない。
	}
}
```
![fgrid04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3189926/2eccedb2-281c-b367-68e7-b9a934902c95.jpeg)
５．また３のようにKMGridを直に置きます。更にkmGridSet()を追加し、実行時に固定部分のデータを表示させてみました。
```HFlexGridExample05.java
import java.awt.Cursor;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

class HFlexGridExample05 extends JFrame {
	JPanel contentPane, wpane;
	int MainCols;
	int MainColsFrac;
	int Clust;
	int MainRows;
	int MainColWidth;
	KMGrid kmgrid;
	String kmwColName[],kmmColName[],kmmFileExist[][];
	DefaultTableModel kmmModel, kmwModel, jtModel;
	DefaultTableColumnModel cmodelhk,cmodelj,kmcmodeln,kmcmodelm,kmcmodelw;
	public static void main(String[] args) {
	    JFrame frame = new HFlexGridExample05("HFlexGridExample05");
	    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
	    frame.setSize(600, 400);
	    frame.setVisible(true);
	}
	
	HFlexGridExample05(String title) {
	    super(title);    
	    kmgrid = new KMGrid(547, 16 + 149 + 16 * 10);	// 特注のTableGrid
	    kmgrid.jtm.setCursor(new Cursor(Cursor.HAND_CURSOR));	
	    			// 単なる修飾だが、kmgridの編集可能なjtmではハンドカーソルにしてみた。
		kmGridSet();
	    JScrollPane jsp = new JScrollPane(kmgrid);	// ScrollPaneを作成し、その中に
	    contentPane = (JPanel) getContentPane();
	    contentPane.add(jsp);					// ウィンドウと一体化して分かり辛いので、	    
	    contentPane.setLayout(null);			// 自由な位置に置けるようにして
	    jsp.setBounds(10, 10, 560, 340);		// 少し小さくして内部に納めた。
	    jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
	    jsp.setVerticalScrollBarPolicy(  JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
	    // スクロールバーが現れても働かない。
	}
	
	private void kmGridSet(){
		// 実行時に別々のファイルを読み込んで指定できるということ
		MainCols=12;
		MainColsFrac=4;
		Clust=3;		// MainCols/MainColsFrac;
		MainRows=10;
		MainColWidth = 50;
		// --------------------------------------------------
		
		String[][] koumoku = new String[MainRows][3];
		for(int i=0;i<MainRows;i++) {
			koumoku[i][0]= Integer.toString(i+1);
			koumoku[i][1]= "項目"+ (i + 1) ;// 上と違い何故かこれは通る
			koumoku[i][2]= i + 1 + "2";
		}
		String[] kmwColName = new String[3];// 空で構わない
		kmwModel = new DefaultTableModel(koumoku, kmwColName) {
			@Override public boolean isCellEditable(int row, int col) { return false; }
		};
		kmgrid.jtw.setModel(kmwModel);
		
		kmmFileExist = new String[MainRows][MainCols];               
		kmmColName = new String[MainCols];
		kmmModel = new DefaultTableModel(kmmFileExist, kmmColName) {
			@Override public boolean isCellEditable(int row, int col) { return true; }
		};
		kmgrid.jtm.setModel(kmmModel);

		kmcmodelw = (DefaultTableColumnModel) kmgrid.jtw.getColumnModel();
		kmcmodeln = (DefaultTableColumnModel) kmgrid.jtn.getColumnModel();
		kmcmodelm = (DefaultTableColumnModel) kmgrid.jtm.getColumnModel();
		String str;
		for(int i=0;i<MainCols;i++){
			TableColumn coln = kmcmodeln.getColumn(i);
			coln.setMaxWidth(MainColWidth); coln.setMinWidth(MainColWidth); coln.setWidth(MainColWidth);
			TableColumn colm = kmcmodelm.getColumn(i);
			colm.setMaxWidth(MainColWidth); colm.setMinWidth(MainColWidth); colm.setWidth(MainColWidth);
			if(i<Clust){      str="1";
			}else if(i<Clust*2){str="2";
			}else if(i<Clust*3){str="3";
			}else        {		str="4";}
			kmgrid.jtn.setValueAt(str, 0, i);
			kmgrid.jtn.setValueAt("<html>" +(i+1)+"月", 1,i);
		}
	}
}
```
![fgrid05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3189926/86379cf7-bca7-04a0-1d30-b58a8e639356.jpeg)
６．JScrollPaneに入れる必要が無いのでヒラにkmgridを置くことにします。
```HFlexGridExample06.java
import java.awt.Color;
import java.awt.Cursor;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

class HFlexGridExample06 extends JFrame {
	JPanel contentPane, wpane;
	int MainCols;
	int MainColsFrac;
	int Clust;
	int MainRows;
	int MainColWidth;
	KMGrid kmgrid;
	String kmwColName[],kmmColName[],kmmFileExist[][];
	DefaultTableModel kmmModel, kmwModel, jtModel;
	DefaultTableColumnModel cmodelhk,cmodelj,kmcmodeln,kmcmodelm,kmcmodelw;
	public static void main(String[] args) {
	    JFrame frame = new HFlexGridExample06("HFlexGridExample06");
	    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
	    frame.setSize(600, 400);
	    frame.setVisible(true);
	}
	
	HFlexGridExample06(String title) {
	    super(title);    
	    kmgrid = new KMGrid(547, 16 + 149 + 16 * 10);	// 特注のTableGrid
	    kmgrid.jtm.setCursor(new Cursor(Cursor.HAND_CURSOR));	
	    			// 単なる修飾だが、kmgridの編集可能なjtmではハンドカーソルにしてみた。
		kmGridSet();
	    //JScrollPane jsp = new JScrollPane(kmgrid);	// ScrollPaneを作成し、その中に
	    contentPane = (JPanel) getContentPane();
	    contentPane.add(kmgrid);					// ウィンドウと一体化して分かり辛いので、	    
	    contentPane.setLayout(null);			// 自由な位置に置けるようにして
	    kmgrid.setBounds(10, 10, 560, 340);		// 少し小さくして内部に納めた。
	    kmgrid.setBackground(Color.darkGray);
	}
	
	private void kmGridSet(){
		// 実行時に別々のファイルを読み込んで指定できるということ
		MainCols=12;
		MainColsFrac=4;
		Clust=3;		// MainCols/MainColsFrac;
		MainRows=10;
		MainColWidth = 50;
		// --------------------------------------------------
		
		String[][] koumoku = new String[MainRows][3];
		for(int i=0;i<MainRows;i++) {
			koumoku[i][0]= Integer.toString(i+1);
			koumoku[i][1]= "項目"+ (i + 1) ;// 上と違い何故かこれは通る
			koumoku[i][2]= i + 1 + "2";
		}
		String[] kmwColName = new String[3];// 空で構わない
		kmwModel = new DefaultTableModel(koumoku, kmwColName) {
			@Override public boolean isCellEditable(int row, int col) { return false; }
		};
		kmgrid.jtw.setModel(kmwModel);
		
		kmmFileExist = new String[MainRows][MainCols];               
		kmmColName = new String[MainCols];
		kmmModel = new DefaultTableModel(kmmFileExist, kmmColName) {
			@Override public boolean isCellEditable(int row, int col) { return true; }
		};
		kmgrid.jtm.setModel(kmmModel);

		kmcmodelw = (DefaultTableColumnModel) kmgrid.jtw.getColumnModel();
		kmcmodeln = (DefaultTableColumnModel) kmgrid.jtn.getColumnModel();
		kmcmodelm = (DefaultTableColumnModel) kmgrid.jtm.getColumnModel();
		String str;
		for(int i=0;i<MainCols;i++){
			TableColumn coln = kmcmodeln.getColumn(i);
			coln.setMaxWidth(MainColWidth); coln.setMinWidth(MainColWidth); coln.setWidth(MainColWidth);
			TableColumn colm = kmcmodelm.getColumn(i);
			colm.setMaxWidth(MainColWidth); colm.setMinWidth(MainColWidth); colm.setWidth(MainColWidth);
			if(i<Clust){      str="1";
			}else if(i<Clust*2){str="2";
			}else if(i<Clust*3){str="3";
			}else        {		str="4";}
			kmgrid.jtn.setValueAt(str, 0, i);
			kmgrid.jtn.setValueAt("<html>" +(i+1)+"月", 1,i);
		}
	}
}
```
![fgrid06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3189926/c5d693ef-cf3b-4e49-c8b6-28c7f798fe5b.jpeg)
実行時にファイルからデータを読込ませ、変更後書き出すこともできます。
 以上、pleiades 2022-12で動作確認しています。拙い内容を最後までご覧いただきありがとうございました。