2017-10-23 12 views
1

タスクエクセルVBA - 任意のワークブック

私の目標のためにすべてのユーザーフォームのリストコントロールは、任意のワークブックのためにすべてのユーザーフォームのすべてのコントロールを一覧表示することです。私のコードは、ワークブックコレクション以外の内のすべてのワークブックで呼び出し元のワークブック(ThisWorkBook)よりも機能します。

問題

私は呼び出すワークブックに関するすべてのユーザーフォームのコントロールを一覧表示しようとすると、私はエラー91オブジェクト変数を取得またはWithブロック変数が、いわゆる番号の誤りライン200(でを設定していませんERL)。以下のコードは、明示的にエラーを表示するために冗長部分に意図的に分割されています。どんな助けもありがとうございます。

フォームが表示されたら、あなたはそのデザイナーへのプログラムによるアクセスを得ることができないコード

Sub ListWBControls() 
' Purpose: list ALL userform controls of a given workbook within workbooks collection 
' 
Dim bProblem As Boolean 
Dim vbc  As VBIDE.VBComponent   ' module, Reference to MS VBA Exte 5.3 needed !!! 
Dim ctrl  As MSForms.Control 
Dim i  As Integer, imax As Integer ' control counters 
Dim cnr  As Long, vbcnr As Long 
Dim sLit  As String 
Dim sMsg  As String      ' result string 
Dim owb  As Workbook     ' workbook object 
Dim wb  As String      ' workbook name to choose by user 
' -------------------- 
' choose Workbook name 
' -------------------- 
    wb = Me.ComboBox1.List(Me.ComboBox1.ListIndex, 0) ' << existing workbook name chosen in combobox 
' check if wb is calling workbook or other 
     For Each owb In Workbooks 
      If owb.Name = wb And ThisWorkbook.Name = wb Then 
      bProblem = True 
      Exit For 
      End If 
     Next owb 
' count workbooks 
    imax = Workbooks.Count 
    i = 1 
' a) start message string showing workbook name 
    sMsg = sMsg & vbNewLine & String(25, "=") & vbNewLine & _ 
      sLit & " WorkBook: " & Workbooks(i).Name & vbNewLine & String(25, "=") 
'------------------------------ 
'Loop thru components (modules) - if of UserForm type 
'------------------------------ 
For Each vbc In Workbooks(wb).VBProject.VBComponents 
    ' Only if Component type is UserForm 
    If vbc.Type = vbext_ct_MSForm Then 
    ' increment component and ctrl counters 
     sLit = Chr(i + 64) & "." 
     vbcnr = vbcnr + 1000 
     cnr = vbcnr 

    ' b) build message new component 
     sMsg = sMsg & vbNewLine & String(25, "-") & vbNewLine & sLit & cnr & " '" & _ 
       vbc.Name & "'" & vbNewLine & String(25, "-") 
    '------------------- 
    ' Loop thru controls 
    '------------------- 
    ' =================================================================== 
    ' Code is intently broken into 2 portions, to show error explicitly ! 
    ' =================================================================== 
     On Error GoTo OOPS ' Error handler --> Error 91: Object variable or With block variable not set 

     If Not bProblem Then ' part 1 - other workbooks: shown explicitly, are no problem 
100   For Each ctrl In Workbooks(wb).VBProject.VBComponents(vbc.Name).Designer.Controls 
      ' increment ctrl counter 
       cnr = cnr + 1 
      ' c) build messages controls) 
       sMsg = sMsg & vbLf & " " & Format(cnr, "0 000") & " " & ctrlInfo(ctrl) 
      Next 
     Else     ' part 2 - problem arises here (wb = calling workbook) 
200   For Each ctrl In Workbooks(wb).VBProject.VBComponents(vbc.Name).Designer.Controls ' << ERROR 91 
      ' increment ctrl counter 
       cnr = cnr + 1 
      ' c) build messages controls) 
       sMsg = sMsg & vbLf & " " & Format(cnr, "0 000") & " " & ctrlInfo(ctrl) 
      Next 

     End If 

     i = i + 1  ' increment letter counter i 
    End If 
