コードに無駄が多すぎる気がする

このQ&Aのポイント
  • フォーム上のコントロールをタブインデックス順に取得するコードに無駄が多すぎると感じる。
  • 現在のコードでは、フォームをループして一つずつコントロールを見ているが、簡略化できないか検討したい。
  • より効率的な方法でフォーム上のコントロールを取得する方法を教えてほしい。
回答を見る
  • ベストアンサー

コードに無駄が多すぎる気がする

http://hiroba.chintai.net/qa7900795.html こちらでも質問したものなのですが、ご提示いただいた内容が難しくてよくわからなかった為 自分でコードを作ったのですが、無駄が多すぎるような気がするので見てもらえますか? やりたい事は、フォーム上のコントロールをタブインデックス順に取得したいのですが --------------------------------------------------------- Option Compare Database Option Explicit Sub test() Dim ctl As Control Dim i As Integer Dim j As Integer Dim intTabIndex As Integer Dim StrFormName As String StrFormName = "SampleCode_SubForm" DoCmd.OpenForm StrFormName, acDesign For i = 0 To Forms(StrFormName).Controls.Count - 1 For j = 0 To Forms(StrFormName).Controls.Count - 1 Set ctl = Forms(StrFormName).Controls.Item(j) If Forms(StrFormName).Controls.Item(j).ControlType = acTextBox Then 'TabIndexがないコントロールはエラーになる。 ' Debug.Print "TabIndex:" & Forms(StrFormName).Controls.Item(j).TabIndex Do While Forms(StrFormName).Controls.Item(j).TabIndex = intTabIndex '数が小さい順からTabIndexを照合していく(0~コントロールの最大値) Debug.Print "TabIndex:" & Forms(StrFormName).Controls.Item(j).TabIndex & " " & Forms(StrFormName).Controls.Item(j).Name intTabIndex = intTabIndex + 1 Exit For '該当のTabIndexが見つかったのなら抜ける Loop End If Next j Next i End Sub --------------------------------------------------------- これで一応取得できるのですが、かなり無駄があるように感じます。 フォームをループして一つずつコントロールを見て行ってるのですがもっと簡略化できないでしょうか? ご回答よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • sean9
  • ベストアンサー率86% (26/30)
回答No.3

No.2 30246kikuさんのおっしゃる通り、フォームのコントロールを全部だとごちゃごちゃになる気がします。が、そのへんはうまいことやってくれるものとして、前に進みます。 ■概要 フォームの中のコントロールをリストで取得 → TabIndexでソート ■使い方 フォームからのコールであれば _controls = GetTabIndexes(Me) ■ソース 'ソートのデリゲード Private Function TabIndexCompare(ByVal c1 As Control, ByVal c2 As Control) As Integer  Return c1.TabIndex - c2.TabIndex End Function 'フォームに含まれるコントロールをタブインデックス順に示す Private Function GetTabIndexes(ByVal form As Form)  Dim controls As New List(Of Control)  For Each c As Control In Me.Controls   controls.Add(c)  Next  controls.Sort(AddressOf TabIndexCompare)  Return controls End Function

wcjiagcnk4
質問者

お礼

ありがとうございます。

その他の回答 (2)

  • 30246kiku
  • ベストアンサー率73% (370/504)
回答No.2

TabIndex は、Section 毎に 0 ~ 連番で振られるようです。 なので、フォームの Controls を対象にすると、ごちゃごちゃになると思います。 ヘッダ、詳細、フッタに分けて、単に TabIndex 順にコントロール名を表示・・・ たぶん以下でいけるかと(未検証) Public Sub Sample()   Dim dic As Object   Dim ctl As Control   Dim v As Variant   Dim i As Long   Const StrFormName As String = "SampleCode_SubForm"   DoCmd.OpenForm StrFormName, acDesign   On Error Resume Next   Set dic = CreateObject("Scripting.Dictionary")   With Forms(StrFormName)     For Each v In Array(1, 0, 2)       dic.RemoveAll       For Each ctl In .Section(v).Controls         Err = 0         i = ctl.TabIndex         If (Err = 0) Then dic.Item(i) = ctl.Name       Next       Debug.Print "> Section(" & v & ") TabIndex 順のコントロール名"       For i = 0 To dic.Count - 1         Debug.Print i, dic.Item(i)       Next     Next   End With   Set dic = Nothing End Sub ※ 不都合あれば修正してください

wcjiagcnk4
質問者

お礼

ありがとうございます。

  • teketon
  • ベストアンサー率65% (141/215)
