- PR -

構文の間違いでしょうか?

1
投稿者投稿内容
ネーブル
常連さん
会議室デビュー日: 2006/08/26
投稿数: 27
投稿日時: 2006-09-03 14:00
先回の質問から間もありませんが宜しくお願いいたします。

[概要]
pathで受けたファイルを開き、文字列buffに一行づつファイルの終わりまで読込みます
配列resultにlistviewで選択した項目を設定しbuffにresultの項目があれば表示するという内容のコードです。

[質問]

コンパイルは通るのですが、実行すると//★ここでエラーのところで
下記の例外エラーが発生しまいます。
自分では正しいと思うのですが、原因がわかりません、ご教授願います。

[エラー]
System.IndexOutOfRangeException' のハンドルされていない例外が cut.exe で発生しました。

追加情報: インデックスが配列の境界外です。

コード:
private: bool Selection ( String^ path ) {
	// Listview内で選択した項目を配列resultに取得する
	array< String^ >^ result = gcnew array< String^ >( this->listView1->SelectedItems->Count );
	int i = 0;

	// 選択した項目の書出し
	StreamReader^ sr = gcnew StreamReader( path,
			System::Text::Encoding::GetEncoding( "shift-jis" ));
	array<String^>^ arr = gcnew array<String^>(8);
	String^ buff;
	String^ tmp = sr->ReadLine()->Substring(51, 5);
	while ((buff = sr->ReadLine()) != nullptr) {
		for each ( ListViewItem^ item in this->listView1->SelectedItems ) {
			result[ i ] = item->SubItems[ 5 ]->Text;
			if ( buff->Contains( result[ i ] ) == true ) {	//★ここでエラー
				arr[0] = buff->Substring(1, 3);
				arr[1] = buff->Substring(7, 3);
				arr[2] = buff->Substring(11, 10);
				arr[3] = buff->Substring(22, 12);
				arr[4] = buff->Substring(35, 1);
				arr[5] = buff->Substring(38, 12);
				arr[6] = buff->Substring(51, 5);
				arr[7] = buff->Substring(57)->Replace("}", nullptr);
				array< String^ >^ item = { arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7] };
				listView1->Items->Add( gcnew ListViewItem( item ) );
			}
			i++;
		}
	}
		sr->Close();								// ファイルをクローズ
		return true;
}






















Blue
大ベテラン
会議室デビュー日: 2005/09/12
投稿数: 230
お住まい・勤務地: 知っている人は知っている
投稿日時: 2006-09-03 14:13
System.IndexOutOfRangeExceptionのままです。

i = 0;

の位置がおかしくて、3行目以降を読み込んだとき

this->listView1->SelectedItems->Count

以上の値になっています。


それと
>array< String^ >^ item = { arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7] };
はいらないのでは?
単に

listView1->Items->Add( gcnew ListViewItem( arr ) );

じゃダメなのかな?

また
>String^ tmp = sr->ReadLine()->Substring(51, 5);
と先頭行だけ先読みしているけど、tmpはなにか意味があるのでしょうか?(使っていないけど)

[ メッセージ編集済み 編集者: Blue 編集日時 2006-09-03 14:18 ]
ネーブル
常連さん
会議室デビュー日: 2006/08/26
投稿数: 27
投稿日時: 2006-09-03 14:44
Blueさん先日はお世話になりました、申し訳ございません宜しくお願いします。
引用:

i = 0;

の位置がおかしくて、3行目以降を読み込んだとき

this->listView1->SelectedItems->Count

以上の値になっています。


そうなんですか、ご指摘ありがとうございます、もう少し自分で考えて見ます。

引用:

listView1->Items->Add( gcnew ListViewItem( arr ) );


すっきりかけるんですね、_(--)_
引用:

>String^ tmp = sr->ReadLine()->Substring(51, 5);
と先頭行だけ先読みしているけど、tmpはなにか意味があるのでしょうか?(使っていないけど)


余分なもの貼り付けてました(^^);
不要です。
Blue
大ベテラン
会議室デビュー日: 2005/09/12
投稿数: 230
お住まい・勤務地: 知っている人は知っている
投稿日時: 2006-09-03 14:47
インデックスを扱うのであれば、for eachを使うよりも forを使ったほうがスッキリすると思います。

コード:


private:
bool Selection( String^ path )
{
StreamReader^ sr = nullptr;

try
{
String^ buff;
array< String^ >^ arr = gcnew array< String^ >( 8 );

sr = gcnew StreamReader( path, Text::Encoding::GetEncoding( L"shift-jis" ) );

while ( ( buff = sr->ReadLine() ) != nullptr )
{
for ( int i = 0; i < this->listView1->SelectedItems->Count; i++ )
{
ListViewItem^ item = this->listView1->SelectedItems[ i ];
if ( buff->Contains( item->SubItems[ 5 ]->Text ) )
{
arr[ 0 ] = buff->Substring( 1, 3 );
arr[ 1 ] = buff->Substring( 7, 3 );
arr[ 2 ] = buff->Substring( 11, 10 );
arr[ 3 ] = buff->Substring( 22, 12 );
arr[ 4 ] = buff->Substring( 35, 1 );
arr[ 5 ] = buff->Substring( 38, 12 );
arr[ 6 ] = buff->Substring( 51, 5 );
arr[ 7 ] = buff->Substring( 57 )->Replace( L"}", L"" );

this->listView1->Items->Add( gcnew ListViewItem( arr ) );
}
}
}
}
catch ( Exception^ ex )
{
MessageBox::Show( ex->Message );
return false;
}
finally
{
if ( sr != nullptr )
sr->Close();
}
return true;
}