Next vbc 
' show result 
Debug.Print sMsg 
Exit Sub 

OOPS: 
MsgBox "Error No " & Err.Number & " " & Err.Description & vbNewLine & _ 
     "Error Line " & Erl 
End Sub 

ヘルパー機能

Private Function ctrlInfo(ctrl As MSForms.Control) As String 
' Purpose: helper function returning userform control information 
    ctrlInfo = Left(TypeName(ctrl) & String(5, " "), 5) & " " & _ 
      Left(ctrl.Name & String(20, " "), 20) & vbTab & _ 
      " .." & IIf(TypeName(ctrl.Parent) = "UserForm", "Me " & String(15, " "), _ 
         TypeName(ctrl.Parent) & ": " & _ 
          Left(ctrl.Parent.Caption & String(15, " "), 15)) & vbTab & _ 
      " T " & Format(ctrl.Top, "# 000") & "/ L " & Format(ctrl.Left, "# 000") 
End Function 

答えて

2

。開いているUserFormからListWBControlsを呼び出しています。フォームをあらかじめ閉じておき、最初に開いたコードでリストを作成してから、再度開くことができます。

このコードは、モジュールに行く:

Public Sub Workaround() 
    On Error GoTo errHandler 

    Dim frmUserForm1 As UserForm1 
    Dim bDone As Boolean 

    bDone = False 

    Do 
     Set frmUserForm1 = New UserForm1 
     Load frmUserForm1 
     frmUserForm1.Show vbModal 

     If frmUserForm1.DoList Then 
      Unload frmUserForm1 
      Set frmUserForm1 = Nothing 

      ListWBControls 
     Else 
      bDone = True 
     End If 
    Loop Until bDone 

Cleanup: 
    On Error Resume Next 
    Unload frmUserForm1 
    Set frmUserForm1 = Nothing 
    Exit Sub 

errHandler: 
    MsgBox Err.Description, vbExclamation + vbOKOnly, "Error" 
    Resume Cleanup 
End Sub 

このコードを使用すると、1つのコマンドがcmdDoListという名前入れているのUserForm1に行く:

Option Explicit 

Private m_bDoList As Boolean 

Public Property Get DoList() As Boolean 
    DoList = m_bDoList 
End Property 

Private Sub cmdDoList_Click() 
    m_bDoList = True 
    Me.Hide 
End Sub 

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) 
    Cancel = True 
    m_bDoList = False 
    Me.Hide 
End Sub 

アイデアがありますフォームを閉じるには、コントロールを一覧表示し、cmdDoListがクリックされたときにフォームを再度開いて、フォームが良好であればフォームを閉じますXボタンで終了します。

+0

完全なリストを作成するためにユーザーフォーム内に*直接的な方法がないことをあなたが助けてくれるのではないかと心配しています。うまくいけば代替のアイデアを受け取ることができます:-) –

+1

私の答えを編集して回避策を追加してください。 – Excelosaurus

+0

userformのクラスメソッドを使うのは素晴らしい考えです。 –

0

見つかり直接解ほとんどの場合覆いユーザーフォームとVBComponentsのクラスのプロパティを使用して。

私は再編集の代わりに以下の変更されたコードを表示します。もちろん、私は非常に

背景

  • VBComponentsが.HasOpenDesigner性質を持っている:-) @Excelosaurusによってすでに受け入れソリューションを感謝しています。
  • 呼び出し元のuserFormは、クラスのプロパティ.Controlsを持ち、識別子Meで参照できます。
  • (これらのUFを直接参照していない場合は、ほんの3番目のケースのみが残っています:IFがアクティブな場合= .HasOpenDesignerはfalseです新しい質問)

修正コード

