2012-05-15 13 views
10

Znalazłem wiele zasobów w Internecie, które robią prawie co chcę zrobić, ale nie całkiem. Mam nazwany zakres "lista dzienna". Dla każdego dnia w liście dziennej chcę utworzyć przycisk na formularzu użytkownika, który uruchomi makro dla tego dnia. Jestem w stanie add the buttons dynamically ale nie wiem jak przekazać daycell.text z podanego zakresu, do przycisku, do obsługi zdarzeń, do makra: s Herezje kod mam stworzyć postać użytkownika:Przypisywanie procedur obsługi zdarzeń do formantów formularza użytkownika utworzonego dynamicznie w VBA

Sub addLabel() 
ReadingsLauncher.Show vbModeless 
Dim theLabel As Object 
Dim labelCounter As Long 
Dim daycell As Range 
Dim btn As CommandButton 
Dim btnCaption As String 


For Each daycell In Range("daylist") 
    btnCaption = daycell.Text 
    Set theLabel = ReadingsLauncher.Controls.Add("Forms.Label.1", btnCaption, True) 
    With theLabel 
     .Caption = btnCaption 
     .Left = 10 
     .Width = 50 
     .Top = 20 * labelCounter 
    End With 

    Set btn = ReadingsLauncher.Controls.Add("Forms.CommandButton.1", "runButton", True) 
    With btn 
     .Caption = "Run Macro for " & btnCaption 
     .Left = 80 
     .Width = 80 
     .Top = 20 * labelCounter 
    ' .OnAction = "btnPressed" 
    End With 

    labelCounter = labelCounter + 1 
Next daycell 

End Sub 

aby obejść powyższej kwestii i obecnie poprosi użytkownika o wpisanie dzień chcą uruchomić (np Day1) i przekazać do makro i to działa:

Sub B45runJoinTransactionAndFMMS() 


loadDayNumber = InputBox("Please type the day you would like to load:", Title:="Enter Day", Default:="Day1") 

Call JoinTransactionAndFMMS(loadDayNumber) 

End Sub 

Sub JoinTransactionAndFMMS(loadDayNumber As String) 
xDayNumber = loadDayNumber 

Sheets(xDayNumber).Activate 
-Do stuff 

End Sub 

Więc dla każdego z moich runButtons, to musi wyświetlić daycell.text i uruchomić makro, które używa tego samego tekstu jako parametru, aby wybrać arkusz roboczy do wykonania swoich rzeczy.

Każda pomoc będzie świetna. Widziałem odpowiedzi, które dynamicznie zapisują kod vba, aby obsłużyć makra, ale uważam, że musi być w jakiś sposób można to zrobić nieco bardziej elegancko poprzez przekazywanie parametrów, po prostu nie wiem jak. Z góry bardzo dziękuję!

+0

