DOBON.NET DOBON.NETプログラミング掲示板過去ログ

comboboxをまとめて指定する方法

環境/言語:[winXP vb.net(2010) excel2000]
分類:[.NET]

先日こちらでexcelの解放方法を教えて頂き、数歩前進したのですが…
またつんのめってしまいました。
comboboxについて調べてみたのですが、どうにも該当するものが見つからず困っています。
以下コードです。

Dim sCellVal As String
Dim y As Integer
Dim x As Integer
Dim rng As Excel.Range ' Range オブジェクト--解放対象【rng】
Dim chk1 As Excel.Range ' Range オブジェクト--解放対象【chk1】
Dim chk2 As Excel.Range ' Range オブジェクト--解放対象【chk2】
Dim xlsCells As Excel.Range = oSheet.Cells ' Range オブジェクト--解放対象【xlsCells】
Try
x = 0 'データは2行目から1行開けて記入。初期値は0とする
Do
x += 2 'データは2行毎に記入なので加算値は2とする
y = 4 'データ格納は5列目から、4列目は項目記入。項目チェックの為初期値は4列目
chk1 = DirectCast(xlsCells(y, x), Excel.Range) '項目情報取得
chk2 = DirectCast(xlsCells(y, x + 1), Excel.Range) '隣の行の項目情報取得
If chk1.Text = "" AndAlso chk2.Text = "" Then '項目情報の空白チェック
MRComObject(chk1) '【chk1】exitで漏れると困るのでここで解放
MRComObject(chk2) '【chk2】exitで漏れると困るのでここで解放
Exit Do '空白ならループを抜ける
End If

Do
y += 1 '実データ取得なので5列目へ加算し、以下ループ
rng = DirectCast(xlsCells(y, x), Excel.Range) 'データ取得
If rng.Text = "" Then 'データの空白チェック
MRComObject(rng) '【rng】exitで漏れると困るのでここで解放
Exit Do '空白ならループを抜ける
End If
sCellVal = rng.Text.ToString() 'データをsCellValに一度受ける
ComboBox1.Items.Add(sCellVal) ' セルの内容をcomboboxへ格納
MRComObject(rng) '【rng】解放。
Loop
MRComObject(chk1) '【chk1】解放
MRComObject(chk2) '【chk2】解放
Loop
MRComObject(xlsCells) '【xlsCells】解放

コメントが多いのはご容赦頂くとして…
やりたい事は(B,5)〜(B,最終項)取得してcomboboxへ。
続けて一つ飛ばして(D,5)〜(D,最終項)。
以降1つ飛ばしを続けて2行空白だと項目無しとしてループを抜ける。
という事です。
外のDO〜LOOPが横へのシフトで、中に入れてるDO〜LOOPがデータの取得。
このときに
ComboBox1.Items.Add(sCellVal)
の”1”をフォームで作成している数(70個近くになる予定なので、変数xがそのままcomboboxの名前になるのが理想的かな)まで増やしたいのです。
combobox分このDO〜LOOPをつらつらと書くのもミスになりそうですし…

宜しくお願いします。
2012/09/21(Fri) 16:56:15 編集(投稿者)

■No30961に返信(歩野さんの記事)

> の”1”をフォームで作成している数(70個近くになる予定なので、変数xがそのままcomboboxの名前になるのが理想的かな)まで増やしたいのです。
> combobox分このDO〜LOOPをつらつらと書くのもミスになりそうですし…
Formに直接貼ってあるなら
  Form.Controls(名前)
Panelなどの上なら
Panel.Controls(名前)
特定のControlの上とは限らないなら
Form.Conrols.Find(名前, True)
で名前によるコントロールの取得は出来ます。

ただ70個もある同じような役割をするコントロールをデザインで配置するより
実行時に自分のコード内で作成するようにした方がよいと思います。そうすれば
DictionaryとかListとかを使用する事により他のコントロールとは独立した管理が出来るようになります。

追記:
処理を見て思ったのですが、コンボボックス用のリストデータが格納されている
セルの集まりが矩形領域であるので一括で2次元配列に値を取得したほうが効率が
よいです。
Range("A1:C4").Value
のようにするとA1〜C4までの矩形領域の値が2次元配列として取得できます。
shuさん、ありがとうございます。

> 追記:
> 処理を見て思ったのですが、コンボボックス用のリストデータが格納されている
> セルの集まりが矩形領域であるので一括で2次元配列に値を取得したほうが効率が
> よいです。
> Range("A1:C4").Value
> のようにするとA1〜C4までの矩形領域の値が2次元配列として取得できます。

との事ですが、まだ私自身が配列を理解しきれていないもので…
試行錯誤している所なので、初歩的な質問になってしまいますがご容赦願います。
  配列---excelでいう所のA1,A2,A3・・・という感じ。
2次配列---同じくexcelでA1,A2,A3…B1,B2,B3…C1,C2,C3…
ということですよね?
上のがあってるのが前提なのですが、配列取得の際に今私がしているように行や列を詰めて取得していると配列と関係がずれちゃいます?
(B5は配列の0,0、B6は1,0。Cは飛ばすのでD5は1,0…以下ループ終わるまで)
という事は、横方向(私のコードでXのループ)は今の手順で最終項目取得。
縦方向(同じくYのループ)は今の手順だと毎回書きかえられちゃうので、Yの最終値を変数”Z”で受けて都度前回と比べる
(X=Bの時のYの最終ZとX=Dの時のYの最終Zを比較して大きければZを更新。小さければスルー)
とすれば取得範囲(X,Y)は求められると思うのですが、空欄(C,E,G…以下1文字飛ばし)も含まれちゃうのかな?っと。
配列を範囲取得した後で抜き出すときに1文字飛ばしにすれば良いのかも?ですが…
配列取得で四苦八苦しているもので、まだ確認まで手が届いていません。
ComboBox(変数).Items.Add(sCellVal)
みたいに出来るかな?っと安易に考えていたのが、そもそもの間違いだったのかも?
■No30963に返信(歩野さんの記事)
>   配列---excelでいう所のA1,A2,A3・・・という感じ。
> 2次配列---同じくexcelでA1,A2,A3…B1,B2,B3…C1,C2,C3…
> ということですよね?
イメージ的にそれでよいかと思います。

