Страницы: 1
RSS
Ошибка 91 при попытке скопировать документ
 
Вкратце, ошибка "Run-time error '91' Object variable or With block variable not set" в строке с копированием:
Код
Sub main()
Dim wdApp As Object 'Переменная для модуля управления Word документами
Dim wdDoc As Object 'Переменная для открытия и работы с итоговым документом
Dim wdTemplate As Object 'Переменная для файла шаблона
HomeDir$ = ThisWorkbook.Path 'Путь к общей папке
Set wdApp = CreateObject("Word.Application") 'создание модуля управления Word файлами
wdApp.Visible = True

Set wdDoc = wdApp.Documents.Add 'создаем пустой файл Word

'открыть шаблон, скопировать из него данные и закрыть
Set wdTemplates = wdApp.Documents.Open(HomeDir$ + "\Templates\" + Cells(2, 3).Text)
wdTemplate.Range.Copy
wdTemplate.Close False

'вставить в основной документ
wdDoc.Selection.Paste
wdDoc.Selection.TypeParagraph

Написал скрипт, который автоматически заполняет данными из таблицы шаблон word(папка Templates) и сохраняет(в папку Result) на каждого студента(см макрос module 1 по кнопке "сделать красиво"). Появилась необходимость сразу объединить доки всех студентов и, в идеале, сохранить в пдф, чтобы сразу на всех отправить на печать. С PDF разобрался, а вот с объединением решил делать так(module 2 по кнопке "объединить"):
Копирую шаблон, создаю документ, вставляю в него текст, меняю данные, вставляю снова текст, меняю данные и повторяю столько раз, сколько студентов. Затем сохраняю в DOCX и PDF.
Для начала решил просто проверить копирование текста из одного файла в другой, поэтому вставка не в цикле. Нагуглил такое решение, человеку помогли, но с заранее созданными документами, прописанными в экселе https://www.planetaexcel.ru/forum/index.php?PAGE_NAME=message&FID=1&TID=94642
У меня же на строчке wdTemplate.Range.Copy выдает ошибку, описанную выше.
Пробовал создать переменную bufer как Variant, Range и Object, чтобы в нее сохранять оператором Set, но эффекта никакого. Подскажите, в чем может быть проблема. Заранее спасибо.
 
По поводу ошибки - найдите два отличия :)
Set wdTemplates = wdApp.Documents.Open(HomeDir$ + "\Templates\" + Cells(2, 3).Text)
wdTemplate.Range.Copy

Но это может и не помочь, т.к. при первом запуске создается пустой документ, а при открытии второго(заполненного) - пустой удаляется. Такая вот схема. И по сути, при открытии шаблона, у Вас некуда будет вставить скопированное, т.к. пустой документ будет отсутствовать.
Попробуйте вместо всего вот этого:
Код
Set wdDoc = wdApp.Documents.Add 'создаем пустой файл Word
'открыть шаблон, скопировать из него данные и закрыть
Set wdTemplates = wdApp.Documents.Open(HomeDir$ + "\Templates\" + Cells(2, 3).Text)
wdTemplate.Range.Copy
wdTemplate.Close False

'вставить в основной документ
wdDoc.Selection.Paste
wdDoc.Selection.TypeParagraph

записать всего короче и правильнее:
Код
Set wdDoc = wdApp.Documents.Add(HomeDir$ + "\Templates\" + Cells(2, 3).Text) 'создаем пустой файл Word на основе указанного файла как шаблона

Да и сохранение в PDF лучше делать не через метод SaveAs, а через экспорт:
Код
wd.ExportAsFixedFormat HomeDir$ & "\Result\" & Replace(Cells(I%, 2).Text, ".docx", ".pdf"), 17


А здесь можете скачать готовую универсальную модель по созданию файлов на основе шаблона: Как из Excel обратиться к другому приложению

P.S. Для объединения строк в VBA лучше использовать не знак +, а амперсанд: &. Это правильнее и избавляет от ошибок в ситуациях конкатенации чисел.
Изменено: Дмитрий(The_Prist) Щербаков - 20.06.2024 11:58:40
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Дмитрий(The_Prist) Щербаков, сам скрипт то у меня работает, в первом модуле видно, что создать док из шаблона я смог, а, насколько я понял, метод Add делает разовый документ. А я хочу вторым действием добавить в конец этого же документа шаблон еще раз и его заменить. И тогда у меня в одном документе будет хоть 20, хоть 30 файлов под каждого студента
 
Цитата
ViKKuzya написал:
создать док из шаблона я смог,
не видно. Видно, что создаете пустой документ, потом в него пытаетесь скопировать всю информацию из шаблона. Ничего другого по сути не происходит.
Выше расписал все.
Цитата
ViKKuzya написал:
А я хочу вторым действием добавить в конец этого же документа шаблон еще раз и его заменить
в конец какого? Лучше опишите задачу нормально - Ваш код не делает то, что Вы описали.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Дмитрий(The_Prist) Щербаков,
Как работает старая программа(module1):
0. берется студент 1(vasya)
1. шаблон копируется из папки Templates в папку Result и переназывается по имени студента(vasya41.docx)
2. открывается файл vasya41.docx и в нем изменяются данные
3. Файл сохраняется и закрывается
4. меняем на следующего студента(petya)
Повторяем цикл, пока не кончатся студенты. На выходе получаем N файлов, по количеству студентов с именами.
Часто это приходится печатать одновременно на всю группу(20-30 студентов), причем луше в пдф, т.к. принтеры часто ломают форматирование doc. Приходится использовать браузерные проги, которые конвертируют в пдф и объединяют. Но эксель то это и сам умеет.

Задача: собрать все файлы студентов в 1

Моя реализация:
0. Создаю wdDoc - общий документ
1. из шаблона копирую весь текст.
2. вставляю в конец wdDoc и по первому скрипту меняю данные
3. Меняю студента
Повторяю шаги 1-3, пока не кончатся студенты
4. Сохраняю документ в  docx и pdf
На выходе получаю единый документ с данными по всем студентам
 
Дмитрий(The_Prist) Щербаков, вот так я себе представляю итоговый код. Скорее всего, чтобы многократно вставлять шаблон в конец файла, придется либо его N раз открывать внутри цикла, либо создать буферную переменную
Код
Sub main()
Dim wdApp As Object 'Переменная для модуля управления Word документами
Dim wdDoc As Object 'Переменная для открытия и работы с итоговым документом
Dim wdTemplate As Object 'Переменная для файла шаблона
HomeDir$ = ThisWorkbook.Path 'Путь к общей папке
Set wdApp = CreateObject("Word.Application") 'создание модуля управления Word файлами
wdApp.Visible = True

'открыть шаблон, скопировать из него данные и закрыть
Set wdTemplate = wdApp.Documents.Open(HomeDir$ + "\Templates\" + Cells(2, 3).Text)
wdTemplate.Range.Copy
wdTemplate.Close False

Set wdDoc = wdApp.Documents.Add 'создаем пустой файл Word

Qreplaces = WorksheetFunction.CountA(Rows(1)) 'количество заменяемых элементов

I% = 2 'Итерационная переменная со второй строки

'Запускаем цикл, перебирающий строки(студентов)
Do
    If Cells(I%, 1).Value = "" Then Exit Do 'Пропускать, если первый столбец в I% строке пустой
    If Cells(I%, 1).Value <> "" Then 'иначе
        'копируем шаблон из Templates в wdDoc
        wdDoc.Selection.Paste
        wdDoc.Selection.TypeParagraph
        'меняем значения, начиная с 5 колонки
        For J = 5 To Qreplaces
            wdDoc.Range.Find.Execute FindText:=Cells(1, J).Text, ReplaceWith:=Cells(I%, J).Text, Replace:=2
            Next J
    End If 'конец условия
    I% = I% + 1
'Loop 'перезапуск цикла
wdDoc.SaveAs2 HomeDir$ + "\Result\" + Cells(2, 3).Text, 16
wdDoc.SaveAs2 HomeDir$ + "\Result\" + Replace(Cells(I%, 2).Text, ".docx", ".pdf"), 17
wdDoc.Close
'закрытие макроса
wdApp.Quit
MsgBox "Ready!"
End Sub
 
Так делать корректнее будет:
Код
Sub main()
    Dim wdApp As Object 'Переменная для модуля управления Word документами
    Dim wdDoc As Object 'Переменная для открытия и работы с итоговым документом
    Dim wdTemplate As Object 'Переменная для файла шаблона
    HomeDir$ = ThisWorkbook.Path 'Путь к общей папке
    Set wdApp = CreateObject("Word.Application") 'создание модуля управления Word файлами
    'wdApp.Visible = True
    
    Set wdTemplate = wdApp.Documents.Open(HomeDir$ & "\Templates\" & Cells(2, 3).Text)
    'открыть шаблон, скопировать из него данные и закрыть
    Set wdDoc = wdApp.Documents.Add() 'создаем пустой файл Word
    Qreplaces = WorksheetFunction.CountA(Rows(1)) 'количество заменяемых элементов
    
    I% = 2 'Итерационная переменная со второй строки
    
    'Запускаем цикл, перебирающий строки(студентов)
    Do
        If Cells(I%, 1).Value = "" Then
            Exit Do 'Пропускать, если первый столбец в I% строке пустой
        End If
        If Cells(I%, 1).Value <> "" Then 'иначе
    '        открываем шаблон из Templates и делаем замены в нем
            If wdTemplate Is Nothing Then
                Set wdTemplate = wdApp.Documents.Open(HomeDir$ & "\Templates\" & Cells(2, 3).Text)
            End If
    '        меняем значения, начиная с 5 колонки
            For J = 5 To Qreplaces
                wdTemplate.Range.Find.Execute FindText:=Cells(1, J).Text, ReplaceWith:=Cells(I%, J).Text, Replace:=2
            Next J
            wdTemplate.Range.Copy
            'вставить в основной документ
            wdDoc.Range(wdDoc.Range.End - 1).Paste
            'если надо делать разрыв страницы после вставки
            'wdDoc.Range(wdDoc.Range.End - 1).InsertBreak Type:=0
    '        Экспортируем в pdf, сохраняем и закрываем файл
            wdTemplate.Close False
            Set wdTemplate = Nothing
        End If 'конец условия
        I% = I% + 1
    Loop 'перезапуск цикла
    wdDoc.SaveAs2 HomeDir$ & "\Result\" & Cells(2, 3).Text, 16
    wdDoc.ExportAsFixedFormat HomeDir$ & "\Result\" & Replace(Cells(2, 3).Text, ".docx", ".pdf"), 17
    'wdDoc.SaveAs2 HomeDir$ + "\Result\" + Replace(Cells(I%, 2).Text, ".docx", ".pdf"), 17
    
    wdDoc.Close
    'закрытие макроса
    wdApp.Quit
    MsgBox "Ready!"
End Sub
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Дмитрий(The_Prist) Щербаков, большое спасибо, последней подсказкой не воспользовался, пока вы писали, я и сам экспериментировал и получилось.
Самое главное, что помогло - указание на ошибку в нейминге и объяснение, что vba не держит два открытых файла одновременно(как раз была ошибка, когда нормально назвал). В итоге получилась такая последовательность:
0. В начале программы создаю документ и сохраняю
1. открываю шаблон, копирую и закрываю.
2. открываю документ, вставляю скопированное в конец методом Range(wdDoc.Range.End - 1).Paste, меняю данные и сохраняю
3. меняю студента
Повторяю цикл 1-3
Осталось добавить разрыв страницы, чтобы каждый документ с новой начинался, и придумать, как тогда убрать последний путой лист после последнего документа. Это я сам соображу.
И сломалась последняя строка с сохранением в формате PDF. Попробую с вашей подсказкой с экспортом, но когда я ее гуглил, экспорт мне выдавал ошибку.
Вот получившийся код:
Код
Sub main()
Dim wdApp As Object 'Переменная для модуля управления Word документами
Dim wdDoc As Object 'Переменная для открытия и работы с итоговым документом
Dim wdTemplate As Object 'Переменная для файла шаблона
HomeDir$ = ThisWorkbook.Path 'Путь к общей папке
Set wdApp = CreateObject("Word.Application") 'создание модуля управления Word файлами
wdApp.Visible = True

'открыть шаблон, скопировать из него данные и закрыть
Set wdTemplate = wdApp.Documents.Open(HomeDir$ & "\Templates\" & Cells(2, 3).Text)
wdTemplate.Range.Copy
wdTemplate.Close False

'создать основной документ и сохранить в нужном месте
Set wdDoc = wdApp.Documents.Add 'создаем пустой файл Word
wdDoc.SaveAs2 HomeDir$ & "\Result\" & Cells(2, 3).Text, 16
wdDoc.Close

Qreplaces = WorksheetFunction.CountA(Rows(1)) 'количество заменяемых элементов

I% = 2 'Итерационная переменная со второй строки

'Запускаем цикл, перебирающий строки(студентов)
Do
    If Cells(I%, 1).Value = "" Then Exit Do 'Пропускать, если первый столбец в I% строке пустой
    If Cells(I%, 1).Value <> "" Then 'иначе
        'открыть шаблон, скопировать из него данные и закрыть
        Set wdTemplate = wdApp.Documents.Open(HomeDir$ & "\Templates\" & Cells(2, 3).Text)
        wdTemplate.Range.Copy
        wdTemplate.Close False
        'Открыть документ и вставить в его конец текст из шаблона
        Set wdDoc = wdApp.Documents.Open(HomeDir$ & "\Result\" & Cells(2, 3).Text)
        wdDoc.Range(wdDoc.Range.End - 1).Paste
        'меняем значения, начиная с 5 колонки
        For J = 5 To Qreplaces
            wdDoc.Range.Find.Execute FindText:=Cells(1, J).Text, ReplaceWith:=Cells(I%, J).Text, Replace:=2
            Next J
        'Сохранить и закрыть документ
        wdDoc.Save
        wdDoc.Close
    End If 'конец условия
    I% = I% + 1
Loop 'перезапуск цикла
'Открыть документ и пересохранить в pdf
'Set wdTemplate = wdApp.Documents.Open(HomeDir$ & "\Templates\" & Cells(2, 3).Text)
'wdDoc.SaveAs2 HomeDir$ & "\Result\" & Replace(Cells(2, 3).Text, ".docx", ".pdf"), 17
'wdDoc.Close
'закрытие макроса
wdApp.Quit
MsgBox "Ready!"
End Sub
Изменено: ViKKuzya - 20.06.2024 12:51:33
 
Цитата
ViKKuzya написал:
Осталось добавить разрыв страницы,
я же выше показал как добавить разрыв страницы - там даже комментарий есть. Просто строка закомментирована :)
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Дмитрий(The_Prist) Щербаков, не заметил) пытался перед вставкой поставить и он заменл предыдущую вставку) И с пдф не получалось, потому что открыл шаблон, а сохранить пытался документ. Тему можно закрывать, Дмитрию спасибо)
Страницы: 1
Наверх