2016-07-17 3 views
1

VBA와 함께 Excel 2003을 사용 중입니다. 동적으로 시트의 확인란 컨트롤을 만들고 VBA 컨트롤을 클래스에 연결하여 사용자가 확인란을 클릭하면 이벤트가 발생하여 작업을 수행 할 수 있도록합니다.Excel VBA 클래스와 컨트롤을 연결하는 방법?

내가 읽은 바로는 사용자 클래스를 만드는 것이 해결책 인 것처럼 보였지만이 방법을 시도해 보니 작동하지 못했습니다.

내 사용자 클래스는 다음과 같습니다

Option Explicit 

    Public WithEvents cbBox As MSForms.checkbox 

    Private Sub cbBox_Change() 
     MsgBox "_CHANGE" 
    End Sub 

    Private Sub cbBox_Click() 
     MsgBox "_CLICK" 
    End Sub 

체크 박스를 만드는 내 코드 :

For Each varExisting In objColumns 
    'Insert the field name 
     objColumnHeadings.Cells(lngRow, 1).Value = varExisting 
    'Insert a checkbox to allow selection of the column 
     Set objCell = objColumnHeadings.Cells(lngRow, 2) 
     Dim objCBclass As clsCheckbox 
     Set objCBclass = New clsCheckbox 
     Set objCBclass.cbBox = ActiveSheet.OLEObjects.Add(_ 
            ClassType:="Forms.CheckBox.1" _ 
           , Left:=300 _ 
           , Top:=(objCell.Top + 2) _ 
           , Height:=10 _ 
           , Width:=9.6).Object 
     objCBclass.cbBox.Name = "chkbx" & lngRow 
     objCBclass.cbBox.Caption = "" 
     objCBclass.cbBox.BackColor = &H808080 
     objCBclass.cbBox.BackStyle = 0 
     objCBclass.cbBox.ForeColor = &H808080 
     objCheckboxes.Add objCBclass 
     lngRow = lngRow + 1 
    Next 

체크 박스는 내가 그들을 클릭, 어떤 메시지 상자 시트에서 볼 수 없지만, 클래스에 대한 링크가 작동하지 않는 것 같습니다.

왜?

편집 ... 확인란을 추가 한 후에 VB IDE로 이동하여 컨트롤 목록에서 만든 확인란 중 하나를 선택한 다음 프로 시저 드롭 다운 목록에서 클릭을 선택하면 호출 코드가 삽입됩니다 다시 어떤 메시지 상자를 추가하면 동일한 체크 박스를 클릭 할 때 작동합니다. 코드에서 어떻게이 작업을 수행 할 수 있습니까? 이 작업을 수행하기 위해 매크로 기록을 시도했지만 아무 것도 기록되지 않았습니다.

+0

objCheckboxes가 선언 된 위치는 어디입니까? –

+0

objCheckboxes는 하나의 컬렉션 일뿐입니다. – SPlatten

+0

나는 그것을 깨닫는다. 그러나 나는 가끔씩 세계적인 것 대신에 그것을 채우는 하위 안에 선언하는 실수를했다. –

답변

1

편집이 문제가 해결 나에게 도움이 방법은 맨 아래로 이동합니다 ...

이상한 이유로 인해 VBA는 시트가 추가 된 동일한 실행주기에서 Sheet의 ActiveX 컨트롤에 대한 이벤트를 연결하지 않습니다. 따라서 우리는 컨트롤을 추가 한 사이클에서 빠져 나오고 다음 사이클에서 proc을 추가하는 이벤트를 호출해야합니다. Application.OnTime 여기에 도움이됩니다.

그것의 과잉을 조금 보이지만 그것은 :)

Option Explicit 

Dim collChk   As Collection 
Dim timerTime 

Sub master() 

     '/ Add the CheckBoxes First 
     Call addControls 

     '<< Due to some weird reason, VBA doesn't hook up the events for Sheet's ActiveX control in the same 
     'execution cycle in which they were added. So, we need to come out of the cycle which added the controls 
     'and then invoke the event adding proc in next cycle. >> 

     '/ Start Timer. Timer will call the sub to add the events 
     Call StartTimer 
End Sub 

