Computer envelopes cartoon

Hasznos kiegészítő Word körlevélhez

A Word körlevélkészítés funkciójával (az angol nyelvű verzióban Mail Merge) egyszerűen tudunk tömegesen megszemélyesített leveleket létrehozni, vagyis olyan leveleket, amelyeknek bizonyos részei azonosak, bizonyos részei (például cím, megszólítás, számmezők, de akár komplett szöveges bekezdések) pedig levelenként változnak. A Word által így létrehozott körlevél egy, akár több száz vagy több ezer oldalas dokumentum. Ez az output tökéletesen megfelel, ha nyomtatni akarjuk a leveleket; de mi van, ha nekünk levelenként különálló Word vagy Pdf fájlokra van szükségünk? A Word beépített funkciója erre nem kínál megoldást, de egy rutinos makrókészítő nem esik kétségbe, hanem egy kis szkript segítségével áthidalja a hiányosságot.

Szöveges formában megfogalmazva az alábbi műveletsort szeretnénk a makrónkkal elvégeztetni:

  • keresse meg az első levelet,
  • másolja ki egy új Word fájlba, a formázás megtartása mellett,
  • adjon nevet a fájlnak: feltételezzük, hogy minden levél a címzéssel kezdődik, ahol az első szöveges sorban szerepel a címzett neve (és tegyük fel hogy ez a név egyedi)
  • mentse el a Word fájlt ezen a néven, ugyanabba a könyvtárba, ahol a körlevél dokumentum is szerepel,
  • ugyanezen a néven mentse el a levelet Pdf formátumban is,
  • a fenti műveletsort végezze el az összes többi levéllel.

Az egyes levelek azonosítása

Word Section Break A körlevél dokumentumunk feldarabolásához azt fogjuk felhasználni, hogy az egyes levelek egy-egy szakaszt (Section) alkotnak és közöttük szakasztörés (Section Break) található.

A rutinunk kerete így néz ki:

Option Explicit
Dim FajlNev  As String
Dim Korlevel As Document
Dim TempDoc  As Document

Sub Korlevelbol_Egyedi_Levelek()
    
Dim i As Long

Set Korlevel = ThisDocument

    Application.Browser.Target = wdBrowseSection

    For i = 1 To ((Korlevel.Sections.Count) - 1)

    '   [Műveletek]

        Application.Browser.Next
    Next i

End Sub

Az Application.Browser tulajdonsággal az ún. Selct Browse Object eszközt címezhetjük meg. Ez a kis eszköz amúgy megtalálható a Word jobb oldali gördülősáv alján.

Word Select Browse Object

Az  Application.Browser.Target tulajdonsággal beállíthatjuk, hogy az eszköz léptetésekor hova ugorjon a kurzor. Az alapbeállítás a következő oldalra ugrás, de lehetőségünk van többek között a megjegyzések, lábjegyzetek, címsorok, grafikák, táblák – és az Application.Browser.Target = wdBrowseSection utasítással a szakaszok – között lépdelni.

Magát a léptetést az Application.Browser.Next utasítással végezzük el. Felmerülhet a kérdés, hogy emellett az utasítás mellett mi szükség van a For … Next ciklusra. Az Application.Browser.Next utasítás csak a kurzort lépteti a következő szakaszra, nekünk viszont arra is szükségünk van, hogy a programunk újra és újra, minden egyes szakaszon végrehajtsa a cikluson belül szereplő utasítássort.

Feltűnhet, hogy a For … Next ciklusban a szakaszok számánál egyel kevesebbszer hajtjuk végre a műveletsort. Ennek oka, hogy a Word által generált körlevél dokumentum mindig szakasztöréssel végződik, és számláláskor az utolsó szakasztörés utáni részt is egy szakasznak veszi (tehát ha csak egy darab levelünk lenne, azt is két szakasznak számolja), viszont a legutolsó szakaszra vonatkozóan a cikluson belül végrehajtandó műveleteket (például másolás) már nem tudná elvégezni, és hibaüzenetet kapnánk – de ezen műveletek elvégzésére nincs is szükségünk.

