Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Excel 在userform模块中以编程方式创建命令按钮和编写代码_Excel_Vba - Fatal编程技术网

Excel 在userform模块中以编程方式创建命令按钮和编写代码

Excel 在userform模块中以编程方式创建命令按钮和编写代码,excel,vba,Excel,Vba,这就是我想做的: 1检查文件夹中文件的版本数 2在用户窗体中添加与版本数相同的按钮 3为每个按钮编写代码,例如,显示MsgBox 使用下面的代码,可以正确地检查版本数,也可以正确地创建按钮,并且代码可以正确地添加到userform模块中,但是。。。当我点击任何按钮(为每个版本创建)时,什么都没有发生。救命啊 Dim Boton As MSForms.CommandButton Dim Fichero_Secundaria_Hoy As String Dim Versiones_secundari

这就是我想做的:

1检查文件夹中文件的版本数

2在用户窗体中添加与版本数相同的按钮

3为每个按钮编写代码,例如,显示MsgBox

使用下面的代码,可以正确地检查版本数,也可以正确地创建按钮,并且代码可以正确地添加到userform模块中,但是。。。当我点击任何按钮(为每个版本创建)时,什么都没有发生。救命啊

Dim Boton As MSForms.CommandButton
Dim Fichero_Secundaria_Hoy As String
Dim Versiones_secundaria(8) As Integer
Dim i As Integer
Dim Number_of_versions As Integer
Dim Code As String
Dim j As Integer

Fichero_Secundaria_Hoy = Dir("C:\Prueba\pdvd_" & Format(Date, "yyyymmdd") & "*")

Do While Fichero_Secundaria_Hoy <> ""
    Versiones_secundaria(i) = Mid(Fichero_Secundaria_Hoy, 27, 1)
    Fichero_Secundaria_Hoy = Dir
    i = i + 1
Loop

Number_of_versions = i
Version_secundaria.Height = 18 + 24 * Number_of_versions

With ActiveWorkbook.VBProject.VBComponents("Version_secundaria").CodeModule
    .DeleteLines 1, .CountOfLines
End With

For i = 0 To  Number_of_versions - 1
    Set Boton = Version_secundaria.Controls.Add("Forms.commandbutton.1", "Version" & Versiones_secundaria(i))
    Version_secundaria.Controls("version" & Versiones_secundaria(i)).Caption = Versiones_secundaria(i)

    Code = "Sub " & Boton.Name & "_Click()" & vbCrLf
    Code = Code & "Call Mostrar_secundaria" & vbCrLf
    Code = Code & "Version_secundaria.Hide" & vbCrLf
    Code = Code & "End Sub"

    With ActiveWorkbook.VBProject.VBComponents("Version_secundaria").CodeModule
        .InsertLines .CountOfLines + 1, Codigo_del_boton
    End With

Next i
Dim Boton As MSForms.CommandButton
Dim Fichero_Secundaria_Hoy作为字符串
Dim Versiones_secundaria(8)作为整数
作为整数的Dim i
作为整数的\u版本的Dim编号\u
将代码设置为字符串
作为整数的Dim j
Fichero_Secundaria_Hoy=Dir(“C:\Prueba\pdvd_wd”和格式(日期,yyyymmdd)和“*”)
当菲切罗(Fichero_Secundaria_Hoy)的时候
第二版(i)=中期(第27、1页)
Fichero_Secundaria_Hoy=Dir
i=i+1
环
版本的数量=i
版本号?secundaria.Height=18+24*版本号
使用ActiveWorkbook.VBProject.VBComponents(“Version_secundaria”).CodeModule
.DeleteLines 1、.countofline
以
对于i=0到版本数-1
Set Boton=Version\u secundaria.Controls.Add(“Forms.commandbutton.1”、“Version”和Versiones\u secundaria(i))
Version_secundaria.Controls(“Version”和Versiones_secundaria(i))。Caption=Versiones_secundaria(i)
Code=“Sub”&Boton.Name&“\u Click()”&vbCrLf
代码=代码和“呼叫Mostrar\u secundaria”和vbCrLf
Code=Code&“Version\u secundaria.Hide”&vbCrLf
代码=代码和“末端接头”
使用ActiveWorkbook.VBProject.VBComponents(“Version_secundaria”).CodeModule
.InsertLines.CountOfLines+1,Codigo_del_boton
以
接下来我
此代码位于普通模块中,以编程方式编写的代码出现在名为“Version_secundaria”的现有用户表单模块中

似乎点击按钮并不意味着点击子按钮,但不知道为什么


