[VBA/Word] Hergebruik code voor textinvoer bij bookmarks

Pagina: 1
Acties:
  • 539 views sinds 30-01-2008
  • Reageer

  • Wekkel
  • Registratie: Maart 2000
  • Laatst online: 13-06 12:06

Wekkel

De downloadkoning

Topicstarter
Sinds een paar maanden ben ik in Visual Basic gedoken. Ik loop heel vaak tegen dingen aan die een repeterend karakter hebben of zich om andere redenen bij uitstek lenen om in een programma te tackelen. Vroeger programmeerde ik in Basic en nu probeer ik de draad na vele jaren weer op te pakken.

Ik heb een waslijst aan eBooks die deze taal beschrijven, en ben inmiddels redelijk gevorderd in een daarvan. Langzamerhand begin ik het te begrijpen. Dit handelt echter over Visual Basic 2005 en .NET, mijn vraag spitst zich toe op de simpelere variant van Visual Basic: VBA in Word.

Voor werk vul ik heel veel documenten in op een standaard wijze. Om deze invuloefening simpeler te maken, ben ik met Userforms aan de gang gegaan. Daar zijn prima tutorials voor te vinden, en met wat passen en meten kom ik er prima uit.

Het probleem waar ik tegenaan loop is een kwestie van nette code schrijven.

Inleiding:
Ik heb nu Word documenten met tekst waar ik met een heleboel bookmarks werk. De bookmarks zet ik er allemaal handmatig in. Bij de bookmarks wordt middels een VBA script een woord of tekstje ingevuld die ik als gebruiker invul in een userform. Door op de OK knop te drukken worden de velden uit het userform bij de desbetreffende bookmarks ingevuld.

In het invulveld staat of wel een tekst, of er staat niets in. Zoals uit onderstaande code mag blijken wordt de bookmark met "[ ]" ingevuld als het invulveld leeg is, en zo niet, dan met de tekst die in het invulveld in het userform staat.

Het lijkt mij zo ongeveer het makkelijkste wat er is in VBA ;)

casus
Bij een aantal documenten zijn er een flink aantal bookmarks in gebruik evenals de daarbij behorende invulvelden in een userform. Dat houdt in dat ik dezelfde code (die werkt 8) ) meer dan 30 keer zit te copy/pasten in mijn script om alle bookmarks ingevuld te krijgen. Het lijkt mij dat dit efficienter kan.

In feite zit mijn script voor iedere bookmark telkens:
• de invoer in het invulveld in het userform te checken aan de hand waarvan het de string "[ ]" of de string als ingevoerd in het invulveld krijgt; en
• deze string in de desbetreffende bookmark in te vullen

Ik ben nu al enige tijd bezig om dit simpeler te krijgen, zodat bij grotere documenten met veel bookmarks de code overzichtelijker kan blijven. Een aantal dagen google leren mij dat er eigenlijk maar weinig te vinden is over 'hard core' VBA (zeker voor Word) en met de gegeven voorbeelden voor Visual Basic voor een functie kan ik in VBA niet terecht. De syntax is net iets anders, heb ik het idee.

Mijn gedachte is om voor een bepaald invulveld de string in te voeren in een apart te maken functie die kijkt of de string leeg is of gevuld (actiepunt 1 van mijn script). Het daarna ook invullen in de bookmark in het Word document zelf lijkt mij niet iets voor een functie, ik begrijp dat dit niet kan in Visual Basic.

Een en ander probeer ik van de grond te krijgen met een heel simpel voorbeeld.

Afbeeldingslocatie: http://img70.imageshack.us/img70/1593/vbacn1.jpg
Voorbeeld userform en bijbehorende tekst met bookmarks (waar tekst ingevuld gaat worden)

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Private Sub btnCancel_Click()
Unload UserForm1

End Sub

Private Sub btnOk_Click()

If txtNaam.text = "" Then
    ActiveDocument.Bookmarks("Naam").Range.text = "[   ]"
Else
    ActiveDocument.Bookmarks("Naam").Range.text = txtNaam.text
End If

If txtZetel.text = "" Then
    ActiveDocument.Bookmarks("Zetel").Range.text = "[   ]"
Else
    ActiveDocument.Bookmarks("Zetel").Range.text = txtZetel.text
End If

TextInputCheck (txtAdres.text)

ActiveDocument.Bookmarks("Adres").Range.text = Blockcontents

Unload UserForm1

End Sub
Public Function TextInputCheck(ByVal textblock As String)

Dim Blockcontents As String

If textblock = "" Then
     Blockcontents = "[   ]"
Else
    Blockcontents = textblock
End If

End Function


Private Sub UserForm_Click()

End Sub


De bookmarks "Naam" en "Zetel" worden prima ingevuld via het userform. De bookmark "Adres" probeer ik in te vullen via een functie die ik telkens zou kunnen hergebruiken voor dit klusje.