Másolás külön fájlokba

A cikluson belüli első utasítással ki kell jelölnünk egy egész szakaszt, egész pontosan a kurzor és a kurzor utáni szakasztörés közötti szöveget. Ezt a következő utasítássorral tudjuk elérni:

        
        Korlevel.Bookmarks("\Section").Range.Copy

Bookmarks(“\Section”) objektum egyike az előre definiált könyvjelző objektumoknak, az aktuális szakaszt definiálja (vagyis azt a szakaszt, ahol a kurzor éppen áll), az elejétől a végéig, beleértve a lezáró szakasztörést is. Ahhoz, hogy egy másolható szöveget kapjunk, nem egy Bookmark típusú objektumra van szükségünk, hanem egy Range típusúra, ezért használjuk a könyvjelző .Range tulajdonságát. A másolást értelemszerűen a .Copy metódussal tudjuk elvégezni.

Következő lépésként hozzunk létre egy új, üres dokumentumot és rendeljünk hozzá egy változót:

        Set TempDoc = Documents.Add

Majd ebbe az üres dokumentumba másoljuk be az előző lépésben kimásolt szakaszt:

        With TempDoc.PageSetup
            .TopMargin = Korlevel.PageSetup.TopMargin 
            .BottomMargin = Korlevel.PageSetup.BottomMargin 
            .LeftMargin = Korlevel.PageSetup.LeftMargin 
            .RightMargin = Korlevel.PageSetup.RightMargin 
            .Gutter = Korlevel.PageSetup.Gutter 
        End With

        Selection.PasteAndFormat Type:=wdFormatOriginalFormatting

Azt, hogy a formázás ne változzon, két beállítással tudjuk elérni. Egyrészt másolás előtt beállítjuk a margókat úgy, hogy azok megegyezzenek az eredeti körlevél dokumentum margó beállításaival. Másrészt nem a .Paste metódust használjuk, mert ez esetben a formázást (betűtípus, betűméret, stb.) nem másolja, hanem az újonnan létrehozott dokumentum beállításait alkalmazza, hanem a .PasteAndFormat metódust, ahol megadhatjuk, hogy tartsa meg az eredeti formázási beállításokat.

Az új dokumentumban a szekciótörésre már nincs szükségünk, így töröljük azt:

        Selection.MoveLeft Unit:=wdCharacter, Count:=1
        Selection.Delete Unit:=wdCharacter, Count:=1

Vagyis a kurzort a .Left utasítással egy karakternyit balra léptetjük, majd a .Delete utasítással töröljük a kurzor mögötti karaktert (ami nem más mint a szakasztörés jel).

Ezután mentsük el az új dokumentumot a megfelelő könyvtárba a megfelelő néven:

	ChangeFileOpenDirectory Korlevel.Path
        FajlNev = CimAdas(TempDoc)
        TempDoc.SaveAs FileName:=FajlNev & ".docx"

ChangeFileOpenDirectory metódussal beállíthatjuk a mentés könyvtárának elérési útvonalát (ne tévesszen meg senkit, hogy az utasításban “Open” szerepel…), ami a példánkban megegyezik a körlevél dokumentum könyvtárával. A dokumentum elnevezéséhez pedig jelen esetben egy függvényt (CimAdas) használunk (lásd lejjebb).

Amennyiben Pdf-ként is menteni szeretnénk a levelet, azt egy külön szubrutin segítségével végezhetjük el, amit a levél lezárása előtt meghívhatunk:

        SavePdf

Végezetül zárjuk le az elmentett dokumentumot (most már újabb mentés nélkül):

        TempDoc.Close savechanges:=wdDoNotSaveChanges

A teljes eljárás egyben így néz tehát ki:

Option Explicit
Dim FajlNev As String
Dim Korlevel As Document
Dim TempDoc As Document

Sub Korlevelbol_Egyedi_Levelek()
    
Dim i As Long