[to] (http://www.access-programmers.co.uk/forums/archive/index.php/t-88887.html) wygląda blisko tego, co chcesz. OTOH, dlaczego nie utworzyć combobox, który zapełnia się z 'daylist' i jednego przycisku polecenia, który może odczytać wybraną wartość? –

+0

Myślę, że będę musiał wybrać tę opcję. Ponieważ makro służy do przesiewania i przesyłania danych, miałem nadzieję, że będę w stanie stworzyć mały ekran startowy, który będzie wypełniony, który będzie zawierał wiersz dla każdej daty i pokazuje liczbę rekordów, liczba błędów itp. przyciski dla każdego z nich sprawiają, że jest to trochę bardziej przyjazne dla użytkownika. Jednakże, chyba że znajdę prostsze rozwiązanie, myślę, że twoja sugestia zostanie zwycięzcą. – BiGXERO

+0

Kolejna myśl ... Być może w specjalnym arkuszu roboczym można utworzyć tabelę powiązanych informacji (numer dnia, # rekordów, # błędów itp.) I przechwycić zdarzenia kliknięć. –

Odpowiedz

16

wiem, że zaakceptowali rozwiązanie teraz, że będzie pracować dla Ciebie i jest znacznie prostsze niż poniżej, ale jeśli jesteś zainteresowany, to byłoby bardziej bezpośrednią odpowiedź Twoje pytanie.

Musisz utworzyć klasę, aby obsłużyć kliknięcia przycisku, więc za każdym razem, gdy przycisk zostanie kliknięty, używa zdarzenia w klasie, wystarczy zrobić to tylko raz, a następnie utwórz dla niego nowy egzemplarz dla każdego przycisku. Aby powstrzymać te klasy przed utratą zasięgu i zagubieniem, muszą one być przechowywane w deklaracji na poziomie klasy. Poniżej przedstawiłem trochę kodu.

W module klasy (ja nazwał go cButtonHandler)

Public WithEvents btn As MSForms.CommandButton 

Private Sub btn_Click() 
    MsgBox btn.Caption 
End Sub 

Z wydarzeń jest używany, ponieważ pozwala korzystać z większości wydarzeń dla kontroli. Mam przeniesiony kod generacji przycisk do UserForm jak poniżej:

Dim collBtns As Collection 

Private Sub UserForm_Initialize() 

Dim theLabel As Object 
Dim labelCounter As Long 
Dim daycell As Range 
Dim btn As CommandButton 
Dim btnCaption As String 
'Create a variable of our events class 
Dim btnH As cButtonHandler 
'Create a new collection to hold the classes 
Set collBtns = New Collection 

For Each daycell In Range("daylist") 
    btnCaption = daycell.Text 
    Set theLabel = ReadingsLauncher.Controls.Add("Forms.Label.1", btnCaption, True) 
    With theLabel 
     .Caption = btnCaption 
     .Left = 10 
     .Width = 50 
     .Top = 20 * labelCounter 
    End With 

    Set btn = ReadingsLauncher.Controls.Add("Forms.CommandButton.1", "runButton", True) 
    With btn 
     .Caption = "Run Macro for " & btnCaption 
     .Left = 80 
     .Width = 80 
     .Top = 20 * labelCounter 
     'Create a new instance of our events class 
     Set btnH = New cButtonHandler 
     'Set the button we have created as the button in the class 
     Set btnH.btn = btn 
     'Add the class to the collection so it is not lost 
     'when this procedure finishes 
     collBtns.Add btnH 
    End With 

    labelCounter = labelCounter + 1 
Next daycell 


End Sub 

Wtedy możemy nazywamy useform z oddzielnego rutyny:

Sub addLabel() 
ReadingsLauncher.Show vbModeless 

End Sub 

Zajęcia w VBA nie są szczególnie dobrze opisane w wielu książki VBA (zazwyczaj trzeba czytać książki VB6 aby uzyskać zrozumienie), jednak po ich zrozumieć i jak one działają, stają się niezwykle przydatna :)

Nadzieja to pomaga

EDYCJA - w celu odpowiedzi na dodatkowe zapytania:

Aby odwoływać się do obiektów w kolekcji, można to zrobić za pomocą klucza lub indeksu.Aby użyć klucza, trzeba dodać go jak dodać element do kolekcji, tak:

collBtns.Add btnH 

staną

collBtns.Add btnH, btnCaption 

Z tego powodu, klucze muszą być unikalne. Następnie można zapoznać się następująco:

'We refer to objects in a collection via the collection's key 
'Or by it's place in the collection 
'So either: 
MsgBox collBtns("Monday").btn.Caption 
'or: 
MsgBox collBtns(1).btn.Caption 
'We can then access it's properties and methods 
'N.B you won't get any intellisense 
collBtns("Monday").btn.Enabled = False 

można również dodać dodatkowe właściwości/metody klasy, jeśli to konieczne, tak na przykład:

Public WithEvents btn As MSForms.CommandButton 

Private Sub btn_Click() 
    MsgBox btn.Caption 
End Sub 

Public Property Let Enabled(value As Boolean) 
    btn.Enabled = value 
End Property 

będzie wówczas dostępna:

collBtns("Monday").Enabled = False 

Czy to pomaga? Dla dalszego czytania chciałbym skierować cię na stronę Chipa Pearsona, ma świetne rzeczy na większość tematów: http://www.cpearson.com/excel/Events.aspx

Pamiętaj tylko, że VBA jest oparty na VB6, więc nie jest w pełni rozwiniętym językiem OO, na przykład nie obsługuje dziedziczenia w normalnym znaczeniu, tylko interfejs dziedziczenie

Nadzieja to pomaga :)

+0

Dzięki stosy za dogłębną odpowiedź. Nadal trzęsie się, czy użyć formularza użytkownika, czy arkuszy, ale jest to doskonała odpowiedź, szczególnie jak wspomniałeś, klasy wydają się być unikane (lub super technicznie wyjaśnione).Zmieniłem twoją odpowiedź na rzeczywistą, ponieważ to ona faktycznie odpowiada na pytanie. – BiGXERO

+1

Twoja odpowiedź dała mi pewność (po zakończeniu obecnego rozwiązania opartego na arkuszach), aby wypróbować formularze użytkownika. 2 pytania, które myślę, że pomogą sobie i innym noobom, 1) Jeśli chcę odnieść się do konkretnego btn w kolekcji (np. Zmienić podpis lub uczynić go niewidzialnym) w późniejszym czasie, czy mogę się do niego odnieść, korzystając z kolekcji reference (np. collBtns.btn [2]) 2) Czy znasz jakieś zasoby online, które wyjaśniają kolekcje, programy obsługi zdarzeń, itp. Posiadanie jaśniejszego tła java lubię ideę bycia zorientowanym na obiekt i mniejszą ilością zdarzeń – BiGXERO

+0

Zmieniłem powyższe odpowiedzi na twoje pytania – SWa

2

Przykład kliknięcia w arkusz roboczy. Umieścić to w module arkusza:

Private Sub Worksheet_SelectionChange(ByVal Target As Range) 
    ' e.g., range(A1:E1) is clicked 
    If Not Application.Intersect(Target, Range("A1:E1")) Is Nothing Then 
    MsgBox "You clicked " & Target.Address 
    End If 
End Sub 
+0

Myślę, że na coś. Jeśli używam metody przecinania, użyj czegoś wzdłuż linii komórek (dayCell, 6' do iteracji poprzez mój nazwany zakres, może to być potencjalnie proste rozwiązanie mojego problemu.) Testowanie i raportowanie z powrotem. ! – BiGXERO

+0

to działa, aby przetestować kod, którego używam: 'Sub intersectCallingMacro() Zakres (" D8 ") Wybierz" używany tylko do testowania Ustaw cel = ActiveCell Jeśli nie Application.Intersect (cel, zasięg ("A1: M100")) Is Nothing Następnie połączeń testIntersect (ActiveCell.Value) End If End Sub Sub testIntersect (dayString As String) Dim xDayString As String xDayString = dayString Arkusze (xDayString) .Aktywuj Koniec Sub'' (przepraszanie za formatowanie kodu) Przekazuje wartość komórki do makra jako parametru. NIESAMOWITY! – BiGXERO

Powiązane problemy