probleem
Als ik met F8 door de code hop, stap voor stap, zie ik dat ik wel door de Function heen wandel en dat 'Blockcontents' de waarde krijgt uit mijn invulveld 'txtAdres', doch dat de laatste stap niet van de grond komt. Ik krijg de waarde van mijn invulveld 'txtAdres' in de variabele 'Blockcontents' maar het invullen van de bookmark 'Adres' met deze string werkt uiteindelijk niet.

Het moet vast simpel zijn om dit soort reperteerklusjes in een aparte functie te zetten, doch ik kan maar bitter weinig documentatie vinden op dit punt. Wel veel voorbeeldcode voor VBA voor diverse leuke dingen, doch ik zie nergens een functie voor dit soort reperteerwerk waar ik de kunst vanaf kan kijken, noch literatuur waar dit kunstje duidelijk uit de doeken wordt gedaan. Ik kom er simpelweg niet uit :?

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
??? Als ik het goed zie, dan maak je de fout dat je variabelen probeert te gebruiken die niet meer bestaan.

Variabele blockcontents bestaat alleen binnen de functie : TextInputCheck, niet in de functie : btnOk_Click.

2 mogelijkheden. Of je maakt een return value aan zodat je aanroep wordt :
code:
1
ActiveDocument.Bookmarks("Adres").Range.text = TextInputCheck (txtAdres.text)

Of je maakt er een globale variabele van ( af te raden )

  • Lustucru
  • Registratie: Januari 2004
  • Niet online

Lustucru

26 03 2016

1: Zet even option explicit bovenin je code. Daarmee dwing je jezelf variabelen te declareren voor gebruik. De variabele blockcontents in de functie is een andere dan in je sub. De laatste wordt nergens gevuld en blijft dus 'empty'. De functie geeft ook nergens een waarde terug.

2: Het sleutelwoord voor de oplossing is 'collectie'. Al je bookmarks zijn lid van de collectie bookmarks, al je invulvelden lid van de collectiecontrols. Als je op een of andere manier je controls koppelt aan een bookmark ben je klaar met iets als:

code:
1
2
3
For each c in me.controls
           'vulbookmark
next c

Dat koppelen kan door bv consequente naamgeving maar mi is het mooier door in de 'tag'/extra info van je bookmark de naam te vermelden van de bijbehorende bookmark. Je krijgt dan iets als:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
for each c in me.controls
        if  c.tag<>"" then
                 activedocument.bookmarks(c.tag).range.text=getContent(c.text)
        end if
next c

Function getContent(byVal textblock as string) as string
        if textblock<>"" then
               getcontent=textblock
        else
               getcontent="[       ]"
        end if
end function

[ Voor 1% gewijzigd door Lustucru op 21-05-2007 15:02 . Reden: met dankaan _heretic_ voor het opmerken van de fout ]

De oever waar we niet zijn noemen wij de overkant / Die wordt dan deze kant zodra we daar zijn aangeland


  • Wekkel
  • Registratie: Maart 2000
  • Laatst online: 13-06 12:06

Wekkel

De downloadkoning

Topicstarter
Gomez12 schreef op zondag 20 mei 2007 @ 23:59:
Variabele blockcontents bestaat alleen binnen de functie : TextInputCheck, niet in de functie : btnOk_Click.

2 mogelijkheden. Of je maakt een return value aan zodat je aanroep wordt :
code:
1
ActiveDocument.Bookmarks("Adres").Range.text = TextInputCheck (txtAdres.text)

Of je maakt er een globale variabele van ( af te raden )
Ik had ook al het idee dat ik de verkregen waarde in het functieblok 'TextInputCheck' niet terug krijg in het stukje code waarmee ik de bookmark invul met dat bewuste stukje tekst. Echter, de boven beschreven wijze leidt ook niet tot resultaat (had ik al geprobeerd, doch net nog een keer getest, helaas :'( ).

Op een of andere manier moet ik de waarde, verkregen binnen de functie, buiten de functie kunnen halen voor gebruik. Een code als 'return' werkt echter niet zoals in vb2005.

Alvast dank voor het opzetje voor een verdergaande wijze van koppelen van bookmarks met invulvelden. Daar zal ik eens hard over na gaan denken en flink mee gaan stoeien nadat ik mijn eerste serieuze hobbel heb beslecht (het onderhavige probleempje). Alle begin is moeilijk ;)

  • JJvG
  • Registratie: Juli 2003
  • Laatst online: 16-07 15:17
