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