Gadgets > ViewFile アプリケーション:シンプルなファイル・ブラウザーの作成 > 手順 2:ファイルのブラウズ
 
手順 2:ファイルのブラウズ
手順 1:ブラウザー・ウィンドウの構築で、ファイルの階層リストを表示するグラフィック・オブジェクトの作成方法を学びました。この 2 番目の手順では、ファイル・ブラウザーの定義方法およびインスタンス化の方法を説明します。つまり、グラフィック・オブジェクトにデータを埋めるのに使用されるオブジェクトです (ツリーおよびシート)。ハードディスクのブラウズに使用されるクラスは FileViewer です。これは、viewer.h ファイルで宣言し、viewer.cpp ファイルで定義します。
この手順では、次のタスクを実行する方法を紹介します。
*ファイル・ブラウザーの作成
*ガジェット・アイテムの作成
*ファイル・ビューアーのインスタンス化
*アプリケーションのプレビュー
メモ: この手順用のコードに見られるクラス IlPathName および IlString は、コードを読みやすくするために使用されます。
ファイル・ブラウザーの作成
FileViewer クラスは、長くて複雑です。このセクションではその主要部分を説明します。
*コンストラクター
*ツリーの初期化
*シートの初期化
*ディレクトリーのスキャン
*シートの更新
コンストラクター
FileViewer コンストラクターは、IlvTreeGadget および IlvSheet をそのパラメーターとして必要とします。両方のオブジェクトは initObjects メンバー関数によって初期化されます。
FileViewer::FileViewer(IlvTreeGadget* tree, IlvSheet* sheet)
: _tree(tree), _sheet(sheet)
{
// Initialize the gadgets.
initObjects();
}
ツリーの初期化
ツリー・オブジェクトは initTree メンバー関数で初期化されます。
void
FileViewer::initTree()
{
// Set up the tree gadget.
_tree->removeAllItems(IlvFalse);
_tree->removeCallback(IlvTreeGadget::ExpandCallbackType(),
TreeItemExpanded);
_tree->addCallback(IlvTreeGadget::ExpandCallbackType(),
TreeItemExpanded,
this);
_tree->removeCallback(IlvTreeGadget::SelectCallbackType(),
TreeItemSelected);
_tree->addCallback(IlvTreeGadget::SelectCallbackType(),
TreeItemSelected,
this);
}
このメンバー関数は、ツリーの全アイテムを削除して、ツリーで新しいフォルダが選択されたときにシートを更新する選択コールバックおよび、ツリー・アイテムが展開されるときにトリガーされるコールバックの 2 つを設定します。この
2 つ目のコールバックは、FileViewer オブジェクトが、操作速度を遅らせる原因となる一度でのファイル階層全体の読み込みを行わないようにします。フォルダは展開された時にのみ、読み込まれます。
メモ: 各コールバックは、同じコールバックが 2 度登録されるのを避けるために追加される前に削除されます
詳細は、グラフィック・オブジェクトの「コールバック」を参照してください。
シートの初期化
シートは、initSheet メンバー関数で初期化されます。
void
FileViewer::initSheet()
{
// Set up the sheet.
_sheet->scrollBarShowAsNeeded(IlvTrue, IlvFalse);
_sheet->hideScrollBar(IlvHorizontal, IlvFalse);
_sheet->adjustLast(IlvTrue);
_sheet->reinitialize(3, 1);
_sheet->setNbFixedColumn(0);
_sheet->scrollToColumn(0);
_sheet->setExclusive(IlvTrue);
_sheet->allowEdit(IlvFalse);
 
// Create the header.
_sheet->set(0, 0, new IlvLabelMatrixItem("Name"));
_sheet->setItemAlignment(0, 0, IlvLeft);
_sheet->setItemRelief(0, 0, IlvTrue);
_sheet->setItemSensitive(0, 0, IlvFalse);
_sheet->setItemGrayed(0, 0, IlvFalse);
_sheet->set(1, 0, new IlvLabelMatrixItem("Size"));
_sheet->setItemRelief(1, 0, IlvTrue);
_sheet->setItemSensitive(1, 0, IlvFalse);
_sheet->setItemGrayed(1, 0, IlvFalse);
_sheet->set(2, 0, new IlvLabelMatrixItem("Type"));
_sheet->setItemAlignment(2, 0, IlvLeft);
_sheet->setItemRelief(2, 0, IlvTrue);
_sheet->setItemSensitive(2, 0, IlvFalse);
_sheet->setItemGrayed(2, 0, IlvFalse);
}
このメンバー関数は、 3 つの列と 1 つの行のみでシート・ヘッダーを表示するようにシートを変更します。下図に示すように、列 1 はファイル名、列 2 はファイル・サイズ、列 3 はファイル・タイプの情報を提供します。
メモ: ヘッダーを構成するアイテムは、非センシティブに設定されています。つまり、ユーザーはこれらを選択することができません。
ディレクトリーのスキャン
fillTree メンバー関数は、ツリーが初期化されるとツリーをデータで埋めます。任意のディレクトリーの内容を読み込み、対応するアイテムをツリーに作成します。
void
FileViewer::fillTree(IlvPathName& path, IlvTreeGadgetItem* parent)
{
// Read the 'path' directory and insert each sub-folder as a child of
// the item 'parent'.
if (path.openDir()) {
IlvPathName file;
while (path.readDir(file)) {
if (file.isDirectory() &&
file.getDirectory(IlvFalse) != IlvString(".") &&
file.getDirectory(IlvFalse) != IlvString("..")) {
IlvTreeGadgetItem* item =
(IlvTreeGadgetItem*)createFileItem(file, _tree);
item->setUnknownChildCount(IlvTrue);
// Insert the directory 'file' into parent.
parent->insertChild(item);
// Compute the absolute path name.
IlvPathName* absPathName=new IlvPathName(path);
absPathName->merge(file);
item->setclientData(absPathName)
}
}
path.closeDir();
// Sort the added items.
_tree->sort(parent, 1);
}
}
FileViewer::createFileItem メンバー関数は、各ツリー・アイテムを作成します。これらは、親アイテム、つまり読み込まれているフォルダに追加されます。追加されたアイテムは、IlvTreeGadgetItemHolder::sort メンバー関数によってソートされます。
createFileItem の内容は、ガジェット・アイテムの作成に記述されています。
メモ:  
1. メンバー関数 IlvTreeGadgetItem::setUnknownChildCount が、展開コールバックが呼び出されることを確実にするため、追加された各アイテム用に呼び出されます。詳細については、共通ガジェットの使用の「アイテム特性の変更」を参照してください。
2. アイテムのクライアント・データは、アイテムがポイントするディレクトリーを参照するパス・オブジェクトを保存するために使用されます。このオブジェクトは、毎回アイテムの絶対パスを再計算することを避けるキャッシュです。
fillTree メソッドは、ツリーの 1 つのノードのみを埋めます。ツリー全体は、実際には展開コールバックによって構築されます。
static void
TreeItemExpanded(IlvGraphic* g, IlvAny arg)
{
IlvTreeGadgetItem* item = ((IlvTreeGadget*)g)->getCallbackItem();
if (!item->hasChildren()) {
FileViewer* viewer = (FileViewer*)arg;
IlvPathName* path = (IlvPathName*)item->getClientData();
viewer->updateTree(*path, item);
}
}
このコールバックは、折りたたまれたフォルダを展開しようとするたびに呼び出されます。arg パラメーターは、コールバックが設定されたときに指定されたとおり、FileViewer オブジェクトへのポインターです。アイテムのクライアント・データとして保存されているパスは、ツリー更新のために取得、使用されます。フォルダが一度も開かれていない場合のみツリーを更新するので、updateTree メソッドを呼び出す前に展開されたアイテムには子がないことを確認してください。
void
FileViewer::updateTree(IlvPathName& path, IlvTreeGadgetItem* item)
{
_tree->initReDrawItems();
// Reset the tree, if needed.
if (!item)
initTree();
// Fill it using the 'path' directory.
fillTree(path, item? item :_tree->getRoot());
// Finally, redraw.
_tree->reDrawItems();
}
このメンバー関数は、fillTree メンバー関数を呼び出し、ツリーのクリーニングやスマート再描画処理などの追加操作を実行します。ガジェット・アイテムの「ガジェット・アイテムの再描画」を参照してください。
シートの更新
IlvSheet オブジェクトによってウィンドウの右側に表示されているファイルのリストは、ツリーで選択されているアイテムが変更するたびに更新されなくてはなりません。更新は、IlvTreeGadget クラスの選択コールバックによって実行されます。
static void
TreeItemSelected(IlvGraphic* g, IlvAny arg)
{
// Retrieve the item that has triggered the callback.
IlvTreeGadgetItem* item = ((IlvTreeGadget*)g)->getCallbackItem();
// In the case of a selection (this callback is also called when an item
// is deselected) update the sheet.
if (item->isSelected()) {
// Retrieve the path of the item.
IlvPathName* pathname = (IlvPathName*)item->getClientData();
// Retrieve the file viewer instance.
FileViewer* viewer = (FileViewer*)arg;
// Update the sheet.
viewer->updateSheet(*pathname);
}
}
このコールバックは、新しいアイテムがツリーで選択されるたびに呼び出されます。コールバックをトリガーしたアイテムがメンバー関数 IlvTreeGadget::getCallbackItem によって取得されると、アイテムが選択されているかどうかをチェックする必要があります (ツリー選択コールバックはアイテムが選択解除されたときも呼び出されるため)。次に、アイテムのクライアント・データに保存されているパスが、updateSheet メンバー関数に渡されます。
void
FileViewer::updateSheet(IlvPathName& path)
{
_sheet->initReDrawItems();
// Reset the sheet.
initSheet();
// Read all the files contained in 'path'.
if (path.openDir()) {
IlvPathName file;
while (path.readDir(file)) {
if (!file.isDirectory() ||
(file.getDirectory(IlvFalse) != IlvString(".") &&
file.getDirectory(IlvFalse) != IlvString(".."))) {
if (!file.isDirectory())
file.setDirectory(path);
// Add the file to the sheet.
addFile(file);
}
}
path.closeDir();
}
// Recompute the column sizes.
_sheet->fitWidthToSize();
// Invalidate the whole sheet.
_sheet->getHolder()->invalidateRegion(_sheet);
// Finally, redraw.
_sheet->reDrawItems();
}
このメンバー関数は、ディレクトリー・パスに指定されている全ファイルを addFile メンバー関数を使用してシートに追加します。シートの再描画も管理します。
void
FileViewer::addFile(const IlvPathName& file)
{
// Create the gadget item that will be inserted into the sheet.
IlvGadgetItem* item = createFileItem(file, _sheet);
// Encapsulate it with a matrix item.
IlvAbstractMatrixItem* mitem = new IlvGadgetItemMatrixItem(item);
// Add a new row in the matrix .
_sheet->insertRow((IlvUShort) -1);
IlvUShort row = (IlvUShort)(_sheet->rows() - 1);
 
// Set the item in the first column.
_sheet->set(0, row, mitem);
_sheet->resizeRow((IlvUShort)(row + 1), item->getHeight() + 1);
_sheet->setItemAlignment(0, row, _sheet->getItemAlignment(0, 0));
// File Size in the second column.
_sheet->setItemSensitive(1, row, IlvFalse);
_sheet->setItemGrayed(1, row, IlvFalse);
_sheet->setItemAlignment(1, row, _sheet->getItemAlignment(1, 0));
ifstream ifile(file.getString(), IlvBinaryInputStreamMode);
if (!(!ifile)) {
ifile.seekg(0, ios::end);
streampos length = ifile.tellg();
mitem = new IlvIntMatrixItem(length);
_sheet->set(1, row, mitem);
}
// File Type in the third column.
mitem = new IlvLabelMatrixItem(file.isDirectory()
? "File Folder"
: "File");
_sheet->setItemSensitive(2, row, IlvFalse);
_sheet->setItemGrayed(2, row, IlvFalse);
_sheet->setItemAlignment(2, row, _sheet->getItemAlignment(2, 0));
_sheet->set(2, row, mitem);
}
このメンバー関数は、その引数として提供されているファイル・パラメーターに対応するアイテムを作成し、これをシートの最初の列に追加します。それから、ファイル・サイズを取得して、これを IlvIntMatrixItem オブジェクトとして
2 番目の列に配置します。最後に、ファイル・タイプを IlvLabelMatrixItem オブジェクトとして 3 番目の列に置きます。
2 番目と 3 番目の両方の列アイテムは、非センシティブに設定されています。つまりユーザーはこれらを選択することができません。
メモ: シートの最初の列のファイル名は、ツリー構築に使用されたものと同じメソッドで作成されます。
ガジェット・アイテムの作成
メンバー関数 FileViewer::createFileItem でアイテムを作成します。
IlvGadgetItem*
FileViewer::createFileItem(const IlvPathName& file,
const IlvGadgetItemHolder* holder) const
{
// Compute the item label.
IlvString filename = file.isDirectory()
? file.getString()
: file.getBaseName();
// If file is a directory, remove the trailing '/'.
if (file.isDirectory())
filename.remove(filename.getLength() - 1);
return
holder->createItem(filename,
0,
getBitmap(file, IlvGadgetItem::BitmapSymbol()),
getBitmap(file,
IlvGadgetItem::SelectedBitmapSymbol()));
}
ガジェット・アイテムは、ピクチャーおよびラベルの両方を含むことができます。ガジェット・アイテムの詳細については、ガジェット・アイテムを参照してください。アイテム・ラベルはファイル・パラメーターから計算されます。アイテムは 2 つのビットマップに割り当てられます。1 つは選択されたときのアイテムを表示し、もう 1 つは選択されていないときのアイテムを表します。
次に、アイテムをファクトリー・メンバー関数 IlvGadgetItemHolder::createItem を使用して作成します。これはそのパラメーターとして提供されているホルダー・インスタンスで呼び出されます。ガジェット・アイテムの「ガジェット・アイテムの作成」を参照してください。
ディレクトリーのスキャンでは、ツリーおよびシート両方のアイテムを同メソッドの呼び出しで作成します。クラス IlvTreeGadget および IlvSheet の両方がクラス IlvGadgetItemHolder から継承しているからです。createFileItem メンバー関数と IlvTreeGadget クラスのインスタンスをそのホルダー・パラメーターとして呼び出すと、IlvTreeGadgetItem のインスタンスを返し、これを IlvSheet のインスタンスと呼び出すと、IlvGadgetItem クラスのインスタンスを返します。
メンバー関数 IlvGadgetItemHolder::createItem は、2 つのビットマップをその 3 番目および 4 番目のパラメーターとして取ります。これは、定義済みビットマップ付きアイテムの作成を容易にします。
ただし、createItem への呼び出しは、ビットマップのガジェット・アイテムへの割り当て方法を示す次のコードで置き換えることができます。
IlvGadgetItem* item = holder->createItem(filename);
item->setBitmap(IlvGadgetItem::BitmapSymbol(),
getBitmap(file, IlvGadgetItem::BitmapSymbol()));
item->setBitmap(IlvGadgetItem::SelectedBitmapSymbol(),
getBitmap(file, IlvGadgetItem::SelectedBitmapSymbol()));
return item;
ここで使用される getBitmap メソッドはファイル・タイプ/アイテム・ステータスのペアに対応するビットマップを返します。コードは、次に示すようにとても単純です。
IlvBitmap*
FileViewer::getBitmap(const IlvPathName& file,
const IlvSymbol* state) const
{
if (state == IlvGadgetItem::BitmapSymbol())
return getBitmap(file.isDirectory()
? folderBm
: fileBm);
else
return getBitmap(file.isDirectory()
? sfolderBm
: sfileBm);
}
folderBmfileBmsfolderBm、および sfileBm は、次の条件で定義された記号です。
*folderBm は、フォルダに使用されるビットマップの名前です。
*fileBm は、非選択ファイルに使用されるビットマップの名前です。
*sfolderBm は、選択されたフォルダに使用されるビットマップの名前です。
*sfileBm は、選択されたファイルに使用されるビットマップの名前です。
ファイル・ビューアーのインスタンス化
FileViewer クラスが、以上で完成しました。これをアプリケーションにインスタンス化するには、メンバー関数 FileViewerApplication::configureApplication への呼び出しを、セクションメイン・ウィンドウの作成で定義された FileViewerApplication::makePanels に追加しなくてはなりません。
void
FileViewerApplication::makePanels()
{
// Initialize the main window.
initMainWindow();
// Initialize the application.
configureApplication();
// Show it.
getMainWindow()->show();
}
FileViewerApplication::configureApplication メンバー関数は、FileViewer クラスをインスタンス化し、初期化します。
void
FileViewerApplication::configureApplication()
{
FileViewer* viewer = createFileViewer(getMainWindow());
FileViewerApplication::SetFileViewer(getMainWindow(), viewer);
viewer->init(IlvPathName("/"));
}
メモ: FileViewerApplication::SetFileViewer を呼び出すと、メイン・ウィンドウがビューアーに接続されます。特定のウィンドウに接続されたファイル・ビューアーを、FileViewerApplication::GetFileViewer で取得することができます。
ファクトリー・メソッド createFileViewer は、FileViewer クラスの新しいインスタンスを返します。
FileViewer*
FileViewerApplication::createFileViewer(FileViewerWindow* window) const
{
return new FileViewer(window->getDirectoryHierarchy(),
window->getFileList());
}
アプリケーションのプレビュー
これで手順 2 は完了です。アプリケーションは次のように見えるはずです。
図 1.4   手順 2 完了後の ViewFile アプリケーション

Version 6.0
Copyright © 2015, Rogue Wave Software, Inc. All Rights Reserved.