• 締切済み

VBAでオブジェクトの配列の配列の削除をすると動作異常になります

VBA(Excel2000)でオブジェクト指向のお勉強をしておりますが、ミスか言語仕様か分からないトラブルがあり、困っております。 簡単な碁(碁盤を再現し、活き死に程度を判定する)のプログラムを作成していますが、クラス石の配列であるクラス群を作成し、更にクラス群の配列を石の黒・白別に標準モジュールで定義しています。一塊の石の群が死んでいると判定した時、その群を削除しようとするのですが、redim preserve 群の配列(添字-一番最後の)を実行すると、群の配列全体にアクセスできなくなってしまいます。redimする前に、Nothingを代入するとか、もとの群(石の配列)にNothingを代入してからredimするとかしてみましたが、事態は変わりませんでした。 仕様なのか、勘違いしているのか、クラスの使い方が分かっていないのか..アドバイスお願いします。

みんなの回答

  • kakusuke
  • ベストアンサー率36% (95/259)
回答No.3

'まずは動的配列の宣言 Dim x() As Integer '配列要素の宣言 Dim y As Integer 'お次は動的配列の再宣言 y = 100 Redim x(1 to y) '…いろんな処理を経て… 'さて現在の配列から、 '88番目だけ削除しようかな…。 Dim Back_x() As Integer Redim Back_x(1 to y) Dim intLoop As Integer For intLoop = 1 To y Back_x(intLoop) = x(intLoop) Next Erase x Redim x(1 To y - 1) For intLoop = 1 To y If intLoop < 88 Then x(intLoop) = Back_x(intLoop) ElseIf intLoop > 88 Then x(intLoop - 1) = Back_x(intLoop) End If Next y = y - 1 これで1個削除できたっしょ?

mitarashi
質問者

お礼

なるほど。java向けの参考書をVBAに載せ替えて勉強しておりましたので、javaは配列の再編が楽そうだなと思いながら、消したい要素と一番最後の要素を入れ替えてから、redimしておりましたが、これだと順番が入れ替わってしまうので、教えて頂いた方法の方がスマートですね。勉強になりました。ところで、碁盤の例では最大4個の群を統合して一つの群にまとめ、以前の群を削除する事を行っています。これをUndoしたいと思ったものです。現在は、仕方がないので次々と新しい群を作り、石が活きていると判定できてから統合する群をNothingに置き換えていますので、どんどんとゴミが増えて行ってしまいます。良いやり方がありますでしょうか。

  • kakusuke
  • ベストアンサー率36% (95/259)
回答No.2

Redimステートメントでは、 配列要素の上限値以下の値を 設定することが出来ません。 例えば、 Dim x() As Integer…(1) Redim x(1 to 100)…(2) Redim x(1 to 10)…(3) この場合、(3)でエラーになります。 したがって、このような処理を行いたい場合、 一度、バックアップを取った後 配列をEraseステートメントで、 クリアしてあげたうえで 元の変数に削除したい要素を除いたものを 戻してあげる必要があります。

mitarashi
質問者

お礼

アドバイスありがとうございます。実は一手打って、石の群を再編し、その結果石が囲まれて死んでしまう位置であったという場合に、元に戻せるようオブジェクトの配列の配列をコピーして操作して、死んでいるときは消してしまい、活きていればコピーし戻そうと考えたのですが、EXCEL VBAは参照渡しらしくうまくいきませんでした。(別の関数等にByValで渡せばとも思いましたが、うまくいかずくじけました)仕方がないので別の方法で対処しましたが、後学のため教えて頂けると幸いです。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

Redimする時にちゃんと新しいサイズ上限は指定していますか? 削除するのに、preserveっておかしい気もしますが。 あと、削除するのにredimっていうのもおかしい気がします。 できたら、キモとなる部分(こちらでも検証できるだけの部分、そのクラスと、その配列、値の設定とredimする部分)を、補足していただけませんか?

mitarashi
質問者

お礼

ExcelのVBAでのクラスモジュール使用に独学でチャレンジしたもので、うまくいかないと仕様の所為にしてしまい、ご迷惑をおかけしました。お陰様でなんとか形になりました。ありがとうございました。

mitarashi
質問者

補足

かいつまんで説明を試みます。 ishiというクラスは、色とか座標、属する群の番号等のプロパティしか持っていません。groupというクラスで、動的配列 Dim myGun() As ishi を宣言しています。質問に記した、標準モジュールで配列の配列を宣言というのは勘違いで、playerというクラスの中で、動的配列Dim myGroups() As group を宣言しています 標準モジュールは、先手と後手のplayerに順番を渡す程度の処理しかしていません。 新しく、例えば黒石を打つと、playerクラスの中で、ishi一個の新しいgroupを作り、盤上で隣接するishiがあれば、新しいgroupに取り込み、groupに活きているか死んでいるか問い合わせします。 新しいgroupを作る際に、myGroups()は、redim preserve myGroups(省略)で、一つ大きくしています。 groupから死んでいるという返事があったとき、このgroupの削除を行いたいのです。 と、コードを眺めながら記していたら、ReDim Preserve myGroups(0 To currentGunNo - 1)と すべき所、Preserveが抜けていた事が判明しました。※currentGunNo=Ubound(myGroups) これが原因かもしれません(そうだったら恥ずかしい限り-昨晩深夜さんざん悩んだのですが)。もう少しいじってみます。

関連するQ&A

専門家に質問してみよう