Sub ListWBControls2() 
' Purpose: list ALL userform controls of a given workbook within workbooks collection 
' cf.: https://stackoverflow.com/questions/46894433/excel-vba-list-controls-of-all-userforms-for-any-given-workbook 
Dim bProblem As Boolean 
Dim vbc  As VBIDE.VBComponent   ' module, Reference to MS VBA Exte 5.3 needed !!! 
Dim ctrl  As MSForms.Control 
Dim i  As Integer, imax As Integer ' control counters 
Dim cnr  As Long, vbcnr As Long 
Dim sLit  As String 
Dim sMsg  As String      ' result string 
Dim owb  As Workbook     ' workbook object 
Dim wb  As String      ' workbook name to choose by user 
' ------------------ 
' chosen Workbook 
' ------------------ 
    wb = Me.ComboBox1.List(Me.ComboBox1.ListIndex, 0) ' << existing workbook name chosen in combobox 
' count workbooks 
    imax = Workbooks.Count 
    i = 1 
' a) build message new workbook 
    sMsg = sMsg & vbNewLine & String(25, "=") & vbNewLine & _ 
      sLit & " WorkBook: " & Workbooks(i).Name & vbNewLine & String(25, "=") 
'------------------------------ 
'Loop thru components (modules) 
'------------------------------ 
For Each vbc In Workbooks(wb).VBProject.VBComponents 
    ' Only if Component type is UserForm 
    If vbc.Type = vbext_ct_MSForm Then 
    ' increment component and ctrl counters 
     sLit = Chr(i + 64) & "." 
     vbcnr = vbcnr + 1000 
     cnr = vbcnr 

    ' b) build message new component 
     sMsg = sMsg & vbNewLine & String(25, "-") & vbNewLine & sLit & cnr & " '" & _ 
       vbc.Name & "'" & vbNewLine & String(25, "-") 
    '------------------- 
    ' Loop thru controls 
    '------------------- 
     If vbc.HasOpenDesigner Then  ' i) problem for closed userforms in same file resolved 
      sMsg = sMsg & vbNewLine & "** " & vbc.Name & " active via Designer.Controls" 
      For Each ctrl In Workbooks(wb).VBProject.VBComponents(vbc.Name).Designer.Controls ' << ERROR 91 
       ' increment ctrl counter 
       cnr = cnr + 1 
       ' c) build messages controls) 
       sMsg = sMsg & vbLf & " " & Format(cnr, "0 000") & " " & ctrlInfo(ctrl) 
       Next 
     ElseIf vbc.Name = Me.Name Then ' ii) problem for calling userform resolved 
       sMsg = sMsg & vbNewLine & "** " & vbc.Name & " active via Me.Controls" 
       For Each ctrl In Me.Controls 
       ' increment ctrl counter 
       cnr = cnr + 1 
       ' c) build messages controls) 
       sMsg = sMsg & vbLf & " " & Format(cnr, "0 000") & " " & ctrlInfo(ctrl) 

       Next ctrl 
        ' ----------------------------------------------------------- 
     Else  ' iii) problem reduced to other userforms within the calling file, 
        ' but only IF OPEN 
        ' ----------------------------------------------------------- 
       sMsg = sMsg & vbLf & "** Cannot read controls in calling file when HasOpenDesigner property is false! **" 
      End If 
     End If 

     i = i + 1  ' increment letter counter i 


Next vbc 
' show result in textbox 
Me.tbCtrls.Text = sMsg 
Debug.Print sMsg 

End Sub 

ヘルパー機能

Private Function ctrlInfo(ctrl As MSForms.Control) As String 
' Purpose: helper function returning userform control information 
    ctrlInfo = Left(TypeName(ctrl) & String(5, " "), 5) & " " & _ 
      Left(ctrl.Name & String(20, " "), 20) & vbTab & _ 
      " .." & IIf(TypeName(ctrl.Parent) = "UserForm", "Me " & String(15, " "), _ 
         TypeName(ctrl.Parent) & ": " & _ 
          Left(ctrl.Parent.Caption & String(15, " "), 15)) & vbTab & _ 
      " T " & Format(ctrl.Top, "# 000") & "/ L " & Format(ctrl.Left, "# 000") 
End Function