Set Korlevel = ThisDocument

    Application.Browser.Target = wdBrowseSection

    For i = 1 To ((Korlevel.Sections.Count) - 1)

        Korlevel.Bookmarks("\Section").Range.Copy

        Set TempDoc = Documents.Add

        With TempDoc.PageSetup
            .TopMargin = CentimetersToPoints(2.25)
            .BottomMargin = CentimetersToPoints(2)
            .LeftMargin = CentimetersToPoints(2)
            .RightMargin = CentimetersToPoints(2)
            .Gutter = CentimetersToPoints(0)
        End With

        Selection.PasteAndFormat Type:=wdFormatOriginalFormatting

        Selection.MoveLeft Unit:=wdCharacter, Count:=1
        Selection.Delete Unit:=wdCharacter, Count:=1

	ChangeFileOpenDirectory Korlevel.Path
        FajlNev = CimAdas(TempDoc)
        TempDoc.SaveAs FileName:=FajlNev & ".docx"
        
        SavePdf
        
        TempDoc.Close savechanges:=wdDoNotSaveChanges

        Application.Browser.Next
    Next i    
    
End Sub

Fájlok elnevezése

Mail Merge Address boxAhogy a bevezetőben olvasható, példánkban a levelek címzéssel kezdődnek, az első szöveges sorban szerepel a levél címzettje, akinek a nevét szeretnénk a fájl neveként felhasználni. Az első szöveges sor nem feltétlenül a dokumentum első sora, a dokumentum kezdődhet sortörésekkel: ennek programozáskor lesz jelentősége.

Function CimAdas(Doc As Document) As String