Sub addControls() 
    Dim ctrlChkBox  As MSForms.CheckBox 
    Dim objCell   As Range 
    Dim i    As Long 

    'Intialize the collection to hold the classes 
    Set collChk = New Collection 

    '/ Here Controls are added. No Events, yet. 
    For i = 1 To 10 
     Set objCell = Sheet1.Cells(i, 1) 
     Set ctrlChkBox = Sheet1.OLEObjects.Add(_ 
          ClassType:="Forms.CheckBox.1" _ 
         , Left:=1 _ 
         , Top:=(objCell.Top + 2) _ 
         , Height:=objCell.Height _ 
         , Width:=100).Object 
     ctrlChkBox.Name = "chkbx" & objCell.Row 
    Next 

End Sub 

Sub addEvents() 

    Dim ctrlChkBox  As MSForms.CheckBox 
    Dim objCBclass  As clsCheckBox 
    Dim x    As Object 


    'Intialize the collection to hold the classes 
    Set collChk = New Collection 

    '/ Here we assign the event handler 
    For Each x In Sheet1.OLEObjects 
     If x.OLEType = 2 Then 

     Set ctrlChkBox = x.Object 

     Set objCBclass = New clsCheckBox 
     Set objCBclass.cbBox = ctrlChkBox 

     collChk.Add objCBclass 
     Debug.Print x.Name 
     End If 
    Next 

    '/ Kill the timer 
    Call StopTimer 

End Sub 

Sub StartTimer() 
    timerTime = Now + TimeSerial(0, 0, 1) 
    Application.OnTime EarliestTime:=timerTime, Procedure:="addEvents", _ 
     Schedule:=True 
End Sub 

Sub StopTimer() 
    On Error Resume Next 
    Application.OnTime EarliestTime:=timerTime, Procedure:="addEvents", _ 
     Schedule:=False 
End Sub 

클래스 모듈을 작동 : 편집 계속 clsCheckBox

Option Explicit 

    Public WithEvents cbBox As MSForms.CheckBox 

    Private Sub cbBox_Change() 
     MsgBox "_CHANGE" 
    End Sub 

    Private Sub cbBox_Click() 
     MsgBox "_CLICK" 
    End Sub 

...

클래스 (clsCheckbox) :

Option Explicit 

    Public WithEvents cbBox As MSForms.checkbox 

    Private Sub cbBox_Click() 
     MsgBox "_CLICK" 
    End Sub 

Module1의

Public objCheckboxes As Collection 
    Public tmrTimer 

    Public Sub addEvents() 
     Dim objCheckbox As clsCheckbox 
     Dim objMSCheckbox As Object 
     Dim objControl As Object 

     Set objCheckboxes = New Collection 
     For Each objControl In Sheet1.OLEObjects 
      If objControl.OLEType = 2 _ 
      And objControl.progID = "Forms.CheckBox.1" Then 
       Set objMSCheckbox = objControl.Object 
       Set objCheckbox = New clsCheckbox 
       Set objCheckbox.cbBox = objMSCheckbox 
       objCheckboxes.Add objCheckbox 
      End If 
     Next 
     Call stopTimer 
    End Sub 

    Public Sub startTimer() 
     tmrTimer = Now + TimeSerial(0, 0, 1) 
     Application.OnTime EarliestTime:=tmrTimer _ 
         , Procedure:="addEvents" _ 
         , Schedule:=True 
    End Sub 

    Public Sub stopTimer() 
     On Error Resume Next 
     Application.OnTime EarliestTime:=tmrTimer _ 
         , Procedure:="addEvents" _ 
         , Schedule:=False 
    End Sub 

컨트롤을 추가 시트의 코드 :

Dim objControl As MSForms.checkbox 
    For Each varExisting In objColumns 
    'Insert the field name 
     objColumnHeadings.Cells(lngRow, 1).Value = varExisting 
    'Insert a checkbox to allow selection of the column 
     Set objCell = objColumnHeadings.Cells(lngRow, 2) 
     Set objControl = ActiveSheet.OLEObjects.Add(_ 
            ClassType:="Forms.CheckBox.1" _ 
           , Left:=300 _ 
           , Top:=(objCell.Top + 2) _ 
           , Height:=10 _ 
           , Width:=9.6).Object 
     objControl.Name = "chkbx" & lngRow 
     objControl.Caption = "" 
     objControl.BackColor = &H808080 
     objControl.BackStyle = 0 
     objControl.ForeColor = &H808080 
     lngRow = lngRow + 1 
    Next 

이 전체 프로젝트가 아니라 동작을 설명하기에 충분.

+0

감사합니다. 저는 오늘 밤 이것을 구현하고 다시 게시 할 것입니다. – SPlatten

