Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Microsoft Office и VBA программирование > Microsoft Office Word
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 23.01.2013, 16:24   #1
CrySTaL
 
Регистрация: 18.02.2008
Сообщений: 3
По умолчанию Быстрое заполнение таблицы

Здравствуйте.
Заполняю таблицу в Word данными из внешнего источника.
Записываю последовательно в каждую ячейку, добавляя новые строки.
Но в случае, если данных хотя бы на 15-20 страниц, этот процесс работает довольно долго.
Вопрос - возможно ли как-нибудь заполнить таблицу в памяти, а затем вставить ее в документ?
Как Copy-Paste, который работает быстро
CrySTaL вне форума Ответить с цитированием
Старый 23.01.2013, 16:50   #2
Скрипт
Форумчанин
 
Регистрация: 24.12.2012
Сообщений: 776
По умолчанию

CrySTaL, пока такая первая мысль пришла:
  1. формируете VBA-массив (VBA-массив - это таблица в памяти);
  2. когда массив заполнится, переносите массив в Excel - это делается моментально;
  3. затем таблицу из Excel копируете в Word.
Или нужно посмотреть, что из VBA-объектов есть в программе Word для взятия данных из массива.

Последний раз редактировалось Скрипт; 23.01.2013 в 16:53.
Скрипт вне форума Ответить с цитированием
Старый 24.01.2013, 03:25   #3
viter.alex
Балуюсь кодами
Участник клуба
 
Аватар для viter.alex
 
Регистрация: 09.01.2009
Сообщений: 1,837
По умолчанию

Массив в таблицу средствами VBA в Word перенести нельзя, т.к. таблица в Word это средство отображения текста, а не обработки данных как в Excel. Способ, предложенный Скриптом, может оказаться лучшим вариантом по быстродействию.
Если же делать только в Word, то можно отключить обновление экрана пока добавляются данные. Так же на скорость влияет способ перебора ячеек: цикл For...Next работает медленнее, чем Do...Loop
Заполнить таблицу в памяти тоже нельзя, т.к. таблица не существует вне документа.

Пока писал, в голову пришла идея: сформировать текстовую строку из данных, разделяя ячейки, например, знаком $, а строки — знаком #. Вставить строку в документ, выделить и преобразовать в таблицу по разделителям. Думаю, это будет гораздо быстрее
Лучше день потерять — потом за пять минут долететь!©

Последний раз редактировалось viter.alex; 24.01.2013 в 03:27.
viter.alex вне форума Ответить с цитированием
Старый 24.01.2013, 07:43   #4
Скрипт
Форумчанин
 
Регистрация: 24.12.2012
Сообщений: 776
По умолчанию

Провёл сравнение двух способов создания таблицы в программе Word.
Создавал таблицу из 10 000 строк и 10 столбцов (пробовал больше делать строк, но устал дожидаться окончания работы кода в программе Excel. На типе данных "String" не пробовал больше строк).

Способ 1. Использование программы Excel. Результат 175 секунд.
Код:
Sub Procedure_1()
    
    'Для работы этого кода, в VBA нужно подключить библиотеку:
        'Tools - References... - Microsoft Excel Object Library.
    Dim myExcel As Excel.Application
    Dim shSheet_1 As Excel.Worksheet
    Dim i As Long, j As Long
    Dim myArray(1 To 10000, 1 To 10) As Double
    Dim myStart As Double
    
    '1. Запоминаем время начала работы кода.
    myStart = Timer
    
    '2. Отключаем обновление монитора программы Word.
    Application.ScreenUpdating = False
    
    '3. Даём имя "myExcel" запущенной программе Excel,
        'чтобы через это имя получить доступ к программе Excel.
    Set myExcel = GetObject(Class:="Excel.Application")
    
    '4. Убираем в Excel обновление монитора, отключаем пересчёт формул
        'и отключаем события.
    myExcel.ScreenUpdating = False
    myExcel.Calculation = xlCalculationManual
    myExcel.EnableEvents = False
        
    '5. Даём имя "shSheet_1" листу, на который вставим данные.
    Set shSheet_1 = myExcel.ActiveWorkbook.ActiveSheet
    
    '6. Заполняем VBA-массив числом "10000,1".
    For i = 1 To 10000 Step 1
        For j = 1 To 10 Step 1
            myArray(i, j) = 10000.1
        Next j
    Next i
    
    '7. Вставляем сформированный массив на лист Excel.
    shSheet_1.Range("A1").Resize(10000, 10).Value = myArray()
    
    '8. Копируем таблицу в Excel в буфер обмена.
    shSheet_1.Range("A1").Resize(10000, 10).Copy
    
    '9. Всталяем таблицу в документ Word.
    Selection.Paste
    
    '10. Восстанавливаем настройки программы Excel.
    myExcel.ScreenUpdating = True
    myExcel.Calculation = xlCalculationAutomatic
    myExcel.EnableEvents = True
    
    '11. В View - Immediate Window выводим количество секунд, которое
        'работал код
    Debug.Print Timer - myStart