上の例は、for each でもいけますが。。。
(変数 resultが必要であれば、for文のほうが良いです。)

[ メッセージ編集済み 編集者: Blue 編集日時 2006-09-03 14:50 ]
ネーブル
常連さん
会議室デビュー日: 2006/08/26
投稿数: 27
投稿日時: 2006-09-03 22:34
Blueさんどうもいつもすみません、コード参考にさせて頂きました
ありがとうございます単純に選択した項目を出力、もしくは選択されていない
項目を持つ行を削除すれば下記の行いたい事が簡単に行えると思ったのですが
ListViewは一筋縄ではありませんでした(^^);
文章が長くなりますのでまとめます。

[行いたい事]
1. OpenFileDialogで開いた定型フォーマットのファイルを一度ListViewに表示
2. 選択したい項目を選択
3. Button押下で選択した項目のSubItemsプロパティの5番目に含まれている同じ要素を
持つ項目をファイル全部から抽出し、ListViewに出力する。

[問題点]
配列resultに項目を取得後、リストビューの消去を行うと、選択した項目も全て消えてしまう。

[改良部分]
配列resultをFORM1のクラスに定義し保存することによって何処の関数からでも
配列変数渡しできるように実装したが、失敗。

[原因]
コンパイルは通るが、項目を選択してボタンを押下で、
オブジェクト参照がオブジェクト インスタンスに設定されていません。
と例外がスローされてしまいます。
this->result_preservation = result;
多分FORM1の配列変数から何も受取っていない事が原因だと思います

コード:

// FORM1のクラス宣言

