Реализация автоинкремента с макросом Word - PullRequest
3 голосов
/ 08 апреля 2009

Я пишу макрос Word / VBA для шаблона документа. Каждый раз, когда пользователь сохраняет / создает новый документ из шаблона, документу требуется идентификатор, встроенный в текст. Как я могу (настолько просто, насколько это возможно) реализовать автоинкремент для этого идентификатора? Идентификатор числовой.

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

Мне понравилась идея иметь текстовый файл, который я блокирую и разблокирую из макроса или вызываю страницу PHP с базой данных SQLite, но есть ли другие, более разумные решения?

Обратите внимание, что я не могу использовать UUID или GUID, поскольку идентификаторы должны использоваться людьми и машинами. Наши клиенты должны иметь возможность сказать по телефону: «... и об этом, затем, с ID 436 ...?»

Ответы [ 6 ]

3 голосов
/ 10 мая 2009

Дайте дальнейшую мысль об этом, и вот еще один подход, который вы можете рассмотреть. Если вас не интересует каталог предыдущих идентификаторов, вы можете просто использовать пользовательское свойство документа для хранения последнего использованного идентификатора.

В Word 97-2003 вы можете добавить пользовательское свойство, перейдя в «Файл / Свойства», выбрав пользовательскую вкладку и присвоив ей имя и значение. Добавление пользовательского свойства документа в Word 2007 немного сложнее, и мне кажется, что это «Кнопка Office / Подготовка / Свойства документа», выберите маленький выпадающий список для дополнительных свойств, и вы получите то же Старый диалог до 2007 года.

В приведенном ниже примере я назвал свой просто «DocumentID» и присвоил ему начальное значение ноль.

Соответствующий бит кода для обновления пользовательского свойства документа:

ThisDocument.CustomDocumentProperties("DocumentID").Value = NewValue

В качестве подтверждения концепции я создал файл .dot и использовал следующий код в событии Document_New ():

Sub UpdateTemplate()

    Dim Template    As Word.Document
    Dim NewDoc      As Word.Document
    Dim DocumentID  As DocumentProperty
    Dim LastID      As Integer
    Dim NewID       As Integer

    'Get a reference to the newly created document
    Set NewDoc = ActiveDocument

    'Open the template file
    Set Template = Application.Documents.Open("C:\Doc1.dot")

    'Get the custom document property
    Set DocumentID = Template.CustomDocumentProperties("DocumentID")

    'Get the current ID
    LastID = DocumentID.Value

    'Use any method you need for determining a new value
    NewID = LastID + 1

    'Update and close the template
    Application.DisplayAlerts = wdAlertsNone
    DocumentID.Value = NewID
    Template.Saved = False
    Template.Save
    Template.Close

    'Remove references to the template
    NewDoc.AttachedTemplate = NormalTemplate

    'Add your ID to the document somewhere
    NewDoc.Range.InsertAfter ("The documentID for this document is " & NewID)
    NewDoc.CustomDocumentProperties("DocumentID").Value = NewID

End Sub

Удачи!

2 голосов
/ 05 мая 2009

Вы можете справиться с этим полностью через VBA, используя Word и Excel (или Access, я полагаю, но у меня есть неестественное отвращение к использованию Access).

Сначала создайте новую книгу Excel и сохраните ее в месте, к которому вы можете получить доступ через текстовый документ (мое имя - C: \ Desktop \ Book1.xls). Вы можете даже захотеть заполнить значения, введя числовое значение в ячейку A1.

В вашем текстовом документе вы должны ввести это в подпрограмму Document_Open ():

Private Sub Document_Open()

Dim xlApp       As Excel.Application
Dim xlWorkbook  As Excel.Workbook
Dim xlRange     As Excel.Range
Dim sFile       As String
Dim LastID      As Integer
Dim NewID       As Integer

'Set to the location of the Excel "database"
sFile = "C:\Desktop\Book1.xls"

'Set all the variables for the necessary XL objects
Set xlApp = New Excel.Application
Set xlWorkbook = xlApp.Workbooks.Open(sFile)

'The used range assumes just one column in the first worksheet
Set xlRange = xlWorkbook.Worksheets(1).UsedRange

'Use a built-in Excel function to get the max ID from the used range
LastID = xlApp.WorksheetFunction.Max(xlRange)

'You may want to come up with some crazy algorithm for
'this, but I opted for the intense + 1
NewID = LastID + 1

'This will prevent the save dialog from prompting the user
xlApp.DisplayAlerts = False

'Add your ID somewhere in the document
ThisDocument.Range.InsertAfter (NewID)

'Add the new value to the Excel "database"
xlRange.Cells(xlRange.Count + 1, 1).Value = NewID

'Save and close
Call xlWorkbook.Save
Call xlWorkbook.Close

'Clean Up
xlApp.DisplayAlerts = True
Call xlApp.Quit
Set xlWorkbook = Nothing
Set xlApp = Nothing
Set xlRange = Nothing

End Sub

Я понимаю, что это сложная процедура, поэтому непременно переформулируйте ее к своему сердцу. Это был просто быстрый тест, который я взбил. Кроме того, вам нужно добавить ссылку на библиотеку объектов Excel через ссылки в VBA. Дайте мне знать, если у вас есть какие-либо вопросы о том, как это работает.

Надеюсь, это поможет!

1 голос
/ 30 апреля 2009

с макушки головы:

  • Используйте Excel в качестве внешней БД с Automation.
  • Изучите несколько оболочек SQLite COM (на ум приходит Litex).
1 голос
/ 08 апреля 2009

Ну, вы должны где-то хранить следующий идентификационный номер. Идея текстового файла так же хороша, как и любая другая. Вы просто должны справиться с возможностью его блокировки или недоступности по какой-то причине.

Использование базы данных для одного номера излишне.

0 голосов
/ 19 мая 2009

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

Private Function GetNextID(sFile As String) As Integer
    Dim nFile As Integer

    nFile = FreeFile

    On Error Resume Next
    Open sFile For Binary Access Read Write Lock Read Write As #nFile
    If Err.Number <> 0 Then
        ' Return -1 if the file couldn't be opened exclusively
        GetNextID = -1
        Err.Clear
        Exit Function
    End If
    On Error GoTo 0

    GetNextID = 1 + Val(Input(LOF(nFile), #nFile))
    Put #nFile, 1, CStr(GetNextID)
    Close #nFile
End Function

Просто вызывайте эту функцию, пока она больше не вернет -1. Ухоженная.

0 голосов
/ 06 мая 2009

«текстовый файл, который я блокирую и разблокирую из макроса», был бы самым безопасным подходом. Файл DOCID будет иметь только один номер: последний фактически используемый идентификатор.

A) Вы читаете файл (не в режиме записи / добавления) и сохраняете переменную в своем документе DOC_ID = FILE_ID + 1 и сохраняете документ. Предварительно вы уничтожаете файл DOCID, открываете / создаете для чтения-записи, записывая свой DOC_ID. Закройте файл. Если все прошло хорошо, включая «Закрыть», вы в безопасности, иначе вернитесь к пункту А).

Возможно, вы захотите рассмотреть: если файл не найден, создайте его с этим документом с идентификатором +100, как меру восстановления после аварийных ситуаций без ИБП, пока в A)

Я слишком устал, чтобы проверить, может ли это создать тупик при сценарии параллелизма ... возможно.

Если вы чувствуете, что это того стоит, я могу поставить код здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...