OSTRACISM CO.

C#とObjective-CとJavaと...

テーブル

 GraphicGripGropで使っている最も複雑なGUI部品はメインウィンドウのテーブルである。現在のようなテーブルに近いGUI部品が登場したのはMac OS 8とWindows 95からで、どちらもOSの顔であるFinderやExplorerに似たGUI部品をシステムで提供している。ただしFinderやExplorerがそのGUI部品そのものを利用して実装されているかどうかはわからない。

C#

void OnHitItem(TFileInfo info) {
	ListViewItem item = new ListViewItem(info.m_matchRate.ToString());
	item.SubItems.Add(info.m_filePath);
	this.lvResult.Items.Add(item);
	m_hits.Add(info);
}
 .NETに用意されているテーブルのGUI部品はSystem.Windows.Forms.ListViewクラスで、Visual Studioでプロパティを設定することで外見等を決めるコードが自動的に生成される。
 上記OnHitItemメソッドは検索中に合致したファイルが見つかったときにコールバックされるのだが、System.Windows.Forms.ListViewItemクラスの新しいインスタンスを作成し、データを加え、そのListViewItemをListViewクラスのインスタンスに追加している。表示は勝手に更新される。

Objective-C

@interface GGG4M : NSObject 
...
@end

- (void)hitItemCallback:(TFileInfo *)info {
	[m_hits addObject: info];
	[tvResult reloadData];
}

- (int)numberOfRowsInTableView:(NSTableView *)tv {
	return [m_hits count];
}

- (id)tableView:(NSTableView *)tv objectValueForTableColumn:(NSTableColumn *)column row:(int)row {
	if ([m_hits count] <= row)
		return nil;
	TFileInfo *hit = [m_hits objectAtIndex: row];
	if ([[column identifier] isEqualToString: @"MATCHRATE"]) {
		return [hit matchRateNumber];
	}
	else if ([[column identifier] isEqualToString: @"FILEPATH"]) {
		return [hit filePath];
	}
	return nil;
}
 Cocoaに用意されているテーブルのGUI部品はNSTableViewクラスで、Interface Builderでプロパティを設定することで外見等を決めることができるが、これは.nibファイルのバイナリになる。
 NSTableViewクラスのインスタンスに対する操作はコールバックを用意する方法で行う。
 あらかじめNSTableViewクラスのインスタンスに操作クラスのインスタンス(この場合はGGG4Mクラスのインスタンス)を登録しておく。
 上記hitItemCallbackメソッドは検索中に合致したファイルが見つかったときにコールバックされるのだが、そこではNSTableViewクラスのインスタンスに対しデータの再ロードを要求しているだけである。
 再ロード要求時、NSTableViewクラスのインスタンス向けのコールバックは、行数やデータ等を次々に要求しテーブルを組み立てる。プログラム側は受動的に動くという実装となる。

Java

public GGG4J() {
	...
	TableModel dataModel = new AbstractTableModel() {
		public int getColumnCount() {
			return 2;
		}
		public int getRowCount() {
			return m_hits.size();
		}
		public String getColumnName(int column) {
			if (column == 0)
				return java.util.ResourceBundle.getBundle(m_bundlePath).getString("columnMatchRate");
			else if (column == 1)
				return java.util.ResourceBundle.getBundle(m_bundlePath).getString("columnFilePath");
			return "";
		}
		public Object getValueAt(int row, int col) {
			if (row >= m_hits.size())
				return null;
			TFileInfo info = (TFileInfo)m_hits.get(row);
			if (info == null)
				return null;
			if (col == 0)
				return new Long(info.m_matchRate);
			else if (col == 1)
				return info.m_filePath;
			return null;
		}
	};
	tblResult.setModel(dataModel);
	...
	m_gs.m_context = new TGraphicSearch.Callback() {
		public void hitItemCallback(TFileInfo info) {
			m_hits.add(info);
			tblResult.revalidate();
		}
		...
	};
	...
}
 Swingに用意されているテーブルのGUI部品はjavax.swing.JTableクラスで、NetBeansでウィンドウに貼り付けるところまではできるが、その後のサポートはあまりなく、結構自力でコードを書く羽目になる。
 TableModelインターフェースを実装したクラスを用意することで操作するので、ようはコールバックで受動的に動くことになる。
 上記TGraphicSearch.Callbackインターフェースの実装無名クラスのhitItemCallbackメソッドは検索中に合致したファイルが見つかったときにコールバックされるのだが、そこではJTableクラスのインスタンスに対しデータの再バリデートを要求しているだけである。
 再バリデート時、TableModelインターフェースの実装無名クラスに行数やデータ等を次々に要求し、テーブルを組み立てる。
 考え方はCocoaに近い。Javaはクラス設計でNeXTを強く参考にしたといわれている。とはいえCocoaに比べるとかなり煩わしい概念が入り込んでおり、クラスが増える傾向にある点も含め、変に敷居を高めている一因となっている。

2005.07.20
2005.09.18
「インデックス」へ戻る

OSTRACISM CO.
OSTRA / Takeshi Yoneki