> 上のがあってるのが前提なのですが、配列取得の際に今私がしているように行や
列を詰めて取得していると配列と関係がずれちゃいます?
> (B5は配列の0,0、B6は1,0。Cは飛ばすのでD5は1,0…以下ループ終わるまで)
> という事は、横方向(私のコードでXのループ)は今の手順で最終項目取得。
> 縦方向(同じくYのループ)は今の手順だと毎回書きかえられちゃうので、Yの最終値を変数”Z”で受けて都度前回と比べる
> (X=Bの時のYの最終ZとX=Dの時のYの最終Zを比較して大きければZを更新。小さければスルー)
ActiveSheet.Cells.SpecialCells(xlLastCell)
これでシート内の最終セルが取得出来るので
このループを行う必要はないと思います。


> とすれば取得範囲(X,Y)は求められると思うのですが、空欄(C,E,G…以下1文字飛ばし)も含まれちゃうのかな?っと。
もちろん連続列でデータを取得するので1列づつ読み飛ばさないといけませんが
取得した配列でインデックス指定をしてデータを取得するのと1セルづつアクセスするのではパフォーマンスが変わってきます。いまどきのPCではメモリも十分あるでしょうから配列で確保される領域がだいたい2倍になってしまうのは無視してもよいかと思います。
shuさん、お返事が遅れてしまって申し訳ありません。
配列とexcelの関係を理解するのにこんなにかかってしまって…
それで、なんとか形になりそうな感じに動作したのでご報告させて頂きますね。
以下コードです。

'----エクセル処理----
Dim oXL As New Excel.Application() '--解放対象【oXL】
Dim oWBs As Excel.Workbooks = oXL.Workbooks '--解放対象【oWBs】
Dim FileName As String = "C:\test.xls" 'ファイル名はフルパス指定
Try
Dim oWB As Excel.Workbook = oWBs.Open(FileName) '--解放対象【oWB】
Try
Dim oSheets As Excel.Sheets = oWB.Worksheets '--解放対象【oSheets】
Try
Dim oSheet As Excel.Worksheet = DirectCast(oSheets("基準条件"), Excel.Worksheet) 'シート指定は””の中へ--解放対象【oSheet】
Try
Dim cells = oSheet.Cells '--解放対象【cells】
Dim oxlrng As Excel.Range '--解放対象【oxlrng】
oxlrng = oSheet.UsedRange
Dim rng = oSheet.Range(oxlrng.Address) '--解放対象【rng】
Dim s_data(,) As Object = DirectCast(rng.Value, Object(,))
's_data(縦,横)
Dim Countx As Integer '配列の横方向の数
Dim County As Integer '配列の縦方向の数
Countx = s_data.GetLength(1) '配列の横方向の数を取得
County = s_data.GetLength(0) '配列の縦方向の数を取得
Try
Dim x As Integer = 2 'データ記入は偶数列限定なので初期値は2
'---comboboxへのデータ格納処理
For i As Integer = 1 To Countx / 2 '奇数行も配列に含まれるので2で割る。 '---各行へのデータ格納処理
For K As Integer = 2 To County '---実データは2行目以降なので初期値は2。配列の列最大値"county"まで
'---データの空白チェック
If s_data(K, x) Is Nothing Then '---配列データが空白なら---
Exit For '---この後のcomboboxへの追加処理をパスする
End If '---データの空白チェック終了
ComboBox(i).Items.Add(s_data(K, x)) '---comboboxへデータ格納
Next
x += 2 'データ記入は偶数列限定なので2を加算
Next
MRComObject(rng) '【rng】解放
MRComObject(oxlrng) '【oxlrng】解放
MRComObject(cells) '【cells】解放
Finally
If Not oSheet Is Nothing Then
MRComObject(oSheet) '【oSheet】解放
End If
End Try
Finally
If Not oSheets Is Nothing Then
MRComObject(oSheets) '【oSheets】解放
End If
End Try
Finally
If Not oWB Is Nothing Then
Try
oWB.Close() 'Workbookを閉じる
Finally
MRComObject(oWB) '【oWB】解放
End Try
End If
End Try
Finally
If Not oWBs Is Nothing Then
MRComObject(oWBs) '【oWBs】解放
End If
End Try
Finally
If Not oXL Is Nothing Then
Try
oXL.Quit() 'Excelを閉じる
Finally
MRComObject(oXL) '【oXL】解放
End Try
End If
End Try

-----コードここまで。

>   ActiveSheet.Cells.SpecialCells(xlLastCell)
を試してはみたのですが、xllastcellを宣言してといわれ動かなかったもので…
oxlrng = oSheet.UsedRange
を使っています。

動いてるはいるのですが、これで大丈夫なのかな?
添削して頂いた方が良いんじゃない?
という事で、”解決済み”はまた後日という事で…
よろしくお願いします。
なんとか希望通りの動作をしておりますので、解決済みとさせて頂きますね。
shuさん、ありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板