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

时间:2015-08-30 07:46:45

标签: excel-vba vba excel

这就是我想要做的事情:

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

此代码位于普通模块中,以编程方式编写的代码出现在名为&#34; Version_secundaria&#34;的现有用户表单模块中。

似乎单击按钮没有进入Sub Button_click,但不知道为什么!

谢谢!

1 个答案:

答案 0 :(得分:0)

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

你可能还想考虑C Pearson的这个警告:

  

注意:许多基于VBA的计算机病毒都会自行传播   创建和/或修改VBA代码。因此,许多病毒扫描仪可能会   自动而无需警告或确认删除模块   引用VBProject对象,导致永久性和无法恢复   丢失代码。请参阅防病毒软件的文档   详情。

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

我创建了一个用户表单,并用20个选项按钮,1个命令按钮和1个标签填充它。除了我重命名为cmdExit的命令按钮之外,我已经使用默认名称保留了窗体和控件。我把退出按钮和标签放在我希望它们的位置。选项按钮随机放置并变为不可见(属性Visible = False)。这可能不是满足您需求的选项按钮,但在表单显着减慢之前,您可以拥有更多,更多的控件。

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

Option Explicit
Sub DsplForm()

  Load UserForm1
  UserForm1.Show vbModal

End Sub

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

Label1.Caption = "xxxx"
Controls(5).Caption = "xxxx"

这允许运行时访问类似的控件,而无需为每个控件提供特定的代码。

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

  1. 扫描Controls选项按钮并计算它们。
  2. 根据按钮数量调整数组OptButCtrl。
  3. 记录数组OptButCtrl中每个按钮的控制编号。我不关心序列。在OptionButton2 OptionButton1 Controls之前很难获得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 ,但如果你这样做则无关紧要。
  4. 我初始化数组OptButDesc()。这是确定显示多少选项按钮的数组。您需要根据版本的数量调整此数组的大小,并使用版本的名称和详细信息加载此数组。
  5. 适当数量的选项按钮显示在列表中。
  6. 所有选项按钮的单击例程调用单个例程,该例程将除选定按钮之外的所有选项按钮设置为Off / False。 Label1设置为所选按钮的描述。

    尽可能回答问题,但我相信我已经提供了足够的信息来展示如何实现你所寻求的效果。

    # app/models/user.rb
    class User < ActiveRecord::Base
      has_many :articles
      has_many :comments, through: :articles
    end
    
    # app/models/article.rb
    class Article < ActiveRecord::Base
      belongs_to :user
      has_many :comments, dependent: :destroy
    end
    
    # app/models/comment.rb
    class Comment < ActiveRecord::Base
      belongs_to :article
      belongs_to :user
    end
    
    rails g migration AddUsernameToUsers username:string:uniq
    rails g migration AddUserIdToArticles user_id:integer
    rails g migration AddArticleIdToComments article_id:integer
    rails g migration AddUserIdToComments user_id:integer
    rake db:migrate
    

    我应该补充一点,我不相信这是处理您的要求的最佳方式。我相信我会将所有版本加载到ListBox并让使用选择所需的行。