Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Замена шифра в тексте и печать большого количества документов (http://forum.oszone.net/showthread.php?t=242550)

AKBAMAPUH 12-09-2012 22:11 1987623

Замена шифра в тексте и печать большого количества документов
 
Имеется документ MS Word, который состоит из двух страниц. На первой странице документа в четырех местах имеется шифр вида "x" и этот шифр необходимо менять в арифметической последовательности "x+1" (то есть сначала в четырёх местах написан шифр "x", потом шифр меняется и во всех четырёх местах напсиан шифр "x+1" и так далее, до определённого значения), а остальной текст оставлять без изменений и при этом распечатывать каждый раз при изменении значения в автоматическом режиме, используя двустороннюю печать.

Используя возможности VB я добился следующего:
1 - при открытии документа у меня появляется форма, в которую я ввожу начальное значение шифра вида "x", потом ввожу общее число необходимых мне подстановок "y"
2 - кнопка "подстановка" меняет шифр вида "x" на введённое значение в создаваемом документе в необходимых мне четырёх местах (это я сделал при помощи закладок). На текущий момент времени я могу создавать только один документ с введённым форму значением.
3 - кнопка "отмена" закрывает форму, потом документ и затем закрывает Word

Вот как это выглядит на текущий момент времени
Код:

Private Sub CommandButton1_Click()
If CheckBox1.Value = False Then
    MsgBox "Ошибка!" & " " & "Необходимо принять условие." 'выводим сообщение
    Else
 Dim oDoc As Document
 Set oDoc = Application.Documents.Add("C:\Template.dotm")
 oDoc.Bookmarks("bN_1").Range.Text = txtBlank.Value
 oDoc.Bookmarks("bN_2").Range.Text = txtBlank.Value
 oDoc.Bookmarks("bN_3").Range.Text = txtBlank.Value
 UserForm1.Hide
 oDoc.Activate
End If
End Sub
 
Private Sub CommandButton2_Click()
'Выход из формы и закрытие окна документа при нажатии кнопки "Отменить"
On Error GoTo ErrLabel
Unload Me    'Закрываем форму
ActiveDocument.Close  'Закрываем текущий документ
ErrLabel:
Application.Quit    'закрываем Word
End Sub
 
Private Sub txtBlank_Exit(ByVal Cancel As MSForms.ReturnBoolean)
'действия с полем номер бланка
With Me.txtBlank
If Not IsNumeric(.Text) Or Len(.Text) <> 6 Then 'если в поле "Бланк" данные не цифры и меньше или больше 6, то
MsgBox "Ошибка!" & " " & "Введите 6 цифр бланка." 'выводим сообщение
Cancel = True  'возвращаемся к полю
.Text = ""  'очищаем поле
.SetFocus
End If
End With
End Sub
 
Private Sub txtKolvo_Exit(ByVal Cancel As MSForms.ReturnBoolean)
'действия с полем общее количество бланков
With Me.txtKolvo
If Not IsNumeric(.Text) Or Len(.Text) <> 2 Then 'если в поле "общее количество бланков" данные не цифры и общее число цифр меньше или больше 2, то
MsgBox "Ошибка!" & " " & "Вводить только число, состоящее из 2 цифр." 'выводим сообщение
Cancel = True  'возвращаемся к полю
.Text = ""  'очищаем поле
.SetFocus
End If
End With
End Sub

вот нашёл код, он мне в принципе должен помочь, но я пока не могу его изменить под себя...
здесь приводится пример как на странице документа выставляется каждый раз новое число с одного до другого и каждый раз при этом документ распечатывается.
я надеюсь правильно понял пример =)

Код:

Sub Печать_кучи_документов_с_номерами()
 
  ' В документе там где должен быть номер должна стоять 239366 '       
  For Номер_документа = 239366+1 To 239366+100       
        With Selection.Find
            .Text = Trim(Str(Номер_документа - 1))
            .Replacement.Text = Trim(Str(Номер_документа))
            .Forward = True
            .Wrap = wdFindContinue
        End With
     
        Selection.Find.Execute Replace:=wdReplaceAll
       
        Application.PrintOut Range:=wdPrintAllDocument, Item:= _
            wdPrintDocumentContent, Copies:=1, Pages:="", PageType:=wdPrintAllPages, _
            ManualDuplexPrint:=False, Collate:=True, Background:=True, PrintToFile:= _
            False, PrintZoomColumn:=0, PrintZoomRow:=0, PrintZoomPaperWidth:=0, _
            PrintZoomPaperHeight:=0
  Next                   
End Sub