End Sub
Способ 2. Использование типа данных String. Результат 410 секунд (время без превращения текста в таблицу. Средствами программы Word превратил вставленный текст в таблицу, но времени заняло не очень много).
Код:
Sub Procedure_2()

    Dim i As Long, j As Long
    Dim myArray As String
    Dim myStart As Double
    
    '1. Запоминаем время начала работы кода.
    myStart = Timer
    
    '2. Отключаем обновление монитора программы Word.
    Application.ScreenUpdating = False
    
    For i = 1 To 10000 Step 1
    
        For j = 1 To 10 Step 1
            '3. Формируем строку, которая будет превращена в таблицу Word.
            '";" - разделитель между ячейками.
            myArray = myArray & CStr(10000.1) & ";"
        Next j
        '4. Удаляем лишнюю точку с запятой.
        myArray = Left(myArray, Len(myArray) - 1)
        
        '5. Вставляем символ "Конец абзаца". На основе этого символа
            'будут формироваться строки в таблице Word.
        myArray = myArray & Chr(13)
        
    Next i
    
    '6. Убираем лишний знак "Конец абзаца".
    myArray = Left(myArray, Len(myArray) - 1)
    
    '7. Выводим строку в документ Word.
    Selection.Text = myArray
    
    '8. В View - Immediate Window выводим количество секунд, которое
        'работал код
    Debug.Print Timer - myStart

End Sub

Последний раз редактировалось Скрипт; 24.01.2013 в 12:00.
Скрипт вне форума Ответить с цитированием
Старый 24.01.2013, 11:55   #5
viter.alex
Балуюсь кодами
Участник клуба
 
Аватар для viter.alex
 
Регистрация: 09.01.2009
Сообщений: 1,837
По умолчанию

Провёл и у себя эксперименты:
Excel: 138 сек, 371(!) страница
Word: 280 сек., 115 страниц
Немного подчистил макросы. Изменённые строки обрамлены звёздочками
Способ 1: Запускаем приложение Excel с новой книгой, а не пользуемся окрытым и, сооветственно, после использования закрываем его. Что интересно, львиная доля времени тратится на вставку из буфера, ну а Excel, как и положено превосходно работает с табличными данными.
Код:
Sub Procedure_1()

    Dim myExcel As Excel.Application
    Dim shSheet_1 As Excel.Worksheet
    Dim i As Long, j As Long
    Dim myArray(1 To 10000, 1 To 10) As Double
    Dim myStart As Double
    
    '1. Запоминаем время начала работы кода.
    myStart = Timer
    
    '2. Отключаем обновление монитора программы Word.
    Application.ScreenUpdating = False
    
'******************************
    '3. Запускаем Excel
    Set myExcel = CreateObject("Excel.Application")
'******************************
    
    '4. Убираем в Excel обновление монитора, отключаем пересчёт формул
        'и отключаем события.
    With myExcel
        .ScreenUpdating = False
'******************************
        .Workbooks.Add 'Открытие новой книги
'******************************
        .Calculation = xlCalculationManual
        .EnableEvents = False
    End With
        
    '5. Даём имя "shSheet_1" листу, на который вставим данные.
    Set shSheet_1 = myExcel.ActiveWorkbook.ActiveSheet
    
    '6. Заполняем VBA-массив числом "10000,1".
    For i = 1 To 10000 Step 1
        For j = 1 To 10 Step 1
            myArray(i, j) = 10000.1
        Next j
    Next i
    
    '7. Вставляем сформированный массив на лист Excel.
    shSheet_1.Range("A1").Resize(10000, 10).Value = myArray()
    
    '8. Копируем таблицу в Excel в буфер обмена.
    shSheet_1.Range("A1").Resize(10000, 10).Copy
    
    '9. Всталяем таблицу в документ Word.
    Selection.Paste
    
    '10. Восстанавливаем настройки программы Excel.
    With myExcel
        .ScreenUpdating = True
        .Calculation = xlCalculationAutomatic
        .EnableEvents = True
'******************************
'        Выход из приложения
        .ActiveWorkbook.Close False
        .Quit
    End With
'******************************
    '11. В View - Immediate Window выводим количество секунд, которое
        'работал код
    Debug.Print "Excel: " & Timer - myStart