Wekkel schreef op maandag 21 mei 2007 @ 09:38:
[...]
Ik had ook al het idee dat ik de verkregen waarde in het functieblok 'TextInputCheck' niet terug krijg in het stukje code waarmee ik de bookmark invul met dat bewuste stukje tekst. Echter, de boven beschreven wijze leidt ook niet tot resultaat (had ik al geprobeerd, doch net nog een keer getest, helaas :'( ).

Op een of andere manier moet ik de waarde, verkregen binnen de functie, buiten de functie kunnen halen voor gebruik. Een code als 'return' werkt echter niet zoals in vb2005.
Als eerste even een reactie op bovenstaande. Er is een verschil tussen subroutines en functies en vanuit je code lijk je te werken op basis van een subroutine, alleen je noemt het een functie. Je kunt dit op twee manieren oplossen:

Een ByRef in je aanroep (in plaats van een ByVal), hiermee wordt een referentie naar je bestaande variabele gebruikt ipv een nieuwe variabele met dezelfde waarde. Je moet er dan wel een sub(routine) van maken.

Tweede optie is om de functie goed op te bouwen door de volgende code aanpassing....
code:
1
2
3
Public Function TextInputCheck(ByRef/ByVal parameter as String) As String
'Hier je code
End Function


en dan een aanroep in je globale (pseudo)code als volgt:
code:
1
2
3
Dim OngecontroleerdeWaarde as String
Dim GecontroleerdeWaarde as String
GecontroleerdeWaarde = TextInputCheck(OngecontroleerdeWaarde)


Verder zou ik de aanpak zoals eerder voorgesteld (loop door je elementen heen) inderdaad doen. Ik heb zelf een soortgelijke optie een keer gedaan voor het muteren van een Word template op basis van een recordset. In het document moesten op verschillende plekken waarden neergezet worden en op basis van de velden in een recordset heb ik toen het document doorlopen. Code was ongeveer als eerder genoemde, dus die hoef ik niet te herhalen. Enige andere is, dat ik een Find/ReplaceAll functie gebruikte ipv Bookmarks.

Verwijderd

Wekkel schreef op maandag 21 mei 2007 @ 09:38:
Ik had ook al het idee dat ik de verkregen waarde in het functieblok 'TextInputCheck' niet terug krijg in het stukje code waarmee ik de bookmark invul met dat bewuste stukje tekst. Echter, de boven beschreven wijze leidt ook niet tot resultaat (had ik al geprobeerd, doch net nog een keer getest, helaas :'( ).

Op een of andere manier moet ik de waarde, verkregen binnen de functie, buiten de functie kunnen halen voor gebruik. Een code als 'return' werkt echter niet zoals in vb2005.
bekijk nog eens goed de functie van Lustucru (die ik terug even aanpas):
Visual Basic:
1
2
3
4
5
6
7
Function getContent(byVal textblock as string) as string
        if textblock="" then
               getcontent="[       ]"
        else
               getcontent=textblock
        end if
end function
vba kent geen return keyword in de context van een functie. de waarde van een functie wordt eenvoudig teruggegeven door de naam van de functie deze waarde te geven. maw, de functienaam kan automatish als variabele gebruikt worden binnen de functie. dus ipv van een statement als "return blockcontents", krijg je : "getcontent=textblock" of "getcontent="[ ]"" (naam functie=waarde).

  • Wekkel
  • Registratie: Maart 2000
  • Laatst online: 13-06 12:06

Wekkel

De downloadkoning

Topicstarter
Na de heldere input van diverse kanten kan ik natuurlijk niet eindigen zonder de werkende code (ook voor de search). Ik heb het invulscherm thans aangevuld met het Kvk nummer.

Afbeeldingslocatie: http://img19.imageshack.us/img19/2188/vbazs8.jpg

De bijbehorende code is als volgt:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Private Sub btnCancel_Click()
Unload UserForm1

End Sub

Private Sub btnOk_Click()

If txtNaam.text = "" Then
    ActiveDocument.Bookmarks("Naam").Range.text = "[   ]"
Else
    ActiveDocument.Bookmarks("Naam").Range.text = txtNaam.text
End If

If txtZetel.text = "" Then
    ActiveDocument.Bookmarks("Zetel").Range.text = "[   ]"
Else
    ActiveDocument.Bookmarks("Zetel").Range.text = txtZetel.text
End If

ActiveDocument.Bookmarks("Adres").Range.text = getContent(txtAdres.text)

ActiveDocument.Bookmarks("Plaats").Range.text = getContent(txtPlaats.text)

ActiveDocument.Bookmarks("Postcode").Range.text = getContent(txtPostcode.text)

ActiveDocument.Bookmarks("Kvk").Range.text = getContent(txtKvk.text)

Unload UserForm1

End Sub

Function getContent(ByVal textblock As String) As String
        If textblock = "" Then
               getContent = "[       ]"
        Else
               getContent = textblock
        End If
End Function

Private Sub UserForm_Click()

End Sub


De functie heet nu 'getContent'. Waar ik voor 'Naam' en 'Zetel' een volledig beslissingsmodel en invullen van de uitkomst in de bookmark aanhaal, kan ik voor de volgende bookmarks gebruik maken van de functie en zo met één regel de inhoud van het invulveld laten checken en de bookmark invullen.

Veel dank voor de input. Ik zal op een later moment eens proberen de koppeling tussen bookmarks en invulvelden te coden als automatisme :D
Pagina: 1