и ещё нашел вот такую статью
она меня безумно напугала из-за огромного кода на казалось бы простую операцию - установка дуплекса на печать документа

вообщем, как видите, пока что в голове бардак... Требуется помощь для наведения порядка в голове и мыслях.

Dr.DG 24-09-2012 23:45 1994253

IMHO, вы слишком усложняете. По сути, вам нужно выполнить цикл c глобальной заменой (как в первом примере) или перебором закладок с последующей печатью документа. Двухстороннюю печать на время выполнения кода проще задать в свойствах принтера по умолчанию, чтобы не связываться с WinAPI.

AKBAMAPUH 29-09-2012 20:14 1996694

Dr.DG,
вот что мне удалось сделать на текущий момент времени:

Код:

Private Sub CommandButton1_Click()
 
    Dim lNumber As Long
    Dim i As Long
   
    'Помещаем в переменную lNumber, с какого номера
    'должна начинаться нумерация бланков.
    lNumber = Me.TextBox1.Value
   
    'проверяем на согласие с условием
    If CheckBox1.Value = False Then
   
    'выводим сообщение
    MsgBox "Ошибка!" & " " & "Необходимо принять условие."
    Else
   
    'Делаем столько витков цикла, сколько бланков необходимо вывести на печать.
    For i = 1 To Me.TextBox2.Value Step 1
   
            Dim oDoc As Document
            Set oDoc = Application.Documents.Add("C:\Primer\BLANK.docm")
         
            'Помещаем в закладку "bN_1" данные из переменной lNumber.
            oDoc.Bookmarks("bN_1").Range.Text = lNumber + (i - 1)
           
            'Помещаем в закладку "bN_2" данные из переменной lNumber.
            oDoc.Bookmarks("bN_2").Range.Text = lNumber + (i - 1)
 
            'Помещаем в закладку "bN_3" данные из переменной lNumber.
            oDoc.Bookmarks("bN_3").Range.Text = lNumber + (i - 1)
 
            'Помещаем в закладку "bN_4" данные из переменной lNumber.
            oDoc.Bookmarks("bN_4").Range.Text = lNumber + (i - 1)
       
            'Распечатываем.
            Application.PrintOut Range:=wdPrintAllDocument, Item:= _
            wdPrintDocumentContent, Copies:=1, Pages:="", PageType:=wdPrintAllPages, _
            ManualDuplexPrint:=True, Collate:=True, Background:=True, PrintToFile:= _
            False, PrintZoomColumn:=0, PrintZoomRow:=0, PrintZoomPaperWidth:=0, _
            PrintZoomPaperHeight:=0
       
    'Скрываем пользовательскую форму
    UserForm1.Hide
   
    Next i
    End If
End Sub

Здесь представлен работающий код, теперь уже с пользовательской формой (в которой TextBox1 и TextBox2 для ввода значений, CheckBox1 для принятия условия, а также кнопка CommandButton1, которая является основной).

По-прежнему есть некоторые моменты, которые хотелось бы улучшить:

1 - в документе "BLANK.docm", над которым и проводятся все действия, имеется 4 закладки на 4 одинаковых числа, которые начинаются с цифры "ноль". Например, 012222. Так вот сейчас я вынужден был перед каждой закладкой поместить цифру "ноль",а в поле TextBox1 пользовательской формы UserForm1 вбивать значение без цифры "ноль", например 12222.
Можно ли сделать так, чтобы в поле TextBox1 я вносил значение например 012222, в поле TextBox2 я вносил значение например 2 и при этом происходила правильная отработка "lNumber + (i - 1)" и на печать выводились документы с изменёнными номерами - 012222 в первом документе и 012223 во втором документе?

2 - во время выполнения кода открываются новые вкладки с документами, с изменёнными номерами. Как избавиться от этого, чтобы ничего не появлялось, а просто в очередь печати все документы складывались сразу и всё?


3 - необходима двусторонняя печать документа "BLANK.docm". Принтер обладает необходимой функцией.

AKBAMAPUH 29-09-2012 20:48 1996722

по пункту 2 родилась вот какая идея

Код:

    'закрываем активный документ без сохранения изменений, поскольку после вставки
    'текста произошла замена закладки
    ActiveDocument.Close SaveChanges:=wdDoNotSaveChanges

правильно сделал или есть более правильный вариант решения вопроса?

AKBAMAPUH 29-09-2012 22:31 1996767

и ещё появились следующие вопросы (сохранена сквозная нумерация проблем):
4 - текст, вводимый в TextBox1, должен проверяться на следующие условия - это должно быть число, число должно состоять из 5 цифр, и не должно начинаться на ноль.
5 - текст, вводимый в TextBox2, должен проверяться на следующие условия - это должно быть число равное "1", "2" или "50".