谢谢大家!

我不相信你想要的是可能的。一两年前也有类似的问题。OP的目标与您的目标非常不同,但也需要在运行时创建源代码。我记得OP被告知不可能在同一次运行中创建和执行源代码。我在网上找不到任何东西来证实或否认这一限制。我还记得,发布了一个替代方法来满足该要求。可能是我,因为我记得我在考虑如何达到所需的效果

你也可以考虑C皮尔森的警告:

警告:许多基于VBA的计算机病毒通过 创建和/或修改VBA代码。因此,许多病毒扫描程序可能 在没有警告或确认的情况下自动删除 引用VBProject对象,导致永久性和不可恢复的错误 代码丢失。请参阅您的防病毒软件的文档 详情请参阅

下面的代码提供了另一种方法来实现我相信您所寻求的效果

Option Explicit
  Dim OptButCtrl() As Long
  Dim OptButDesc() As String
Private Sub cmdExit_Click()

  Unload Me

End Sub
' VB.Net has the functionality to allow one routine handle the events for
' several controls.  I can find no equivalent functonality with VBA. This
' approach is the best I have found.
Private Sub OptionButton1_Click()
  Call OptionButtonAny(1)
End Sub
Private Sub OptionButton2_Click()
  Call OptionButtonAny(2)
End Sub
Private Sub OptionButton3_Click()
  Call OptionButtonAny(3)
End Sub
Private Sub OptionButton4_Click()
  Call OptionButtonAny(4)
End Sub
Private Sub OptionButton5_Click()
  Call OptionButtonAny(5)
End Sub
Private Sub OptionButton6_Click()
  Call OptionButtonAny(6)
End Sub
Private Sub OptionButton7_Click()
  Call OptionButtonAny(7)
End Sub
Private Sub OptionButton8_Click()
  Call OptionButtonAny(8)
End Sub
Private Sub OptionButton9_Click()
  Call OptionButtonAny(9)
End Sub
Private Sub OptionButton10_Click()
  Call OptionButtonAny(10)
End Sub
Private Sub OptionButton11_Click()
  Call OptionButtonAny(11)
End Sub
Private Sub OptionButton12_Click()
  Call OptionButtonAny(12)
End Sub
Private Sub OptionButton13_Click()
  Call OptionButtonAny(13)
End Sub
Private Sub OptionButton14_Click()
  Call OptionButtonAny(14)
End Sub
Private Sub OptionButton15_Click()
  Call OptionButtonAny(15)
End Sub
Private Sub OptionButton16_Click()
  Call OptionButtonAny(16)
End Sub
Private Sub OptionButton17_Click()
  Call OptionButtonAny(17)
End Sub
Private Sub OptionButton18_Click()
  Call OptionButtonAny(18)
End Sub
Private Sub OptionButton19_Click()
  Call OptionButtonAny(19)
End Sub
Private Sub OptionButton20_Click()
  Call OptionButtonAny(20)
End Sub
Private Sub UserForm_Initialize()

  Dim InxCtrl As Long
  Dim InxOptBut As Long
  Dim Left As Long
  Dim NumOptButs As Long
  Dim Top As Long

  ' Scan all controls and count those that are Option buttons
  NumOptButs = 0
  For InxCtrl = 0 To Controls.Count - 1
    With Controls(InxCtrl)
      If Mid(.Name, 1, 12) = "OptionButton" Then
        NumOptButs = NumOptButs + 1
      End If
    End With
  Next

  ' Size array according to number of option buttons found
  ReDim OptButCtrl(0 To NumOptButs - 1)

  ' Record control numbers of option buttons in array OptButCtrl()
  InxOptBut = LBound(OptButCtrl)
  For InxCtrl = 0 To Controls.Count - 1
    With Controls(InxCtrl)
      If Mid(.Name, 1, 12) = "OptionButton" Then
        OptButCtrl(InxOptBut) = InxCtrl
        InxOptBut = InxOptBut + 1
      End If
    End With
  Next

  ' The lower bound of OptButCtrl and OptButDesc must be the same.
  ' The size of this array controls how many option buttons are displayed.
  ReDim OptButDesc(0 To 5)

  OptButDesc(0) = "Desc for Button 1"
  OptButDesc(1) = "Desc for Button 2"
  OptButDesc(2) = "Desc for Button 3"
  OptButDesc(3) = "Desc for Button 4"
  OptButDesc(4) = "Desc for Button 5"
  OptButDesc(5) = "Desc for Button 6"

  ' These control the top left corner of the first option button
  Left = 5
  Top = 5

  ' Display one button for each description in OptButDesc()
  For InxOptBut = LBound(OptButCtrl) To UBound(OptButCtrl)
    InxCtrl = OptButCtrl(InxOptBut)
    If InxOptBut <= UBound(OptButDesc) Then
      ' This button is required
      With Controls(InxCtrl)
        .Top = Top
        Top = Top + .Height + 5
        .Left = Left
        .Visible = True
        .Caption = OptButDesc(InxOptBut)
      End With
    Else
      ' This button is not required
      Controls(InxCtrl).Visible = False
    End If
  Next

