Wordin VBA:ssa dokumentin bookmarkit saadaan valittua ensimmäisten merkkien perusteella, esim. dokumentissa on n määrä "bas"-alkuisia bookmarkeja, joissa on enemmän kuin 3 merkkiä. Nämä saadaan valittua 3 ensimmäisen merkin perusteella, olen tehnyt näin:
For Each Bookmark In ActiveDocument.Bookmarks If optASME.Value = False And Left(Bookmark, 5) = "bas_A" Then Bookmark.Select Selection.Delete End If Next
Visual Basicissa tämä ei toimi näin. Koodi hakee dokumentin ensin auki ja sen jälkeen pitäisi kaikki esim. "bas"-alkuiset bookmarkit poistaa tai eräässä tapauksessa näihin bookmarkeihin pitäisi lisätä vakioteksti, joka on syötetty textboxiin.
Olisko kenelläkään vinkkiä?
Lisää projektiisi referenssi "Microsoft Word X Object Library" (Project->References...), jossa x viittaa Word-versioosi. Seuraavaa koodia soveltamalla saat tuon tehtäväsi tehtyä.
Dim wrdDoc As Word.Document Dim bkmrk As Word.Bookmark Dim polku As String 'Määritetään polku haluamaamme tiedostoon polku = "C:\Documents and Settings\xxx\My Documents\Being an Evil Overlord.doc" 'Aktivoidaan tiedosto käyttöömme. Tiedostoa ei tuoda näkyviin, ellemme erikseen sitä halua. Set wrdDoc = GetObject(polku) 'Käydään läpi tiedoston bookmarkit ja tulostetaan ne Immediate-ikkunaan. For Each bkmrk In wrdDoc.Bookmarks Debug.Print bkmrk.Name Next bkmrk 'Suljetaan kaikki käyttämämme viittaukset viemästä tietokoneen muistia Set bkmrk = Nothing 'Jos tiedostoon olisi tehty muutoksia, niin niiden tallentamisesta tulisi ilmoitus sulkemisen yhteydessä. 'Estetään ilmoitus kertomalla tiedostolle, että muutokset on jo tallennettu. wrdDoc.Saved = True wrdDoc.Close 'Suljetaan tiedosto Set wrdDoc = Nothing 'Vapautetaan tiedoston varaama muisti
Kiitos. Sain immediate -ikkunaan bookmarkit, mutta miten saan määritettyä eri bookmarkeille uuden arvon (textbox.text) -kentistä? Näitä on useampi erilainen. Haluaisin samanalkuiset bookmarkit esim. 3 merkin tarkkuudella vaihdettua ilman, että luettelen jokaisen bookmarkin kokonaisuudessaan, koodista tulee tosi pitkä.
En muuten keksi, miten Immediate-ikkunaa voi hyödyntää..?
Jos ehto on aina sama, niin voit käyttää Select Case-rakennetta korvaamaan useat If-tarkastelut.
Dim Montako As Long 'Select Case on ehtorakenne, jolla voidaan helposti määritellä eri vaihtoehdoille eri tapahtumat 'LCase = käsitellään merkkijonoa pienin kirjaimin 'Left = luetaan vasemmasta reunasta haluttu määrä merkkejä 'Kaksoispisteellä kootaan yhdelle riville useampia koodirivejä. Select Case LCase(Left(bkmrk.Name, 3)) 'jos kirjanmerkin alku on bas kirjainten koosta riippumatta, niin suoritetaan tämä rivi 'koska kirjanmerkin nimen pitää olla yksilöllinen, niin lisätään niiden perään yksilöivä numero Montako Case "bas": Montako = Montako + 1: bkmrk.name = "foo_" & Montako 'jos alku on sab, niin suoritetaan tämä rivi Case "sab": Montako = Montako + 1: bkmrk.name = textbox.text & Montako 'muissa tapauksissa kirjanmerkki poistetaan Case Else: bkmrk.Delete End Select
* Immediate-ikkunaa käytetään koodin testauksessa.
* Debug.Print-rakenne tulostaa kyseiseen ikkunaan.
* Muutujien/koodin pätkän arvoa voi testata ?:llä koodin alussa. Eli edellisen koodini Select Case -ehdon arvon LCase(Left(bkmrk.Name, 3)) voi tarkistaa kirjoittamalla
?LCase(Left(bkmrk.Name, 3))
Immediate ikkunaan.
* Kyseisessä ikkunassa voi myös muuttaa muuttujien arvoa ihan vain sijoituslauseella kesken koodin suorituksen, kun suoritus on pysähtynyt jollekkin koodiriville, jonka aikana muuttuja on käytössä.
Koodissa bkmrk.name hälyttää .Name -osuutta: "Can't assign to read-only property (Compile error), mikä meni pieleen?
Tässä koodin rivi, jossa häly ensimmäisen kerran (myös seuraava vastaava hälyttää jos ensimmäisen poistaa):
Case "bas": Montako = Montako + 1: bkmrk.name = "foo_" & Montako
Name on tosiaankin vain ReadOnly-arvo, eli sitä ei pysty muuttamaan. Tuon voi kokeilla kiertää Copy-komennolla, jolla tehdään kyseisestä kirjanmerkistä kopio uudella nimellä. Tällöin vanha kirjanmerkki pitää poistaa Delete-komennolla, sillä muuten sekin jäisi vielä jäljelle.
If bkmrk.Name="foo" Then bkmrk.Copy "bar" bkmrk.Delete End If
Huomaa, että muutokset pitää muistaa tallentaa, eli poistaa komento
wrdDoc.Saved = True
ja muuttaa sulkemiskomento muotoon
wrdDoc.Application.Quit True
jossa tuo True-määre tarkoittaa muutosten tallentamista. Jostain syystä testeissäni tuo tallennus ei kuitenkaan tapahtunut joka kerta.
Sain bookmarkit toimimaan tekemällä aliohjelman:
Sub ChangeBookmarks(bm As String, Value As String) Dim i As Integer Dim r As Integer On Error GoTo virhe For i = 1 To 20 Call msWord.activedocument.Bookmarks(bm & i).Select Call msWord.selection.typetext(Value) Next loppu: Exit Sub virhe: Resume loppu End Sub
Tämä aliohjelma kutsutaan ohjelman sisällä:
Call ChangeBookmarks("pv_", txtProduct.Text) Call ChangeBookmarks("cust_", txtCustName.Text) Call ChangeBookmarks("add1_", txtAddress1.Text) Call ChangeBookmarks("add2_", txtAddress2.Text)
Kiitos BadSource neuvoista (vaikka en osannutkaan ohjeidesi avulla viemään koodia loppuun), olet aika guru Visual Basic 6 käsittelyssä! Sain avullasi toisen ongelman ratkaistuksi (.pdf-tiedoston tulostaminen). Toivottavasti jaksat neuvoa meitä aloittelijoita jatkossakin.
Jos olet itse saanut ratkaistua ongelmasi, niin sehän on parempi, kuin kopioida valmista koodia sellaisenaan, sillä oman ratkaisun muistaa paremmin jatkossakin. =)
He-ehei! En saanut itse ratkaistua ongelmaa, sain konsulttiapua isolla rahalla...
Mutta siinä olet oikeassa, että kun on saanut toimivaa koodia, voi sitä tutkia ja jopa välillä ymmärtää, miksi niin tehtiin. Pikkuhiljaa alkaa tajuta edes jotain.
;-)
Aihe on jo aika vanha, joten et voi enää vastata siihen.