End Sub
Способ 2: 1. При формировании строки убрал функцию CStr, т.к. число автоматически преобразуется в строку. 2. Удаление лишней точки с запятой из цикла убрал, вместо этого в уже сформированной строке делаю замену точки с запятой и знака абзаца на знак абзаца. 3. Функцию Chr(13) заменил на константу vbCr. 4. Добавил преобразование текста в таблицу. 5. Добавил DoEvents
Код:
Sub Procedure_2()

    Dim i As Long, j As Long
    Dim myArray As String
    Dim myStart As Double
    
    '1. Запоминаем время начала работы кода.
    myStart = Timer
    
    '2. Отключаем обновление монитора программы Word.
    Application.ScreenUpdating = False
    
    For i = 1 To 10000 Step 1
    
        For j = 1 To 10 Step 1
            '3. Формируем строку, которая будет превращена в таблицу Word.
            '";" - разделитель между ячейками.
            myArray = myArray & 10000.1 & ";"
        Next j
'******************************
        '4. Удаляем лишнюю точку с запятой.
'        myArray = Left(myArray, Len(myArray) - 1)
        
'******************************
        '5. Вставляем символ "Конец абзаца". На основе этого символа
            'будут формироваться строки в таблице Word.
        myArray = myArray & vbCr
'******************************
        DoEvents
'******************************
    Next i
    
'******************************
    '6. Убираем лишние точки с запятой
    myArray = Replace(myArray, ";" & vbCr, vbCr)
'******************************
    '7. Выводим строку в документ Word.
    Selection.Text = myArray
'******************************
    Selection.ConvertToTable ";", NumColumns:=10
'******************************
    '8. В View - Immediate Window выводим количество секунд, которое
        'работал код
    Debug.Print "Word: " & Timer - myStart

End Sub
Тут ещё вопрос в том, в каком виде поступают данные...
Лучше день потерять — потом за пять минут долететь!©
viter.alex вне форума Ответить с цитированием
Старый 24.01.2013, 13:16   #6
Скрипт
Форумчанин
 
Регистрация: 24.12.2012
Сообщений: 776
По умолчанию

Скорректировал код с использованием типа данных String. Время составило 40 секунд.
Код написан при условии, что в документе Word ничего нет.
Код:
Sub Procedure_2()

    Dim myStringOne As String
    Dim myStringAll As String
    Dim myStart As Double
    Dim i As Long, j As Long
    
    '1. Запоминаем время начала работы кода.
    myStart = Timer
    
    '2. Отключаем обновление монитора программы Word.
    Application.ScreenUpdating = False
    
    '3. Переходим в режим "Черновик". В этом режиме
        'документ не будет разбиваться на страницы
        'и код будет быстрее работать.
    ActiveWindow.View.Type = wdNormalView
    
    For i = 1 To 10000 Step 1
    
        For j = 1 To 10 Step 1
            '4. Формируем строку, которая будет превращена
                'в одну строку таблицы Word.
            'Chr(9) - разделитель между ячейками.
                'Это символ "Табуляция".
            '"CStr" оставил, т.к. при использовании "CStr" точно
                'известно, что делается в коде, а без "CStr" можно
                'только догадываться.
            myStringOne = myStringOne & CStr(10000.1) & Chr(9)
        Next j
        
        '5. Удаляем лишний символ "Табуляция" и 
            'вставляем символ "Конец абзаца".
        Mid(myStringOne, Len(myStringOne), 1) = Chr(13)
        
        '6. Формируем строку, которая будет превращена в таблицу.
        myStringAll = myStringAll & myStringOne
        
        '7. Подготовка переменной к следующему использованию.
        myStringOne = ""
        
    Next i
    
    '8. Выводим строку в документ Word.
    Selection.Text = myStringAll
    
    '9. Преобразование текста в таблицу.
    'Часть кода получена с помощью макрорекордера.
    Selection.ConvertToTable Separator:=wdSeparateByTabs, _
        NumColumns:=10, NumRows:=10000, AutoFitBehavior:=wdAutoFitFixed
    
    '10. В View - Immediate Window выводим количество секунд, которое
        'работал код
    Debug.Print Timer - myStart

End Sub

Последний раз редактировалось Скрипт; 24.01.2013 в 13:57.
Скрипт вне форума Ответить с цитированием
Старый 24.01.2013, 14:03   #7
Скрипт
Форумчанин
 
Регистрация: 24.12.2012
Сообщений: 776
По умолчанию

Цитата:
CrySTaL: Но в случае, если данных хотя бы на 15-20 страниц, этот процесс работает довольно долго.
Перед началом работы переходите в режим "Черновик". В этом случае не происходит разбивки на страницы и процессы будут быстрее идти.
Скрипт вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
заполнение таблицы из бд Damhurz PHP 34 05.04.2013 14:38
Макрос: заполнение таблицы данными из другой таблицы с автоматическим добавлением строк yevgeniy.demidov Microsoft Office Excel 6 06.09.2012 15:27
Заполнение таблицы vvvd Microsoft Office Excel 6 24.04.2012 22:04
Заполнение таблицы arkvid Microsoft Office Excel 10 17.11.2010 18:32
заполнение таблицы Andreyka Общие вопросы Delphi 6 07.02.2009 22:18