Dim i As Long

    i = 0
    Do
        i = i + 1
        CimAdas = Doc.Paragraphs(i).Range.Text
    Loop While Len(CimAdas) <= 1

        With Doc
            CimAdas = Left(CimAdas, Len(CimAdas) - 1)
            CimAdas = Replace(CimAdas, "\", "")
            CimAdas = Replace(CimAdas, "/", "")
            CimAdas = Replace(CimAdas, ":", "")
            CimAdas = Replace(CimAdas, """", "")
            CimAdas = Replace(CimAdas, vbCr, "")
            CimAdas = Replace(CimAdas, vbTab, "")
        End With

End Function

A függvényünk két részből áll. Az első részben egy Do … Loop ciklussal megkeressük az első szöveges sort (a pontosság kedvéért: az első olyan sort, ami egy karakternél hosszabb, ahol az egy karakteres sorok sortöréseket jelentenek), ez lesz a fájlnevük kiinduló állapota. Ezután a Replace függvény segítségével törlünk (helyettesítünk) minden olyan karaktert, ami a fájlnévben nem használható.

Pdf készítése

A megnyitott Word dokumentumot Pdf-ként elmenteni – jelen példánkban – az ExportAsFixedFormat metódussal fogjuk:

Sub SavePdf()

    TempDoc.ExportAsFixedFormat _
        OutputFileName:=FajlNev & ".pdf", _
        ExportFormat:=wdExportFormatPDF, _
        OpenAfterExport:=False, _
        OptimizeFor:=wdExportOptimizeForPrint, _
        Range:=wdExportAllDocument

End Sub

Itt paraméterként – többek között – megadhatjuk a fájl nevét, formátumát és hogy az egész dokumentumot exportáljuk-e (lehetőség van egy-egy oldal, vagy meghatározott kijelölés exportálására is).

25 thoughts on “Hasznos kiegészítő Word körlevélhez

  1. Nahát! Ez pontosan az,amit kerestem,nagyon köszönöm! Érthető és hasznos! 🙂
    Egyetlen kérdésem lenne. Megoldható,hogy a fájl neve más legyen? Mondjuk az aktualis dátum és a dokumentum egy adott pontján lévő szöveg?
    Pl a tárgya a dokumentumnak (figyelmeztetés,gratuláció,stb) ami a levélben szerepel valahol?
    Nagyon szépen köszönöm!

    1. Kedves István, először is üdvözlöm a blogon!
      A válasz egyértelműen igen. A megvalósítás attól függ, hogy a dokumentumon belül hogyan tudjuk azonosítani a keresetett szüveget.
      A példámban a Do…Loop ciklus az első szöveges sort keresi meg, és az lesz a cím. Ha viszont, ettől eltérően, például a dokumentum tulajdonságai között szereplő címét szeretnénk használni, akkor a BuiltInDocumentProperties attributum körül kell keresgélni. Ha például az oldalon ‘Heading1’-ként formázott szöveg tartalmazza a keresett szót, akkor formázásra lehet keresni. Ha van egy listánk a keresett kifejezésekről, és feltételezzük, hogy a dokumentum ebből csak egyet tartalmaz, akkor a listára lehet futtatni egy keresést (lásd a “Továbbfejlesztett keresés” című bejegyzésemet, azt kis átalakításokkal át lehet ültetni Word-re). Vagy kereshetünk a “Tárgy:” kifejezésre, és mondhatjuk azt, hogy minden, ami ezután szerepel a sorban, az lesz a fájlnevünk.
      Az aktuális dátumot pedig a Date függvénnyel lehet előhívni, csak a formátum átalakításáról (pl “yyyymmdd”, vagy amit szeretnénk) kell gondoskodni.

  2. Tisztelt Kántor Ádám!

    Körlevél készítésénél tapasztaltam, hogy:
    a forrás állományból (excel) kiválasztott cellában több mint 256 karakter (pl. 1185 db) van és a körlevélben csak 255 darab karakter jelenik meg.
    Mi lenne a jó megoldás?

    Köszönettel,
    tapai

    1. Kedves József!
      Üdvözlöm a blogon!
      Amikor a Word adatokat húz be Excelből (Accessből, stb…), akkor a mező adattípusát az első néhány mező alapján határozza meg (talán első 8, de ebben nem vagyok biztos). Ha ebben a néhány mezőben nincs 255 karakternél hosszabb szöveg, akkor az adattípust “Text” (vagy “Short Text”)-nek veszi, ami maximum 255 karakter lehet, így a későbbi mezőket is megvágja 255 karakternél. Ha az első mezők között szerepel hosszabb szöveg, akkor “Long Text” (régebbi elnevezésén “Memo”) adattípust állít be, ami – ha jól emlékszem – 1 gigabájtnyi szöveget enged.
      Amit én alkalmazni szoktam, hogy a forrás excel tábla első rekordját dummy adatokkal töltöm fel (érdemes figyelni az adattípusra, tehát ha egy oszlop csak egész számokat tartalmaz, akkor a dummy adat is egy egész szám legyen), ahol a kérdéses oszlopba egy jó hosszú szöveget kell írni (például 256 darab x-et). A körlevél beállításainál pedig be lehet állítani, hogy az első rekordból ne készítsen levelet.

      1. nagyon köszönöm, ezek szerint fogok eljárni
        a blogot tanulmányozni fogom, mert tetszik
        üdv,
        tapai

      2. Kedves Ádám! Nagyon köszönöm, ez annyira hasznos volt, hogy azt elmondani nem tudom. Lehet, hogy már nem is működik ez az oldal (elég régiek a bejegyzések), de muszáj megírnom, milyen hálás vagyok (pláne, hogy kiderült, nem én vagyok a teljesen oktondi :-)).
        Köszönöm a segítséget!
        Andrea

        1. Kedves Andrea! Örülök, ha így látja, köszönöm a visszajelzést! És köszönöm a célzást, igyekszem újra időt keríteni, hogy újra működőnek látszódjon az oldal, témám akadna bőven 🙂

          1. Én pedig (másokkal együtt) sok új, hasznos infóhoz juthatnék :-). Részemről várom!

  3. Kedves Ádám!
    Ha egyesítem a körleveleket akkor az új “levél1.doc” file már nem látja a makrót. Ezt hogy lehet meghivatkozni.
    Köszönöm,

    1. Kedves Márton, köszöntöm a blogon!
      A leírásából nem egyértelmű nekem, hogy pontosan mi okozza a problémát, ezért nem tudom, sikerül-e megválaszolnom.

      Ha arra gondolt, hogy miután a sok levelet tartalmazó fájlt a makró segítségével feldarabolta (például levél1.doc, levél2.doc, levél3.doc, stb. elnevezésű fájlokra), hogyan lehet az egyes levelekkel további műveleteket végezni, akkor a hivatkozás a lentiek szerint működik:
      Feltételezve, hogy tempDoc nevű változóba mentjük az objektumhivatkozást (Dim tempDoc As Document)
      – ha már meg van nyitva a fájl, akkor:
      Set tempDoc = Documents(“levél1.doc”)
      – ha még nincs nyitva, akkor a hivatkozáshoz és további műveletekhez így nyitható meg:
      Set tempDoc = Documents.Open(“C:\temp\levél1.doc”)

      Ha az összes lementett dokumentummal el szeretnénk végezni egy adott műveletet, akkor érdemes lehet erre a célra létrehozni egy gyűjteményt (collection), és az egyedi fájl mentése után eltárolni a hivatkozását ebbe, majd egy iterációval egyenként meg lehet nyitni a fájlokat és elvégezni rajutuk a kívánt műveleteket. Alternatívaként még az egyedi fájl bezárása esetén el lehet rajta végezni a műveleteket (a blogbejegyzésben szereplő példában is TempDoc-ként hivatkozunk az egyedi fájlra).

      1. Kedves Ádám!
        Egy példa:
        Van egy körlevél_sablon.doc állomány (ebbe van a makró) + a hozzá tartozó körlevél_sablon.xlsx állomány. Ha a sablont megnyitom az excel fileból behúzza az adatokat a word-be. Ez után ha a befejezés és egyesítés gombra kattintok akkor létrejön egy levél1 dokumentum. Na ebből a fileból nem tudom futtatni a makrót, mert nem látja. E miatt el sem jutok a darabolásig.
        Köszönöm válaszát.

        1. Kedves Márton,
          Ha jól értem, maga a körlevélkészítés még kézzel történik, nem makróval, és a sablon fájlban lévő makrót a körlevél elkészülte után szeretné futtatni.
          Ez esetben is lehet a makrót a sablon fájlból futtatni, a blogbejegyzés elején szereplő hivatkozást kell cserélni –
          erről:
          Set Korlevel = ThisDocument

          -ha a fájl már el lett mentve levél1.doc néven és nyitva van:
          Set Korlevel = Documents(“levél1.doc”)
          -ha még nincs elmentve ÉS FELTÉTELEZVE, hogy más fájlt nem nyitottunk meg a körlevél generálása óta:
          Set Korlevel = Documents(Documents.Count)
          ez utóbbi utasítás az utolsóként megnyitott/létrehozott fájlra hivatkozik a ‘Korlevel’ változóval.

          1. Kedves Ádám!

            Kaptam egy újabb dokumentumot, amin sajnos a fenti kódot az alábbi okból nem tudom alkalmazni. A dokumentum tartalmaz egy táblázatot is ami fektetett fomában van a wordben. Emiatt nem egy hanem 3 szakasztörést eredményez dokumentumonként.

            Hogyan tudom megmondani a vba-nak, hogy minden 3-nál tördelje a körlevelet?

            Köszönöm,
            Marci

          2. Kedves Marci!

            A leírás alapján feltételezem, hogy a táblázat elé és mögé egy ” Section Break (Continuous) ” típusú elválasztót rak be, míg az oldaltörésekhez ” Section Break (Next Page) ” típusút; a blogbejegyzésben leírtak ezt tényleg nem figyelik, minden Section Break elválasztót egyenrangúnak vesz. Én kétféle megközelítést próbálnék ki, mindkettőnél a For…Next cikluson belülre kell rakni még egy feltételvizsgálatot, vagyis a
            For i = 1 To ((Korlevel.Sections.Count) - 1)” sor után:

            1. kód végrehajtása minden harmadik elválasztónál
            Ez esetben az i számlálót vizsgáljuk, ha osztható hárommal, akkor végrehajtjuk a műveleteket, ha hamis, akkor továbblépünk a következő szekcióra; ezt a “mod” operátorral tehetjük meg.

            For i = 1 To ((Korlevel.Sections.Count) - 1)
            If i mod 3 = 0 Then
            'Műveletek
            End If
            Application.Browser.Next
            Next i

            2. kód végrehajtása csak a “Next Page” típusú elválasztóknál
            Ez esetben azt vizsgáljuk, hogy az elválasztó típusa milyen, és csak akkor hajtjuk végre a műveleteket, ha az “Next Page” típusú.

            For i = 1 To ((Korlevel.Sections.Count) - 1)
            If Korlevel.Sections(i).PageSetup.SectionStart = wdSectionNewPage Then
            'Műveletek
            End If
            Application.Browser.Next
            Next i

  4. Kedves Ádám! Ismét egy probléma, amelyet saját kútfőből nem tudok megoldani, kérem, segítsen (Ön biztos tud :-)).
    Excel táblázat, ebből egy word körlevél dokumentum készül. Az adatmezőkkel nincs problémám, de a körlevélbe képeknek is be kellene húzódniuk (ráadásul körlevelenként más-más képnek, és nem is egynek) . Azért a feltételes mód, mert ez az, amit nem tudok megoldani.
    Az excel tartalmazza azt az oszlopot, ahova a képek elérési helyét belinkeltem. A word körlevél tartalmazza azt az adatmezőt, ahol a képnek meg kellene jelennie (beszúrás, kész modulok, mező, insertpic, stb). És itt megáll a tudomány, mert a kép helyén csak egy piros X látszik az alap körlevél dokumentumban is, és összefűzés után is. Könnyen lehet, hogy már az alapdokumentum is rossz, és valahogy máshogy kellene csinálni. Tud segíteni, hogy hogyan lehet ezt megoldani?
    Köszönöm szépen előre is!
    Andrea

  5. Kedves Ádám!
    Szakértelmed és segítséged reményében fordulok hozzád problémámmal. Az excelben kalkulált adatokat körlevél szerkesztő segítségével szeretném word-ben szövegkörnyezetben megjeleníteni. Ehhez több mint 255 különböző mezőre lenne szükségem, azonban a word csak az első 255 darab mező (oszlop) beszúrását engedi. Az ezen túliak nem jelennek meg a mező beszúrásakor, úgy mintha nem is lennének.
    Hogy lehetne több mezőt használni?
    Segítséged előre is köszönöm!

    1. Kedves Misi!
      A 255 mezős korlátozás a Microsoft adatbázis motorjának a sajátja, ezt tudtommal nem lehet kikerülni: akkor sem, ha Excel helyett valami más adatbázist használnánk, és akkor sem, ha körlevél helyett programatikusan próbálnánk adatokat lekérdezni adatbázisból (pl. ADO API-n keresztül SQL-el).

      Az egyik irány, ami eszembe jutott, hogy csökkenteni lehetne a körlevél által használt mezők számát. Egy egyszerű példával: ha a táblában külön-külön mezőink vannak az irányítószámnak, városnak, utcának, házszámnak, abból összefűzéssel még az Excelben lehet képezni egy cím mezőt, és a körlevélbe ezt az egy cím mezőt lehet beolvasni. De ez akár komplett mondatokra, bekezdésekre is működhet, segédtáblákkal, kreatív képletezéssel (feltétel vizsgálatok, behelyettesítések, összefűzések, sortörés karakterek beillesztése, stb.) egész dinamikus szöveg blokkokat lehet már az Excelben gyártani, és azokat egy mezőként a körlevélbe berakni.

      A másik irány, amit én használni szoktam, hogy programmal oldjuk meg az egész feladatot, a körlevélkészítést teljesen kikerülve. Ehhez először egy sablon Word fájlt kell készíteni, abba szövegként berakni a placeholdereket (pl.: %%mezo_1%%). A programnak nagy vonalakban ezt kell tennie:

      • Iteráció a forrás tábla rekordjain. Minden egyes rekordhoz:
      • Új .docx fájl nyitása (vagy igény szerint új oldal/szekció kezdése), tartalom másolása a sablon fájlból.
      • Iteráció a forrás tábla mezőin. Minden egyes mező érték vonatkozásában:
      • Összes hozzá tartozó placeholder megkeresése és szöveg cseréje
      • Egyedi Word fájlok gyártása esetén fájl mentése, bezására

      Ez utóbbi megoldás előkészítése azért időigényesebb, mint a körleveles megoldásé, de sokkal kreatívabban használható: többféle template-ből dinamikusan válogathat, képeket vagy egyéb tartalmakat letet beilleszteni, változó méretű táblázatokat lehet vele gyártani, további formázásokat, kalkulációkat lehet elvégezni.

  6. Kedves Ádám!
    Olvasgatva a fórumot, nagyon sok hasznos dolgot találtam, és tanultam is belőle.
    Jelenlegi feladatomnál sajnos makro nem megoldható, mivel többféle kimutatásból, többféle változó mezőből kell pár körlevelet összetenni, ahol a mezők nevei változnak.
    Ez összesen jelenleg 3 ilyen kimutatás van.
    Ezeket jelenleg még egyszerűbb kézzel megcsinálni.
    Ami a problémát okozza, hogy grafikus megjelenítést is át kellene emelnem WORD körlevélre, viszont amit találtam plug-int “Merge Tools” valami hiba miatt folyamatosan megáll memória címzési hiba miatt.
    Az lenne a kérdésem, hogy van-e valamilyen egyszerűbb megoldás a grafikon körlevélbe való átemeléséhez?
    Köszönettel:
    Gyuri

    1. Kedves Gyuri!
      Grafikonok körlevélbe ágyazásával kapcsolatban sajnos nincs gyakorlati tapasztalatom, úgyhogy amit meg tudok osztani az, hogy én milyen irányban indulnék el. De ha jól értem, két megoldandó téma van: többféle változó mező és grafikon.

      A Merge Tools programot nem ismerem, de a készítője azt írja, hogy probléma esetén kapcsolatba lehet vele lépni: egy próbát megérne a dolog. Ezen a linken van egy jpg fájl, ott van egy email cím, én azon próbálkoznék először.

      A többféle változó mező kapcsán nem lehet megoldás egy segédtábla készítése, ahová a 3 kimutatásból behúzod az adatokat, és onnan már mehet a körlevél egységes mezőnevekkel?

      Ha a fentiek nem működnek, én azért megpróbálnám makróval. Egy megoldás lehet, ha nem is a legegyszerűbb, hogy a Word körlevél funkciója helyett “emuláljuk” annak működését. Ennek egyik (talán egyszerűbb) része, hogy a szükséges adatokat beolvassuk a 3 kimutatásból (memóriába / változóba), a másik (bonyolultabb) része, hogy az adatok alapján egy/több Word fájlt generálunk – ez utóbbihoz azért el kell merülni a Word objektumkönyvtár használatában, de működik a gyakorlatban. Grafikonok átemelését ezzel a módszerrel sem próbáltam még, de biztos vagyok benne, hogy le lehet programozni.

  7. Kedves Ádám,
    Köszönöm a szenzációs makrót, sikerült a darabolás és átnevezés is. Ami problémát jelentett (ebben kérném a segítséged) az, hogy a makrót hova mentsem. Ha a normal dotm-ba mentette a rendszer, akkor működött. Ha viszont csináltam egy körlevél.dotm dokumentumot, ami a makrót tartalmazta és mellé megnyitottam a darabolandó kész körlevelet (kész.cocx), akkor a következő hibaüzenetet írta ki: A gyűjtemény kívánt tagja nem létezik. Mindezt a Korlevel.Bookmarks(“\Section”).Range.Copy sornál követte el.
    Az előtte lévő sorok így néznek ki:
    Set Korlevel = Documents(“Kész.docx”)
    Application.Browser.Target = wdBrowseSection
    For i = 1 To ((Korlevel.Sections.Count) – 1)
    Korlevel.Bookmarks(“\Section”).Range.Copy

    Válaszodat nagyon várom és előre is köszönöm.

    1. Kedves László!

      Ha jók a sejtéseim, a hibaüzenetet csak áttételesen befolyásolja az, hogy hová van mentve a makró. A hibát okozó sor, azon belül is a Bookmarks("\Section") hivatkozás csak az aktív dokumentumban működik. Amikor futtattad a makrót, minden valószínűséggel a körlevél.dotm fájl volt az aktív, nem a kész.docx fájl. A Set Korlevel = Documents("Kész.docx") sor után illessz be még egy sort:


      Korlevel.Activate

      ez aktiválja a Kész.docx dokumentumot, és ez nálam meg is oldotta a problémát.

      A mentés helyével kapcsolatban: én a .docm fájlnak egy standard moduljába raknám a makrót.

  8. Kedves Ádám!
    Persze, ez eszembe juthatott volna.
    Még annyit kérdeznék:
    Van az élőfejben egy logó és egy enter
    A szövegben 8 klf bekezdés van enterrel lezárva, majd jön egy
    Név: TAB jel, majd a Dolgozó_ neve_korlevmező sor.
    Innen kéne a dolgozó nevét kiszednem, mert ebből képzem a fájlnevet fenti leírásod alapján.
    Hogyan tudom ezt megtenni. Úgy működött, hogy az első sorban volt a dolgozó neve.
    Köszönettel László

    1. Kedves László!
      Amiatt nem egyszerű a dolog, mert miután kész, adatokkal kitöltött körlevél dokumentum elkészült, ebben a dokumentumban már nincsenek benne a körlevél készítéshez használt mezők, így azok alapján nem lehet egyszerűen keresni.

      Két megoldás jutott eszembe, amik működhetnek, ha bizonyos feltételek teljesülnek.

      Az első a blogbejegyzésben szereplő névadás továbbfejlesztése: itt nem az első szöveges sort keressük meg, hanem az első sort, ami úgy kezdődik hogy “Név:” (a Loop While Len(CimAdas) <= 1 sor helyett lehet például Loop While Instr(1, CimAdas, "Név:", vbTextCompare) < 1), majd ebből kinyerjük a dolgozó nevét (vagyis a "Név:" utáni karaktereket).

      A második kód szempontjából kicsit bonyolultabb (legalábbis VBA-ban), de univerzálisabban használható (amire jelen esetben nem biztos hogy szükség van, de máskor jól jöhet): RegEx (Regular Expression) használata. Nem tudom, találkoztál-e már RegEx-szel, ha nem, akkor ez az oldal egy egész jó kis áttekintést ad (én is Google-ből kerestem most, biztos létezik még sok hasonló): RegEx. Illetve egy általam sokat használt oldalt tudnék még RegEx témában ajánlani: regex101.com - itt lehet tesztelni, próbálgatni.

      Feltételezve, hogy a "Név:" csak egyszer szerepel a dokumentumban, és a név sorban a dolgozó neve után már nem szerepel semmi, a kapcsolódó függvény valahogy így nézhet ki:

      Public Function DolgozoNeve() As String
          Dim s as String
          s = ActiveDocument.Range.Text 'ActiveDocument helyett a mentendo dokumentum hivatkozasa
      
          Dim re As RegExp
          Set re = New RegExp
          
          re.Pattern = "Név:\t([\w\s]+\w)$"
          re.Global = True
          re.MultiLine = True
          
          Dim Matches As MatchCollection
          Set Matches = re.Execute(s)
          
          Dim m As Match
          For Each m In Matches
              Dim n_groups As Long        
              n_groups = m.SubMatches.Count
              If n_groups >= 1 Then
                  DolgozoNeve = Trim(m.SubMatches.Item(0))
                  Exit Function
              End If
          Next m
      
      End Function
      
  9. Kedves Ádám,
    A körlevél sikeresen elkészült, köszönet a sok segítségért

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.