2012-05-15 13 views
10

Ho trovato molte risorse su Internet che fanno quasi quello che voglio fare, ma non del tutto. Ho un intervallo chiamato "lista dei giorni". Per ogni giorno nella dayList, voglio creare un pulsante su un modulo utente che eseguirà la macro per quel giorno. Sono in grado di add the buttons dynamically ma non so come passare il daycell.text dalla gamma di nome, al pulsante, per il gestore di eventi, alla macro: s Heres il codice che ho per creare il form utente:Assegna i gestori di eventi ai controlli sul modulo utente creato dinamicamente in 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 

per aggirare il problema di cui sopra ho attualmente richiede all'utente di digitare la giornata si desidera eseguire (ad esempio, 1 ° giorno) e passare questo alla macro e funziona:

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 

Così, per ognuno dei miei runButtons, si è necessario visualizzare daycell.text ed eseguire una macro che utilizza lo stesso testo di un parametro per selezionare il foglio di lavoro su cui fare il proprio lavoro.

Qualsiasi aiuto sarebbe fantastico. Ho visto le risposte che scrivono dinamicamente il codice vba, per gestire i macro, ma credo che in qualche modo possa essere fatto un po 'più elegante attraverso i parametri di passaggio, ma non so come. Molte grazie in anticipo!

+0

[questo] (http://www.access-programmers.co.uk/forums/archive/index.php/t-88887.html) sembra vicino a quello che vuoi. OTOH perché non creare una casella combinata che popola da 'daylist' e un singolo pulsante di comando in grado di leggere il valore selezionato? –

+0

Sto pensando che potrei dover andare per quell'opzione. Dal momento che la macro è utilizzata per lo screening e il caricamento dei dati, speravo che sarei stato in grado di creare una piccola schermata di avvio che avrebbe popolato una riga per ogni data e mostrare # di record, # di errori, ecc. E avere i pulsanti per ognuno di questi lo renderebbero un po 'più user friendly. Tuttavia, a meno che non riesca a trovare una soluzione più semplice, penso che il tuo suggerimento sarà il vincitore. – BiGXERO

+0

Un altro pensiero ... Forse potresti creare una tabella delle informazioni correlate (numero giornaliero, # record, # errori, ecc.) In un foglio di lavoro speciale e catturare gli eventi click lì. –

risposta

16

So che avete accettato una soluzione, ora che funziona per voi ed è molto più semplice rispetto al di sotto, ma se siete interessati, questo sarebbe la risposta più diretta a la tua domanda.

È necessario creare una classe per gestire i clic del pulsante, quindi ogni volta che si fa clic sul pulsante si utilizza l'evento nella classe, è necessario farlo una sola volta quindi creare una nuova istanza di esso per ogni pulsante. Per evitare che queste classi vadano fuori ambito e si perdano, devono essere archiviate in una dichiarazione di livello di classe. Nel seguito ho spostato il tuo codice un po '.

Nel modulo di classe (l'ho chiamata cButtonHandler)

Public WithEvents btn As MSForms.CommandButton 

Private Sub btn_Click() 
    MsgBox btn.Caption 
End Sub 

Con eventi viene utilizzato in quanto consente di utilizzare la maggior parte degli eventi per il controllo. Ho spostato la generazione del codice tasto nel form, come di seguito:

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 

Poi possiamo chiamare l'useform da una routine separata:

Sub addLabel() 
ReadingsLauncher.Show vbModeless 

End Sub 

Le classi in VBA non sono particolarmente ben coperti in molti libri VBA (in genere è necessario leggere libri VB6 per ottenere una comprensione), ma una volta li si capisce e come funzionano, diventano incredibilmente utile :)

Spero che questo aiuti

MODIFICA - per indirizzare ulteriori richieste

Per fare riferimento agli oggetti in una raccolta, questo viene eseguito tramite la chiave o l'indice.Per utilizzare la chiave, è necessario aggiungerlo come si aggiunge l'elemento della collezione, in modo da:

collBtns.Add btnH 

diventerebbe

collBtns.Add btnH, btnCaption 

Per questo motivo, le chiavi devono essere univoci. È quindi possibile fare riferimento come segue:

'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 

È inoltre possibile aggiungere le proprietà aggiuntive/metodo per la classe, se richiesto, così per esempio:

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 

Sarebbe quindi possibile accedere:

collBtns("Monday").Enabled = False 

Questo aiuto? Per ulteriori letture mi vuoi puntare verso il sito di Chip Pearson, ha grande roba sulla maggior parte dei temi http://www.cpearson.com/excel/Events.aspx

Basta ricordare che VBA si basa su VB6 quindi non è un linguaggio OO a pieno titolo, per esempio, non supporta l'ereditarietà in il senso normale, unica eredità interfaccia

Spero che questo aiuti :)

+0

Grazie mille per la risposta approfondita. A ancora tirare a sè se usare il modulo utente oi fogli, ma questa è un'ottima risposta, in particolare quando parli, le classi sembrano essere evitate (o super tecnicamente spiegate).Ho cambiato la tua risposta a quella attuale in quanto è quella che risponde effettivamente alla domanda – BiGXERO

+1

La tua risposta mi ha dato la sicurezza di (una volta che ho finito la soluzione basata su foglio corrente) per tentare le forme utente. 2 domande che penso aiuteranno me stesso e altri noobs allo stesso modo, 1) Se voglio riferirmi ad un particolare btn nella collezione (ad esempio per cambiare la didascalia o renderla invisibile) più avanti, posso riferirmi ad essa usando una collezione riferimento (es. collBtns.btn [2]) 2) Conosci qualche risorsa online che spiega collezioni, gestori di eventi, ecc. Avendo uno sfondo job noob mi piace l'idea di essere più orientato agli oggetti e meno guidato dagli eventi – BiGXERO

+0

Ho cambiato quanto sopra per rispondere alle vostre domande – SWa

2

Esempio di clic sul foglio di lavoro. Mettere questo nel modulo di foglio di lavoro:

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

Penso a qualcosa. Se uso il metodo intersect, quindi uso qualcosa lungo la linea di 'cells (dayCell, 6' per scorrere il mio intervallo chiamato, questa potrebbe potenzialmente essere una soluzione semplice e degna di nota al mio problema. ! – BiGXERO

+0

funziona! Per testare il codice che utilizzo: 'Sub intersectCallingMacro() Range (" D8 "). Selezionare 'used for testing only Set target = ActiveCell Se non Application.Intersect (target, Range (" A1: M100")) è niente allora chiamata testIntersect (ActiveCell.Value) End If End Sub Sub testIntersect (dayString As String) Dim xDayString come stringa xDayString = dayString 0.123.Fogli (xDayString). Attiva End Sub' (scuse per la formattazione del codice) Passa il valore della cella alla macro come parametro. STUPEFACENTE! – BiGXERO

Problemi correlati