public ref class Form1 : public System::Windows::Forms::Form
{
private: String^ fileName; // 読書きファイル名
private: array< String^ >^ result_preservation; // 選択した項目
public:
Form1(void)
{
InitializeComponent();
this->fileName="";
this->result_preservation = nullptr;
}
// ボタン押下
private:
System::Void toolStripButton3_Click(System::Object^ sender, System::EventArgs^ e)
{
array< String^ >^ result = gcnew array< String^ >( this->listView1->SelectedItems->Count );

int i = 0;

for each ( ListViewItem^ item in this->listView1->SelectedItems )
{
result[ i ] = item->SubItems[ 5 ]->Text;

i++;
}
Selection( fileName, result_preservation);

this->result_preservation = result;

}
// リストビュー消去選択項目書出し
private:
bool Selection( String^ path, array< String^ >^ foo )
{
int i = 0;

StreamReader^ sr = nullptr;

EraseListView();

try
{
String^ buff;

array< String^ >^ arr = gcnew array< String^ >( 8 );

sr = gcnew StreamReader( path, System::Text::Encoding::GetEncoding( L"shift-jis" ) );

while ( ( buff = sr->ReadLine() ) != nullptr )
{
for ( i = 0; i < foo->Length; i++ )
{
ListViewItem^ item = this->listView1->SelectedItems[ i ];
if ( buff->Contains( item->SubItems[ 5 ]->Text ) )
{
arr[ 0 ] = buff->Substring( 1, 3 );
arr[ 1 ] = buff->Substring( 7, 3 );
arr[ 2 ] = buff->Substring( 11, 10 );
arr[ 3 ] = buff->Substring( 22, 12 );
arr[ 4 ] = buff->Substring( 35, 1 );
arr[ 5 ] = buff->Substring( 38, 12 );
arr[ 6 ] = buff->Substring( 51, 5 );
arr[ 7 ] = buff->Substring( 57 )->Replace( L"}", L"" );
this->listView1->Items->Add( gcnew ListViewItem( arr ) );
}
}
}
}
catch ( Exception^ ex ) //★ここで例外がスローされる
{
MessageBox::Show( ex->Message );
return false;
}
finally
{
if ( sr != nullptr )
sr->Close();
}
return true;
}
// リストビュー消去
private:
void EraseListView( void )
{
listView1->Items->Clear();
return;
}




[ メッセージ編集済み 編集者: ネーブル 編集日時 2006-09-03 23:01 ]

[ メッセージ編集済み 編集者: ネーブル 編集日時 2006-09-04 00:33 ]

[ メッセージ編集済み 編集者: ネーブル 編集日時 2006-09-04 02:20 ]
Blue
大ベテラン
会議室デビュー日: 2005/09/12
投稿数: 230
お住まい・勤務地: 知っている人は知っている
投稿日時: 2006-09-04 00:42
引用:

ネーブルさんの書き込み (2006-09-03 22:34) より:
コード:

for ( i = 0; i < foo->Length; i++ )
{
ListViewItem^ item = this->listView1->SelectedItems[ i ];
if ( buff->Contains( item->SubItems[ 5 ]->Text ) )




不味いですね。fooの配列数だけループするのに、listView1->SelectedItemを見ています。
つまり、取得する対象が違うということです。
ですので
コード:

for ( i = 0; i < foo->Length; i++ )
{
if ( buff->Contains( foo[ i ] ) )


でいいのでは?

あと、
引用:

ネーブルさんの書き込み (2006-09-03 22:34) より:
コード:

Selection( fileName, result_preservation);

this->result_preservation = result;




Selectionメソッドを呼んでいるとき、result_preservationはresultではない、
もしくは処理順番が逆ではないでしょうか?
(せっかく上で取得した、item->SubItems[ 5 ]->Textの情報ではない)

それと、メンバ変数を使うのであれば、いちいち変数を使って渡す必要もないようですが
どうでしょうか?

[ メッセージ編集済み 編集者: Blue 編集日時 2006-09-04 00:47 ]
Blue
大ベテラン
会議室デビュー日: 2005/09/12
投稿数: 230
お住まい・勤務地: 知っている人は知っている
投稿日時: 2006-09-04 01:06
自分だったら、こんな感じにしますかね。
(ただ、メンバ変数として持つのか引数として渡すかは(そちらの事情)よくわからないのでそのままですが)
コード:

// FORM1のクラス宣言

public ref class Form1 : public System::Windows::Forms::Form
{
private: String^ fileName;                          // 読書きファイル名
private: array< String^ >^ result_preservation;     // 選択した項目
public:
    Form1(void)
    {
        InitializeComponent();
        this->fileName="";
        this->result_preservation = nullptr;
    }
private:
    // ボタン押下
    System::Void toolStripButton3_Click(System::Object^  sender, System::EventArgs^  e)
    {
            this->GetSelectionText();
            this->EraseListView();
            this->Selection();
    }
    // 選択項目をresult_preservationに設定する
    void GetSelectionText()
    {
        this->result_preservation = gcnew array< String^ >( this->listView1->SelectedItems->Count );

        for ( int i = 0; i < this->listView1->SelectedItems->Count; i++ )
        {
            this->result_preservation[ i ] = this->listView1->SelectedItems[ i ]->SubItems[ 5 ]->Text;
        }
    }
    // リストビュー項目書出し
    bool Selection()
    {
        StreamReader^ sr = nullptr;
        
        try
        {
            String^ buff;

            sr = gcnew StreamReader( this->fileName, System::Text::Encoding::GetEncoding( L"shift-jis" ) );

            while ( ( buff = sr->ReadLine() ) != nullptr )
            {
                for ( int i = 0; i < this->result_preservation->Length; i++ )
                {
                    if ( buff->Contains( this->result_preservation[ i ] ) )
                    {
                        this->ListItemAdd( buff );
                    }
                }
            }
        }
        catch ( Exception^ ex )
        {
            MessageBox::Show( ex->Message );
            return false;
        }
        finally
        {
            if ( sr != nullptr )
                sr->Close();
        }
        return true;
    }
    // 文字列からリストビューに追加する
    void ListItemAdd( String^ text )
    {
        array< String^ >^ arr = gcnew array< String^ >( 8 );
        arr[ 0 ] = text->Substring( 1, 3 );
        arr[ 1 ] = text->Substring( 7, 3 );
        arr[ 2 ] = text->Substring( 11, 10 );
        arr[ 3 ] = text->Substring( 22, 12 );
        arr[ 4 ] = text->Substring( 35, 1 );
        arr[ 5 ] = text->Substring( 38, 12 );
        arr[ 6 ] = text->Substring( 51, 5 );
        arr[ 7 ] = text->Substring( 57 )->Replace( L"}", L"" );
        this->listView1->Items->Add( gcnew ListViewItem( arr ) );
    }
    // リストビュー消去(一行ならメソッド化しなくてもよさそうな。。。)
    void EraseListView()
    {
        listView1->Items->Clear();
    }

ネーブル
常連さん
会議室デビュー日: 2006/08/26
投稿数: 27
投稿日時: 2006-09-04 01:56
Blueさん本当にありがとうございます
引用:

不味いですね。fooの配列数だけループするのに、listView1->SelectedItemを見ています。
つまり、取得する対象が違うということです。
ですので


本当ですね、なにやってんだか、それから関数の呼出と保存も逆でした。
引用:

それと、メンバ変数を使うのであれば、いちいち変数を使って渡す必要もないようですが
どうでしょうか?


今、「これからはじめるVisualC++2005入門編」
「実践C++/CLI極めるための基礎と実用テクニック」
「ひと目で分かるMicrosoftVisualC++2005アプリケーション開発入門」
以上の三冊をにらめっこしながら習得に励んでいます、各本の文章を参考に
配列変数の受渡し方やメンバ変数による参照方法を合わせて書いたため
おかしな感じになってしまいました(^^);
本当は、メンバ変数によるコードや、よりオブジェクト指向的な書き方を是非
見てみたいです、このコードをオブジェクト化したらどのようになるのか、興味深々です。
本当にありがとうございました。
1

スキルアップ/キャリアアップ(JOB@IT)