Dr.DG 01-10-2012 14:24 1997722

1 - непонятно.
2 - новые вкладки (новые документы) создаются из-за этой строчки:
Код:

Set oDoc = Application.Documents.Add("C:\Primer\BLANK.docm")
Нужно так
Код:

Set oDoc = ActiveDocument
, но, так как вы работаете только с активным документом, IMHO, переменная oDoc вообще не нужна, обращайтесь напрямую к ActiveDocument.
3 - повторяю, задаёте двухстороннюю печать в свойствах принтера в Панели управления. ManualDuplexPrint:=True - это ручной дуплекс средствами Word.
4 - Проверка на число
Код:

If IsNumeric(TextBox1.Value) Then
Else
End If

Проверка на количество цифр
Код:

If Len(TextBox1.Text) = 5 Then
Else
End If

Проверка на 0 в первой цифре
Код:

If Left(TextBox1.Text, 1) = "0" Then
Else
End If

5 -
Код:

If TextBox2.Value = 1 _
    Or TextBox2.Value = 2 _
    Or TextBox2.Value = 50 _
Then
Else
End If


AKBAMAPUH 01-10-2012 19:08 1997872

спасибо огромное за подсказки, сейчас всё переварю, отрихтую и проверю =)

AKBAMAPUH 01-10-2012 19:28 1997886

Итак, сходу образовалась вот какая проблема:
решил использовать ActiveDocument, убрав переменную oDoc, то есть строки стали вот какимим
Код:

     
            'Помещаем в закладку "bN_1" данные из переменной lNumber.
            ActiveDocument.Bookmarks("bN_1").Range.Text = lNumber + (i - 1)
           
            'Помещаем в закладку "bN_2" данные из переменной lNumber.
            ActiveDocument.Bookmarks("bN_2").Range.Text = lNumber + (i - 1)
 
            'Помещаем в закладку "bN_3" данные из переменной lNumber.
            ActiveDocument.Bookmarks("bN_3").Range.Text = lNumber + (i - 1)
 
            'Помещаем в закладку "bN_4" данные из переменной lNumber.
            ActiveDocument.Bookmarks("bN_4").Range.Text = lNumber + (i - 1)

при таком раскладе выяснилось, что я похоже неправильно использую закладки (Bookmarks), то есть у меня происходит не подстановка значения на место закладки, а происходит полная замена закладки на указанное значение. И получается, что при втором витке в документе уже нет закладок, так как на их месте теперь просто указанные значения, соответсвенно цикл заканчивается на первом витке.

как правильно использовать подстановку на место закладки?

AKBAMAPUH 01-10-2012 20:02 1997918

и еще вопрос у меня напрашивается например по пункту 5:

я не понимаю что мне писать в коде после слова Then
Код:

If TextBox2.Value = 1 _
    Or TextBox2.Value = 2 _
    Or TextBox2.Value = 50 _
Then
Else
End If

после слова Else я напишу чтобы появлялось MsgBox "Ошибка!" & " " & "Введите значение равное 1, 2 или 50"
а вот что после слова Then? что-то я не догоняю... мне бы наоборот сделать, чтобы если НЕ РАВНО, то сообщение, вот как-то так...

если пишу If Not , то проверяется только первое значение на 1, а дальше проверка не идёт...

Iska 01-10-2012 20:23 1997936

Код:

If Not (TextBox2.Value = 1 Or TextBox2.Value = 2 Or TextBox2.Value = 50) Then
    …
Else
    …
End If

Оно же:
Код:

If TextBox2.Value <> 1 Or TextBox2.Value <> 2 Or TextBox2.Value <> 50 Then
    …
Else
    …
End If


Dr.DG 01-10-2012 22:18 1998043

Цитата:

Цитата AKBAMAPUH
происходит полная замена закладки на указанное значение. И получается, что при втором витке в документе уже нет закладок»

Как вариант, перед заменой текста закладок сохранять в переменных/массивах начала и концы (Start и End) свойств Range закладок и потом создавать новые объекты Range и закладки на их основе в сохранённых местах.

AKBAMAPUH 01-10-2012 22:26 1998051

Iska,
спасибо огромное за подсказку со скобками!
фантастика, как просто с одной стороны, но мне и в голову не пришло, что можно использовать скобку в таком случае.

P.S. вы даже не представляете, как много я уже узнал за последний месяц, решая эту задачу =)