+0

이 줄에 형식이 일치하지 않습니다. Set ctrlChkBox = x.Object 코드를 검사했는데 제대로 복사했음을 확신합니다. – SPlatten

+0

흠 ...,,, 왜 그런 일이 일어나는지는 확실하지 않습니다. 코드를 테스트 한 결과 작동했습니다. addControls 및 addEvents에서 'Dim ctrlChkBox As MSForms.CheckBox' 선언을 사용하고 있습니까? – cyboashu

0

현재 ActiveX 컨트롤을 사용하고 있습니다. 그러나 ActiveX 컨트롤은 특정 명명 규칙을 따릅니다. 예를 들어, 시트에 ActiveX 단추를 삽입하고 이름을 btnMyButton로 지정한 경우 하위의 이름은 btnMyButton_Click이어야합니다. 체크 박스에도 똑같이 적용됩니다. 이름이 CheckBox2 인 새 확인란을 삽입하면 하위 이름은 CheckBox2_Click이어야합니다. 즉, ActiveX 확인란과 연결된 이름이 cbBox_Change 인 하위는있을 수 없습니다.

그래서 ActiveX 컨트롤을 사용하면 시트에서 VBA 코드를 변경할 수 있습니다. 그러나 지금까지는 그런 코드 (VBA 코드를 시트에 변경하는 코드)를 전혀 발견하지 못했습니다.

form controls 대신 기꺼이 사용하는 것이 더 쉬운 방법입니다.

다음 하위에서는 양식 컨트롤 확인란을 만들고 assign the macrotmpSO을 만듭니다. 하위 tmpSO (ActiveX 컨트롤의 하위와 달리)은 시트에있을 필요는 없지만 모든 모듈에있을 수 있습니다. 이 하위를 호출 된 체크 박스 알고함으로써 그 하위에 Application.Caller을 사용할 수 있습니다 tmpSOfrom control 이후

Sub Insert_CheckBox() 

Dim chk As CheckBox 

Set chk = ActiveSheet.CheckBoxes.Add(390.75, 216, 72, 72) 
chk.OnAction = "tmpSO" 

End Sub 

서브를 호출한다.

Sub tmpSO() 

Debug.Print Application.Caller 

End Sub 

이렇게하면 CheckBox의 이름이 반환됩니다. 따라서이 확인란을 모든 체크 박스에 사용할 수 있습니다 (이름은 Case Select 일 가능성이 있음). 여기

tmpSO의 또 다른 예입니다 S.Platten에 의해

Sub tmpSO() 

With ThisWorkbook.Worksheets(1).CheckBoxes(Application.Caller) 
    MsgBox "The checkbox " & Application.Caller & Chr(10) & _ 
     "is currently " & IIf(.Value = 1, "", "not") & " checked." 
End With 

End Sub 
+0

고맙다. 같은 방식으로 만들어진 버튼으로 뭔가를하고있는 게시물이있다. 하지만 난 어떻게 이러한 사용자 클래스와 함께 작동하고 자신을 시도하고 그것을 볼 수없는 이벤트를 발생시킬 수 없습니다. – SPlatten

+0

VBA 코드를 사용하여 시트 코드를 쓸 때 VBA 확장 성 라이브러리를 사용할 수 있습니다. 보안 설정에서 VBA 프로젝트에 대한 ** 신뢰 ** 액세스 권한이 있어야합니다. 구체적인 예가 [Excel vba 시트 프로그래밍 모듈에 코드 추가] (http://stackoverflow.com/questions/34837006/excel-vba-add-code-to-sheet-module-programmatically)와보다 일반적인 토론입니다. 칩 피어슨 (Chip Pearson) [프로그래밍 VBA 편집자] (http://www.cpearson.com/Excel/VBE.aspx) –

+0

@SPlatten 귀하의 문제/질문에 대한 확신이 없습니다. 'Insert_CheckBox' 하위와'tmpSO' 하위를 복사하십시오. 그런 다음'Insert_CheckBox'를 실행하십시오. 그 다음에는 어떤 시트가 활성화되어 있는지 체크 박스가 생기게되고 그 체크 박스를 클릭하면'debug.print' 또는'MsgBox' (tmpSO 서브 카피에 따라 다름)가 생깁니다. 그게 전부 야. 끝난. 클래스 모듈이없고 코딩 할 추가 이벤트가 없습니다. 그것만큼이나 간단합니다. – Ralph