End Sub
Sub OptionButtonAny(ByVal OptButNum As Long)

  Dim InxCtrl As Long
  Dim InxOptBut As Long

  ' Find Control for selected Option button.
  ' Set all other option buttons to Off.
  ' Display description of selected button in Label1
  For InxOptBut = LBound(OptButCtrl) To UBound(OptButCtrl)
    InxCtrl = OptButCtrl(InxOptBut)
    With Controls(InxCtrl)
      If .Name = "OptionButton" & OptButNum Then
        Label1.Caption = OptButDesc(InxOptBut)
      Else
        .Value = False
      End If
    End With
  Next

End Sub
我创建了一个用户表单,并用20个选项按钮、1个命令按钮和1个标签填充它。我将表单和控件保留为默认名称,但将命令按钮重命名为cmdExit。我把退出按钮和标签放在我想要的地方。选项按钮随机放置,并使其不可见(属性Visible=False)。这可能不足以满足您的需要,但在窗体明显变慢之前,您可以拥有很多很多控件

我创建了一个小例程来显示表单:

Option Explicit
Sub DsplForm()

  Load UserForm1
  UserForm1.Show vbModal

End Sub
表单中代码的基础是集合
控件
,其中包含表单上的所有控件。您可以通过控件名称或控件集合访问控件的属性。例如,如果控件5为Label1,则以下内容等效:

Label1.Caption = "xxxx"
Controls(5).Caption = "xxxx"
这允许运行时访问类似控件,而无需为每个控件指定特定代码