Dr.DG,
да, я примерно понимаю о чём вы говорите... я находил на просторах инета что-то подобное, но не смог сделать, поскольку там явно были ошибки, которые мне не удалось решить.
сейчас найду ещё раз и буду внимательно изучать в этом направлении. Спасибо огромное!

Dr.DG,
кстати, по поводу нулей в начале шифра, вот что мне удалось найти
"0"&Cstr(lNumber + (i - 1))
вот как просто добавлять ноль в начале шифра и корректно отрабатывать арифметическую прогрессию с подобным шифром.

AKBAMAPUH 01-10-2012 22:45 1998065

Цитата:

Цитата Dr.DG
Как вариант, перед заменой текста закладок сохранять в переменных/массивах начала и концы (Start и End) свойств Range закладок и потом создавать новые объекты Range и закладки на их основе в сохранённых местах. »

пока найти не могу, но смысл там был вот какой - расставлялись 2 закладки (начало и конец) в нужное место и потом осуществлялось выделение текста между этими закладками и вставка необходимого текста в это выделение.
завтра продолжу поиск - сейчас уже спать...

AKBAMAPUH 02-10-2012 21:18 1998595

вот нашёл дуплексная печать
безумное количество букв и абсолютно мне непонятно....

AKBAMAPUH 03-10-2012 22:27 1999227

Код:

Option Explicit

Private Sub CommandButton1_Click()
 
    Dim lNumber As Long
    Dim i As Long
   
    'Помещаем в переменную lNumber, с какого номера
    'должна начинаться нумерация бланков.
    lNumber = Me.TextBox1.Value
   
    'проверяем на согласие с условием
    If CheckBox1.Value = False Then
   
    'выводим сообщение
    MsgBox "Ошибка!" & " " & "Необходимо принять условие."
    Else
   
    'Делаем столько витков цикла, сколько бланков необходимо вывести на печать.
    For i = 1 To Me.TextBox2.Value Step 1
   
            Dim oDoc As Document
            Set oDoc = Application.Documents.Add("C:\Primer\TEMP\1.docm")
         
            'Помещаем в закладку "bm_1" данные из переменной lNumber.
            oDoc.Bookmarks("bm_1").Range.Text = "0" & CStr(lNumber + (i - 1))
           
            'Помещаем в закладку "bm_2" данные из переменной lNumber.
            oDoc.Bookmarks("bm_2").Range.Text = "0" & CStr(lNumber + (i - 1))
 
            'Помещаем в закладку "bm_3" данные из переменной lNumber.
            oDoc.Bookmarks("bm_3").Range.Text = "0" & CStr(lNumber + (i - 1))
 
            'Помещаем в закладку "bm_4" данные из переменной lNumber.
            oDoc.Bookmarks("bm_4").Range.Text = "0" & CStr(lNumber + (i - 1))
             
            'Распечатываем.
            ActivePrinter = "doPDF v7"
            ActiveDocument.PrintOut
       
    'Скрываем пользовательскую форму
    UserForm1.Hide
   
    'закрываем активный документ без сохранения изменений, поскольку после вставки
    'текста произошла замена закладки
    ActiveDocument.Close SaveChanges:=wdDoNotSaveChanges
   
    Next i
    End If
End Sub


Private Sub CommandButton2_Click()
    'Выход из формы и закрытие окна документа при нажатии кнопки "ОТМЕНА"
    On Error GoTo ErrLabel
        'Закрываем форму
        Unload Me
        'Закрываем текущий документ
        ActiveDocument.Close
ErrLabel:
End Sub


Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
'действия с полем первый номер бланка для подстановки
With Me.TextBox1
If Not IsNumeric(.Text) Or Len(.Text) < 6 Then 'если в поле введены не цифры и их число меньше 6, то
MsgBox "Ошибка!" & " " & "Введите 6 цифр номера задания" 'выводим сообщение
Cancel = True  'возвращаемся к полю
.Text = ""  'очищаем поле
.SetFocus
End If
End With
End Sub


Private Sub TextBox2_Exit(ByVal Cancel As MSForms.ReturnBoolean)
'действия с полем общее количество необходимых бланков
With Me.TextBox2
If Not (TextBox2.Value = 1 Or TextBox2.Value = 2 Or TextBox2.Value = 50) Then
MsgBox "Ошибка!" & " " & "Введите значение равное 1, 2 или 50" 'выводим сообщение
Cancel = True  'возвращаемся к полю
.Text = ""  'очищаем поле
.SetFocus 'фокус на поле
End If
End With
End Sub

Вот такой замечательный и главное рабочий код появился у меня в ходе безумно долгой и кропотливой работы...

