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
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.

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
A 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"
A 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
Ahogy 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).

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!
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.
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
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.
nagyon köszönöm, ezek szerint fogok eljárni
a blogot tanulmányozni fogom, mert tetszik
üdv,
tapai
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
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 🙂
Én pedig (másokkal együtt) sok új, hasznos infóhoz juthatnék :-). Részemről várom!
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,
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).
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.
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.
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
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
Kedves Ádám!
Köszönöm, ismét sokat segített 🙂
üdv,
Marci
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
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!
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:
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.
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
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.
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.
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. ASet 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.
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ó
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) <= 1sor helyett lehet példáulLoop 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 FunctionKedves Ádám,
A körlevél sikeresen elkészült, köszönet a sok segítségért
Tisztelt Szerző!
2025-öt írunk
Windows 11 és Ofice LTSC Professional Plus 2021 használok
Pont a megadott makróra lenne szükségem
Bemásoltam egy önálló modulba.
Ugyan nem fut hibára de nem is csinál semmit. Hol kell aktualizálni?
Köszönöm
Kedves József!
Így újra átfutva a kódot, nem tűnt fel semmi, ami ne lenne kompatibilis az Office 2021-es verziójával.
Amit nulladik lépésben ellenőriznék, hogy minden használt modul elején szerepel-e az
Option Explicitutasítás (ez biztosítja, hogy a hibák egy jó részét már a compiler megtalálja).Ha ezután is lefut a program, de hibaüzenet nélkül, akkor a következő gyanúm, hogy a dokumentumban nincsenek Section Break-ek –> ezt az alapból rejtett formázó szimbólumok megjelenítésével lehet ellenőrizni.
Ezen felül látatlanban nehéz bármit mondani, a kódon debug mode-ban végiglépdelve ellenőrizném a kritikus részeket (pl. látja-e a szekciókat, vagyis a
Korlevel.Sections.Countváltozó 1-nél nagyobb számot mutat, és belép-e az iterációba; ha igen, akkor az iteráción belül legenerálja-e az új dokumentumot, tud-e neki egyedi nevet generálni, illetve maga a mentés sikeres-e).Köszönöm a gyors választ.
Igazából az alap problémát az elégtelen MS Word makró ismeretem adja.
Fogtam a megadott makrót és bemásoltam egy Modulba. Hibát jelzett ezért ugyanezen modulba legalulra beillesztettem a Fájlok elnevezése és a Pdf készítése makró részeket
Ezek elválasztó vonallal vannak “elszeparálódva” egymástól
Elindítva nem jelez hibát de igazából nem is történik semmi érdemleges. F8 al lépésenkénti végrehajtással eljut a FOR i = 1 … sorig majd a következő F8 ra leugrik az END SUB sorra. A közbenső utasítások mintha ott sem lennének.
Köszönőn ha segítségemre lesz
A leírtak alapjánaz a helyzet állhat fent, hogy nincsenek szekció elválasztók a dokumentumban. Ha a Word körlevél (Mail Merge) funkciójával készítette a dokumentumot, akkor az egy többoldalas dokumentum, ahol egy-egy címzett levele 1-1 oldalt foglal egy (vagy lehet akár több oldal is levelenként), és az egyedi levelek Section Break-el vannak elválasztva.
Ez elvileg nem változott, most Office365-el kipróbálva is Section Break elválasztókkal gyártotta le a Word a körlevelet.
Ha esetleg a körlevél másképp készült, akkor a Section Break-ek hiányozhatnak, viszont ezek megléte szükséges, hogy a makró működjön.
(Elméletileg az oldalankénti szétszedés sem lehetetlen, viszont jóval bonyolultabb, mivel az oldal, mint olyan, nem egy egzakt objektum a Word-ön belül, mert az hogy mennyi szöveg van egy oldalon, függ a margóktól, betűmérettől, nyomtató beállítástól, sortörésektől, oldaltörésektől, oszloptörésektől, stb., úgyhogy azt a Word dinamikusan számolja. Ezzel ellentétben a Section Break-ek konkrét objektumok, pontos pozcióval.)
Nem tudok képet beilleszteni.
Szakasztörés (új oldal)
vannak elválasztva
önálló makró modulba futtatva az Application.Browser.Next utasítás működik
Ciklusba rakva ha fix darabot kérek – jelen esetben 12 db – akkor lefut az ugrás
viszont a ((Korlevel.Sections.Count) – 1) már hibára fut
Option Explicit
Dim FajlNev As String
Dim Korlevel As Document
Dim TempDoc As Document
Dim i As Long
Sub Makró1()
‘
‘ Makró1 Makró
‘ próba
‘
For i = 1 To ((Korlevel.Sections.Count) – 1)
Application.Browser.Next
Next i
End Sub
Error 91
Object variable or with block variable not set
Ellénézést az amatőr kérdések miatt. Nulla WORD makró ismeretein vannak.
Kedves Szerző!
Ha fix db számra állítom akkor lefut szépen.
Set Korlevel = ThisDocument
For i = 1 To 12
Application.Browser.Next
Next i
End Sub
Ha beállítom a ((Korlevel.Sections.Count) – 1) számlálónak akkor a For után azonnal az End Sub ra ugrik
Set Korlevel = ThisDocument
For i = 1 To ((Korlevel.Sections.Count) – 1)
Application.Browser.Next
Next i
End Sub
Az
Application.Browser.Nextalapból a következő oldalre ugrik, nem a következő szakaszra. Ahhoz, hogy a szakaszok között ugráljon, előtte át kell állítani a Target-et:Application.Browser.Target = wdBrowseSectionHa lefuttatja a lenti kódot, milyen számot dob ki?
Sub Test()
MsgBox ThisDocument.Sections.Count
End Sub
Ez a szakaszok számát olvassa ki, ami egyenlő a szakasztörések száma +1-el.
Ha ez 1-et ad ki, akkor valami miatt a szakasztöréseket nem tudja értelmezni (pedig az Ön által írt “Szakasztörés (új oldal”) az általam írt “Section Break (Next Page)” magyar megfelelője).
Még egy valami beugrott, ami okozhatja a jelenséget.
A kód szerkesztőben két hely van, ahová makrót lehet írni.
A struktúra valahogy így nézhet ki (a megnevezések lehetnek mások):
+-Normal
|˙˙˙|--Microsoft Word Objects
|˙˙˙|--Modules
|˙˙˙˙˙˙|--Module1
+-Project(Document1)
˙˙˙|--Microsoft Word Objects
˙˙˙|--Modules
˙˙˙|˙˙|--Module1
˙˙˙|--References
Ahhoz, hogy a makró a jelenleg nyitott dokumentumra vonatkozzon, nem a “Normal” alatti modul(ok)ba, hanem a projekt (nálam Project) alatti modul(ok)ba kell írni.
Ez még megér egy ellenőrzést.
EZ AZ!
Köszönöm. Itt lesz a kutya elásva. Elindul, le is képezi az első .DOCX állományt. De a .PDF -nél elakad Variable not defined el.
OutputFileName:=FajlNev & “.pdf”, _
Mire kellene definiálni?
Bocsi 0% Word makró ismereteim vannak.
ÉS köszönö a segítséget
Eddig eljutottam :
Option Explicit
Dim FajlNev As String
Dim TempDoc As Document
Erre
ObJECT VARIABLE OR WITH BLOCK VARIABLE NOT SET
hibaüzenet
Valami nincs beállítva. De mi és hol?
Jelen példában a
Dim FajlNev As StringésDim TempDoc As Document-nek eljárásokon kívül kell lenniük (ha közvetlenül azOption Explicitalatt vannak, akkor az jó), és valahol a cikluson belül kell lennie aSet TempDoc = Documents.Addsornak, illetve szintén a cikluson belül kell lennie aSavePdfsornak.Ezen kívül, a cikluson belül kell lennie a sornak, ami meghatározza a nevet (a példámban
FajlNev = CimAdas(TempDoc)), itt debug mode-ban max azt érdemes megnézni, hogy valid nevet kapunk-e vissza aCimAdasfüggvényből.Illetve, nem tudom Önnél be van-e kapcsolva az automatikus szintaxis ellenőrzés, de futtatás előtt a VBA szerkesztőből érdemes kézzel lefuttatni: Debug >> Compile VBA Project
Ez kidobja, ha esetleg valami gépelési hiba maradt benne, vagy valamelyik változó nincs definiálva (mert például nem jó scope-ban definiáltuk).
Sub Test()
MsgBox ThisDocument.Sections.Count
End Sub
Eredmény 1
Jó lenne ha képernyő videot lehetne csatolni.
Tisztel Szerző!
Eddig jutottam el. Az alábbi makróval. A PROJECT egyedi file MODULES ból futtatva Korlevel.docm mentett állományban.
Module1:
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”
Rem SavePdf
TempDoc.Close savechanges:=wdDoNotSaveChanges
Application.Browser.Next
Next i
End Sub
Module2:
Option Explicit
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
Module3:
Option Explicit
Dim FajlNev As String
Dim TempDoc As Document
Sub SavePdf()
TempDoc.ExportAsFixedFormat _
OutputFileName:=FajlNev & ".pdf", _
ExportFormat:=wdExportFormatPDF, _
OpenAfterExport:=False, _
OptimizeFor:=wdExportOptimizeForPrint, _
Range:=wdExportAllDocument
End Sub
A kívánt eredményt adja. Az első sorban lévé szöveg adja a file nevét. Annyi állományt ment amennyi egyedi körlevél képződik.
A .PDF mentés nem fut le Object variable or With block variable not set hibaüzenettel. Igy ezt REM be raktam.
A kérésem az lenne. Hol és mit kellene átírni, hogy a NORMAL ba is fusson, hogy a NORMAL.DOT ba is menthető legyen és álltalánosan működjön?
A körlevél egyesítése után Levél1 nevű állományt kapok. Ebben kellene a makró futtatását indítani. Önálló névvel .DOCX és .PDF állományokban.
Köszönök minden eddigi és jövőbeni segítséget.
A pdf mentéssel kapcsolatban:
Ha külön modulokba szétszedi az eljárásokat, akkor a modul szinten (Option Explicit alatt) deklarált változók nem lesznek elérhetők egymás számára. Ezért nem fut a
SavePdfeljárás, mert sem a dokumentum, sem a fájlnév nem létezik számára, csak üres változók. Ez könnyen orvosolható, ha paraméterként átadjuk neki:Module 3:
Option Explicit
Sub SavePdf(ByVal FajlNev As String, ByVal Doc As Document)
Doc.ExportAsFixedFormat _
OutputFileName:=FajlNev & ".pdf", _
ExportFormat:=wdExportFormatPDF, _
OpenAfterExport:=False, _
OptimizeFor:=wdExportOptimizeForPrint, _
Range:=wdExportAllDocument
End Sub
A Module1-ből pedíg így kell meghívni:
SavePdf FileNev, TempDocAhhoz, hogy NORMAL.DOT alól is fusson, szerintem egy dolgot kell változtatni:
Set Korlevel = ThisDocumenthelyettSet Korlevel = ActiveDocument.Értelemszerűen ez esetben a makró akkor fog rendben futni, ha a feldolgozandó körlevél fájl az épp aktív dokumentum.