回答No.1

VBはよくわからないですが、 Controls.Countでコントロールの総数が取得できるなら、 1.最初にコントロール数分サイズの配列を作成 2.全コントロールを繰り返し処理で取得し、取得したtabIndex番目の配列に入れる 3.tabIndex順の配列が出来上がり。 とかじゃないんですかね? 重複・欠番・総数以上のtabIndex番号を考慮する必要はありますが。

wcjiagcnk4
質問者

お礼

ありがとうございます。

関連するQ&A

  • エクセル フォーム上の全てのコントロールを取得した

    エクセル フォーム上の全てのコントロールを取得したい http://okwave.jp/qa/q4879853.html のNo.1さんの回答を参考に、 Sub try() Dim i As Integer Dim StrFormName As String StrFormName = "フォーム1" For i = 0 To Forms(StrFormName).Controls.Count - 1 Debug.Print Forms(StrFormName).Controls.Item(i).Name Next End Sub を作ったのですが、 「Forms」の部分が、 「Sub、Function、または Property が定義されていません。(Error 35)」 というコンパイルエラーになってしまいます。 上記のコードをアクセスVBAにつけると、全てのコントロール名が取得できます。 同じようにエクセルで使うにはどこを修正すればいいでしょうか? フォーム名は、変数に入れて使いたいです。

  • コントロールのタイプを取得したい場合

    Sub test() Dim i As Integer Dim StrFormName As String StrFormName = "UserForm1" With UserForms.Add(StrFormName).Controls For i = 0 To .Count - 1 Debug.Print .Item(i).Name  Next End With End Sub これでエクセルのユーザーフォーム上のすべてのコントロール名が取得できるのですが、 コントロールのタイプを取得したい場合、 Debug.Print .Item(i).Name  の部分をどう変えればいいのでしょうか? 例えばコマンドボタンなら、「CommandButton」と返ってきてほしいです。 Debug.Print .Item(i).Controlstype でも Debug.Print .Item(i).Controltype でもエラーになりました。

  • アクセス For Eachの時点 絞る

    For Eachの時点で、コマンドボタンのみに絞ることは可能ですか? Sub Sample() Dim myFormName As String Dim ctl As Control myFormName = "フォーム1" For Each ctl In Forms(myFormName).Controls Debug.Print ctl.Name Next ctl End Sub これでフォーム上の全てのコントロール名を取得できますが ループの時点でコマンドボタンのみを抽出できますか? For Each ctl In Forms(myFormName).Controls If ctl.ControlType = acCommandButton Then Debug.Print ctl.Name End If Next ctl こうすれば、コマンドボタンのみ絞れますが コントロールの数が多すぎて、処理に時間がかかります。 なので For Each ctl In Forms(myFormName).Controls の部分の、ループの時点でコマンドボタンを絞りたいのですが 絞れる方法があれば教えてください。

  • VB2008: リストメンバーの列数の求め方?

    Sub Main()   Dim I As Integer   Dim J As Integer   Dim K As Integer   Dim aDatas As New List(Of String())()   Dim N = CSVReadToArray("D:\Temp\付属一覧.csv", aDatas) - 1   K = aDatas(0).Count - 1   For I = 0 To N     For J = 0 To K       Debug.Print(aDatas(I)(J))     Next J   Next I End Sub 質問1、K = aDatas(0).Count - 1 の本当のやり方? 質問2、K の処理のされ方。 K が変数としてメモリに配置されることはないと推察しています。 多分、何がしかのスタック領域に一時的に置かれると・・・。 この辺りに関しても教えてもらえれば幸いです。

  • {アクセス}全てのフォームの名前を取得したい

    ひとつのMDBファイルに入っている全てのフォームの名前を取得したいのですが Sub 全てのフォームの名前を取得() Dim i As Integer For i = 1 To Forms.Count Debug.Print Forms.Name Next End Sub このコードだと オブジェクトは、このプロパティまたはメソッドをサポートしていません。(Error 438) となってしまいます。 どうすればいいでしょうか よろしくお願い致します。

  • コントロールタイプを絞ってループしたい

    アクセスのフォーム上のコントロールをループする際に テキストボックスだけ絞ってループしたいのですが Sub Sample() Dim myFormName As String Dim ctl As Control myFormName = "フォーム1" For Each ctl In Forms(myFormName).Controls If ctl.ControlType = acTextBox Then End If Next ctl End Sub これだとテキストボックスの量が多くて、2秒くらいかかるのですが For Each ctl In Forms(myFormName).Controls この時点で、テキストボックスだけ絞る方法はありますか? For Each ctl In Forms(myFormName).ControlType(acTextBox) こうするとエラーになりました。 ご教授よろしくお願いします。

  • コントロールを削除すると、一つ飛ぶ アクセス

    こんばんは。よろしくお願いします。 フォーム上のイメージを削除してるのですが Sub test() Dim ctl As Control Dim FormName As String FormName = "フォーム2" DoCmd.OpenForm FormName, acDesign For Each ctl In Forms(FormName).Controls If ctl.Name Like "イメージ*" Then Debug.Print ctl.Name DeleteControl FormName, ctl.Name End If Next ctl End Sub これをすると、コントロールが一つ飛ばされます。 イミディエイトウインドウで値を確認すると イメージ0 イメージ2 イメージ4 になりました。 1、3、5が飛ばされました。 実行結果は画像のような感じです。 なぜ飛ばされちゃうのでしょうか? 普段、For Each ctl In Forms(FormName).Controlsを使う分には値が飛ばされる事はないので DeleteControl FormName, ctl.Nameが原因だと思うのですが、 全ての「イメージ」で始まるコントロールを削除したい場合、どうすえばいいですか?

  • 変数iもjも同じく値を保持できるからどちらを使って

    このサンプルコードは、 変数iもjも同じく値を保持できるから、test1を使ってもtest2を使っても一緒なのでしょうか? Option Explicit Dim i As Integer Sub test1() Static j As Integer j = j + 1 Debug.Print j End Sub Sub test2() i = i + 1 Debug.Print i End Sub ご回答よろしくお願いします。

  • 全てのコマンドボタンの名前を変更したい

    先日質問した「オブジェクト(コントロール)の名前を変更したい」 http://okwave.jp/qa/q7896863.html?by=datetime&order=DESC の応用で、 前回はDexMachina様にご回答いただいて解決したのですが今度は違う部分で詰みました。 フォームに乗っかっているコマンドボタンの名前を変更しつつ、 インデックスを付けていこうと思うのですが ************************************** Sub オブジェクト名変更() Dim ctl As Control Dim i As Long Dim f As String f = "フォーム1" i = 1 DoCmd.OpenForm f, acDesign 'デザインビューで開く For Each ctl In Forms(f).Controls If ctl.ControlType = acCommandButton Then Forms(f)!Controls(ctl.Name).Caption = i Forms(f)!Controls(ctl.Name).Name = i End If Next ctl DoCmd.Close acForm, "フォーム1", acSaveYes '保存する End Sub ************************************** のControls(ctl.Name).でエラーになります。 エラー内容は 実行時エラー2465 指定した式で参照されている’ Controls’フィールドが見つかりません。 です。 イミディエイトで?ctl.Nameして見ると コマンド0となるので問題ないと思うのですが文法がおかしいのでしょうか? Forms(f)!コマンド0.Caption にすると問題なく動作します。 ご回答よろしくお願いします。

  • Excel VBAライフゲーム

    ExcelのVBAでライフゲームを作りたいのですが、次のプログラムの途中以降がわかりません。 もしよろしければ、このつづきの簡単な実行できるVBAライフゲームを教えてください。 続きのプログラムを教えていただけたら幸いです。 Option Explicit Const ALIVE As Integer = 1 Const DEAD As Integer = 0 Const SIZE As Integer = 19 Const Tmax As Integer = 100 Dim C(SIZE, SIZE) As Integer Sub LifeGame() Dim InitRate As Single Dim T As Integer Dim N As Integer Dim Cnext(SIZE, SIZE) As Integer Dim I As Integer, J As Integer InitRate = -1 Do While InitRate < 0 Or 1 < InitRate Loop For I = 0 To SIZE For J = 0 To SIZE If Rnd() < InitRate Then C(I, J) = ALIVE Else C(I, J) = DEAD End If Next J Next I For T = 1 To Tmax For I = 0 To SIZE For J = 0 To SIZE If C(I, J) = ALIVE Then Cells(I + 1, J + 1).Value = "■" Else Cells(I + 1, J + 1).Vallue = "" End If Next J Next I For I = 0 To SIZE For J = 0 To SIZE N = Count(I, J) Next J Next I For I = 0 To SIZE For J = 0 To SIZE C(I, J) = Cnext(I, J) Next J Next I Next T End Sub Function Count(I As Integer, J As Integer) As Integer End Function

専門家に質問してみよう