есть правда по-прежнему небольшие недочёты, которые вносят в некотором роде незавершённость данному проекту:
1 - двустороння печать реализована путём создания нового принтера, в свойствах печати которого выставлена принудительно двусторонняя печать и весь документ печатается исключительно через этот принтер.
А хотелось бы конечно иметь более универсальный проект, чтобы не приходилось дополнительно производить какие либо манипуляции с компом и его принтерами.
2 - по-прежнему не могу понять как реализовать правильное использования закладок (bookmarks), поскольку на текущий момент времени у меня происходит не вставка текста, а полная замена закладки на текст, поэтмоу приходится с каждым витком открывать документ снова и снова.
Вот нашёл казалось бы замечательную статью про закладки, но не могу понять что делать с ней и как изменить под свои условия - см. эту статью
3 - в момент открытия документа появляется UserForm1, если нажать на "крестик", то появляется вот это сообщение из кода проекта
Код:

MsgBox "Ошибка!" & " " & "Введите 6 цифр номера задания"
А хотелось бы, чтобы закрывалась UserForm1 и текущий открытый документ, то есть то событие, которое происходит сейчас при нажатии на CommandButton2 (см. код выше).
Либо как вариант чтобы отсутствовал тот самый "крестик" на форме =)


Помогите пожалуйста, осталось совсем немного...

Dr.DG 04-10-2012 23:02 1999752

2 - в статье по вашей ссылке есть подпрограмма обновления текста закладки UpdateBookmark, используйте её вместо прямого обновления. Вместо строк типа
Код:

oDoc.Bookmarks("bm_1").Range.Text = "0" & CStr(lNumber + (i - 1))
нужно вызывать её вот так
Код:

UpdateBookmark "bm_1", "0" & CStr(lNumber + (i - 1))
3 - установите точку останова (F9) где-нибудь в начале программы и отлаживайте по шагам (F8). Смотрите, что выполняется и в какой последовательности.

AKBAMAPUH 07-10-2012 12:56 2000823

Dr.DG,
мне бы даже в голову не пришло, что простая вставка кода в форму решит вопрос с обновлением закладок, даже менять ничего не пришлось.

у меня теперь другие вопросы возникли:

1 - каким образом сделать UserForm1 незакрывающуюся? То есть чтобы на форме отсутствовал "крестик", либо чтобы на UserForm1 "крестик" был неактивным, затемнен. Хотя лучше конечно чтобы он просто-напросто отсутствовал.

2 - каким образом осуществить закрытие приложения Word?
указанный ниже код не закрывает приложение...
Код:

Word.Application.Quit

AKBAMAPUH 07-10-2012 13:48 2000836

Вложений: 1
по поводу первого пункта нашёл замечательную вещь, но абсолютно в ней не могу разобраться, поскольку кода очень много для меня, мне столько не переварить...
мне необходим либо вариант "меню", либо вариант "крестик" (см. пример во вложении)
подскажите какой код выдернуть из примера и куда его вставить, пожалуйста.

AKBAMAPUH 07-10-2012 21:25 2001076

по поводу пункта 2 - возникло недоразумение из-за того, что сначала выполнялась процедура закрытия текущего активного документа, а потом осуществлялась попытка закрыть приложение Word, но в этом и есть абсурдность ситуации, потому что уже некому и нечему выполнять код =)
я думаю, что верно понял этот момент. получается, что эту ситуацию необходимо оставить как есть.
хотя если есть у кого комментарии - высказывайтесь, может есть другое решение вопроса.

всё ещё жду решение вопроса по пункту 1.
спасибо за внимание.

Iska 07-10-2012 23:58 2001131

AKBAMAPUH, ничто не мешает сохранить документ/документы и воспользоваться сразу «Application.Quit» без «Document.Close». Либо просто использовать потребным образом первый аргумент — «SaveChanges» — метода «Application.Quit»: Quit Method.

AKBAMAPUH 09-10-2012 15:04 2002062

по пункту 1 мне вот что подсказали
Код:

'отключение крестика на UserForm1
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Cancel = -1
End Sub

но хотелось бы решить данный вопрос используя пример, представленный в файле Forma


А вот как сделал по пункту 2
Код:


    'Распечатываем. Ждём окончания процесса печати.
    'А то не будет распечатываться ничего, сразу закроется всё.
    ActiveDocument.PrintOut Background:=False
       
    'закрываем приложение Word без сохранения изменений и без возможности выбора
    Application.Quit SaveChanges:=wdDoNotSaveChanges



Время: 07:53.

Время: 07:53.
© OSzone.net 2001-