我使用表单的初始化例程来准备一切:

  • 扫描选项按钮的
    控件
    ,并对其进行计数
  • 根据按钮的数量调整数组OptButCtrl的大小
  • 在数组OptButCtrl中记录每个按钮的控制编号。我不在乎顺序。在
    控件中的
    OptionButton1
    之前,很难获取
    OptionButton2
    ,但如果您这样做了,这并不重要
  • 我初始化数组OptButDesc()。这是确定显示多少个选项按钮的数组。您需要根据版本数调整此数组的大小,并使用版本的名称和详细信息加载此数组
  • 列表中会显示适当数量的选项按钮
  • 所有选项按钮的单击例程调用一个例程,该例程将所有选项按钮(所选按钮除外)设置为Off/False。标签1设置为所选按钮的说明

    必要时带着问题回来,但我相信我已经给了你足够的信息来展示如何达到你所寻求的效果

    Option Explicit
      Dim OptButCtrl() As Long
      Dim OptButDesc() As String
    Private Sub cmdExit_Click()
    
      Unload Me
    
    End Sub
    ' VB.Net has the functionality to allow one routine handle the events for
    ' several controls.  I can find no equivalent functonality with VBA. This
    ' approach is the best I have found.
    Private Sub OptionButton1_Click()
      Call OptionButtonAny(1)
    End Sub
    Private Sub OptionButton2_Click()
      Call OptionButtonAny(2)
    End Sub
    Private Sub OptionButton3_Click()
      Call OptionButtonAny(3)
    End Sub
    Private Sub OptionButton4_Click()
      Call OptionButtonAny(4)
    End Sub
    Private Sub OptionButton5_Click()
      Call OptionButtonAny(5)
    End Sub
    Private Sub OptionButton6_Click()
      Call OptionButtonAny(6)
    End Sub
    Private Sub OptionButton7_Click()
      Call OptionButtonAny(7)
    End Sub
    Private Sub OptionButton8_Click()
      Call OptionButtonAny(8)
    End Sub
    Private Sub OptionButton9_Click()
      Call OptionButtonAny(9)
    End Sub
    Private Sub OptionButton10_Click()
      Call OptionButtonAny(10)
    End Sub
    Private Sub OptionButton11_Click()
      Call OptionButtonAny(11)
    End Sub
    Private Sub OptionButton12_Click()
      Call OptionButtonAny(12)
    End Sub
    Private Sub OptionButton13_Click()
      Call OptionButtonAny(13)
    End Sub
    Private Sub OptionButton14_Click()
      Call OptionButtonAny(14)
    End Sub
    Private Sub OptionButton15_Click()
      Call OptionButtonAny(15)
    End Sub
    Private Sub OptionButton16_Click()
      Call OptionButtonAny(16)
    End Sub
    Private Sub OptionButton17_Click()
      Call OptionButtonAny(17)
    End Sub
    Private Sub OptionButton18_Click()
      Call OptionButtonAny(18)
    End Sub
    Private Sub OptionButton19_Click()
      Call OptionButtonAny(19)
    End Sub
    Private Sub OptionButton20_Click()
      Call OptionButtonAny(20)
    End Sub
    Private Sub UserForm_Initialize()
    
      Dim InxCtrl As Long
      Dim InxOptBut As Long
      Dim Left As Long
      Dim NumOptButs As Long
      Dim Top As Long
    
      ' Scan all controls and count those that are Option buttons
      NumOptButs = 0
      For InxCtrl = 0 To Controls.Count - 1
        With Controls(InxCtrl)
          If Mid(.Name, 1, 12) = "OptionButton" Then
            NumOptButs = NumOptButs + 1
          End If
        End With
      Next
    
      ' Size array according to number of option buttons found
      ReDim OptButCtrl(0 To NumOptButs - 1)
    
      ' Record control numbers of option buttons in array OptButCtrl()
      InxOptBut = LBound(OptButCtrl)
      For InxCtrl = 0 To Controls.Count - 1
        With Controls(InxCtrl)
          If Mid(.Name, 1, 12) = "OptionButton" Then
            OptButCtrl(InxOptBut) = InxCtrl
            InxOptBut = InxOptBut + 1
          End If
        End With
      Next
    
      ' The lower bound of OptButCtrl and OptButDesc must be the same.
      ' The size of this array controls how many option buttons are displayed.
      ReDim OptButDesc(0 To 5)
    
      OptButDesc(0) = "Desc for Button 1"
      OptButDesc(1) = "Desc for Button 2"
      OptButDesc(2) = "Desc for Button 3"
      OptButDesc(3) = "Desc for Button 4"
      OptButDesc(4) = "Desc for Button 5"
      OptButDesc(5) = "Desc for Button 6"
    
      ' These control the top left corner of the first option button
      Left = 5
      Top = 5
    
      ' Display one button for each description in OptButDesc()
      For InxOptBut = LBound(OptButCtrl) To UBound(OptButCtrl)
        InxCtrl = OptButCtrl(InxOptBut)
        If InxOptBut <= UBound(OptButDesc) Then
          ' This button is required
          With Controls(InxCtrl)
            .Top = Top
            Top = Top + .Height + 5
            .Left = Left
            .Visible = True
            .Caption = OptButDesc(InxOptBut)
          End With
        Else
          ' This button is not required
          Controls(InxCtrl).Visible = False
        End If
      Next
    
    End Sub
    Sub OptionButtonAny(ByVal OptButNum As Long)
    
      Dim InxCtrl As Long
      Dim InxOptBut As Long
    
      ' Find Control for selected Option button.
      ' Set all other option buttons to Off.
      ' Display description of selected button in Label1
      For InxOptBut = LBound(OptButCtrl) To UBound(OptButCtrl)
        InxCtrl = OptButCtrl(InxOptBut)
        With Controls(InxCtrl)
          If .Name = "OptionButton" & OptButNum Then
            Label1.Caption = OptButDesc(InxOptBut)
          Else
            .Value = False
          End If
        End With
      Next
    
    End Sub
    
    选项显式
    Dim OptButCtrl()尽可能长
    Dim OptButDesc()作为字符串
    私有子cmdExit_Click()
    卸下我
    端接头
    'VB.Net具有允许一个例程处理事件的功能
    “几个控件。我找不到与VBA等价的函数性。这
    “这是我找到的最好的方法。
    专用子选项按钮1\u单击()
    呼叫选项按钮(1)
    端接头
    专用子选项按钮2\u单击()
    呼叫选项按钮(2)
    端接头
    专用子选项按钮3_单击()
    呼叫选项按钮(3)
    端接头
    专用子选项按钮4_单击()
    呼叫选项按钮(4)
    端接头
    专用子选项按钮5_单击()
    呼叫选项按钮(5)
    端接头
    专用子选项按钮6_单击()
    呼叫选项按钮(6)
    端接头
    私人次级选择权