Как передать объект в форму? - PullRequest
0 голосов
/ 05 сентября 2018

Я работаю над сценарием VBA с Microsoft Word, который позволяет пользователю выбирать текст, который будет скопирован в буфер обмена, чтобы его можно было экспортировать в файл Excel. Пользователь сделает несколько выборов и, наконец, укажет, что он / она сделал, когда содержимое буфера обмена будет скопировано в файл шаблона Excel.

Форма frmModelessForInput позволяет пользователю выбрать текст, который копируется в строковую переменную (str_clipboard), нажмите кнопку «Продолжить», чтобы повторить выбор другого текста, а затем нажмите «Готово», когда текстовая строка копируется. в буфер обмена, а затем вставлен в файл Excel, открытый ранее.

Проблема в том, что когда я пытаюсь вставить содержимое буфера обмена Windows в файл Excel в подпрограмме cmdDone формы frmModelessForInput, объект wb_open выдает ошибку 91 примерно вдвое меньше. Я думаю, у меня была та же проблема в подпрограмме Check_Excel_RTM_Template_Test, и я решил ее, передав объект oExcel в подпрограмму. Я пытаюсь передать объект oExcel в форму, но он отображает ту же ошибку, что и в предыдущем подпункте, хотя я включил свойство для формы, как предлагается ниже.

Я создал «минимальный» код и добавил комментарии, чтобы объяснить ключевые задачи, которые выполняет каждое подразделение. Я запустил этот код, и он не работает так же, как мой «производственный» код.

Заранее спасибо за помощь в решении моей проблемы.

Основной модуль

' This is the minimal master module where I open the Excel Template and Word document to process
Option Explicit
Public str_clipboard As String
Public i_how_many_sentences, i_starting_row_ID As Integer
Public str_active_document As String
Public str_Excel_Filename As String
Public b_abort As Boolean
Public i_rows_of_data As Integer


Sub Master_Module_Test()
Dim oExcel As Object
Set oExcel = New Excel.Application
str_Excel_Filename = "C:\Test\Excel_Template.xlsx"
str_active_document = "C\Test\Doc_to_process.docx"
Documents.Open (str_active_document)

oExcel.Visible = True
oExcel.ScreenUpdating = True 
oExcel.Workbooks.Open str_Excel_Filename
Call Check_Excel_RTM_Template(oExcel)
i_how_many_sentences = 0
Call Select_Sentence_Form_Test(oExcel)
End Sub

Sub в основном модуле

   ' This sub now works without errors
    ' The calling routine passes the object oExcel....this approach works
    ' Previously I didn't pass oExcel but used the following statements
    ' Dim wb_open as Workbook
    ' Set Wb_open = ActiveWorkBook
    ' This also worked sometimes and failed about half the time

    ' This sub checks the Excel file whether it is of the expected format and then selects the cell where the new data will be pasted
    ' I have only included the statement to do the selection
    ' This sub works without any errors
    Sub Check_Excel_RTM_Template_Test(oExcel As Object)
        oExcel.ActiveSheet.range("A6").Select
    End Sub

Sub в основном модуле

' This sub activates the frmModelessForInput so that the user can select sentences; the form executes and works as expected
Sub Select_Sentence_Form_Test(wb_open As Object)
    Dim frm As frmModelessForInput
    Set frm = New frmModelessForInput
' Here is where I set the property of the frmModelessForInput to open Excel workbook as suggested in the response 
    Set frmModelessForInput.Book = wb_open
    With frmModelessForInput
        .str_word_doc_filename = str_active_document
        .str_no_copied = "0"
        .Show False
    End With
    Set frm = Nothing
End Sub

функция для извлечения имени файла из полного пути.

Function getName(pf)
getName = Split(Mid(pf, InStrRev(pf, "\") + 1), ".")(0) & ".xlsx"
End Function

код формы frmModelessForInput

' Here I implemented the suggested property for the form 
' I changed the declaration to "Object" since oExcel in Master_Module_Test is declared as an object
Option Explicit
Private m_Book As Object

Public Property Get Book() As Object
   Set Book = m_Book
End Property

Public Property Set Book(ByRef Value As Object)
   Set m_Book = Value
End Property



' This sub works without errors
Private Sub cmdContinue_Click()
    Dim str_clipboard_line As String
    Dim i_row_number As Integer

    ' When the "Continue" button is pressed the code selects the sentence at the cursor and adds the contents to str_clipboard variable
    i_row_number = i_how_many_sentences + i_starting_row_ID
    i_how_many_sentences = i_how_many_sentences + 1
    Call Highlight_Sentence(str_clipboard_line, i_row_number)
    frmModelessForInput.str_no_copied = i_how_many_sentences
    str_clipboard = str_clipboard + str_clipboard_line
End Sub

Private Sub cmdDone_Click()
    Unload frmModelessForInput
 '  When the "Done" button is pressed the contents of the str_clipboard variable is copied to the Windows clipboard
    Dim str_filename As String
    str_filename = getName(str_Excel_Filename)
    MsgBox "I will now copy the data to the Excel file."
    Dim wb_open As Object
    Set wb_open = ActiveWorkbook
    Call SendToClipboard(str_clipboard) 'This sub puts the contents of str_clipboard into the Windows clipboard
    ' The following statement works sometimes but other times it has runtime error 91: Object variable or With block variable not set
    wb_open.ActiveSheet.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False, NoHTMLFormatting:=True
    MsgBox "Done pasting data to: " & getName(str_Excel_Filename)    
End Sub


' This sub works without errors
Private Sub Highlight_Sentence_Test(clipboard As String, i_row_no As Integer)
    Dim txt_sentence, txt_page_no As String 
    Dim txt_section_index As String
    With Selection
     ' Collapse current selection.
     .Collapse
     ' Expand selection to current sentence.
     .Expand Unit:=wdSentence
    End With
    txt_sentence = Selection.Text
    txt_page_no = Selection.Information(wdActiveEndPageNumber)
'I Use tabs to line up data in the correct columns in template file
    clipboard = i_row_no & vbTab & str_active_document & vbTab & txt_page_no & vbTab & vbTab & vbTab & vbTab & txt_sentence & vbCrLf
End Sub

Ответы [ 2 ]

0 голосов
/ 08 сентября 2018

Основная проблема в том, что код в вопросе не работает с правильными объектами Excel. Поскольку все, что связано с Excel, объявлено как тип данных Object, VBA не может предоставить более точные сообщения об ошибках - ему приходится угадывать , что имеется в виду. Это может помочь установить ссылку на библиотеку объектов Excel (Инструменты / Ссылки) и объявить точные типы данных, пока код не будет работать правильно. Затем, если вы хотите использовать позднюю привязку, объявления можно изменить на Object.

Вот несколько примеров того, как передаются неправильные типы объектов, что приводит к путанице в VBA.

В следующей процедуре я добавил объявление объекта Excel.Workbook и создал его при открытии книги. Поскольку UserForm необходимо работать с объектом рабочей книги , этот передается Select_Sentence_Form_Test ...

Sub Master_Module_Test()
    Dim oExcel As Object
    Dim wb As Excel.Workbook 'Object
    Set oExcel = New Excel.Application
    str_Excel_Filename = "C:\Test\Excel_Template.xlsx"
    str_active_document = "C\Test\Doc_to_process.docx"
    Documents.Open (str_active_document)

    oExcel.Visible = True
    oExcel.ScreenUpdating = True
    Set wb = oExcel.Workbooks.Open(str_Excel_Filename)
    Call Check_Excel_RTM_Template(oExcel)
    i_how_many_sentences = 0
    Call Select_Sentence_Form_Test(wb)
End Sub

В вопросе в коде приложение Excel передается и присваивается свойству Book. VBA разрешает это, потому что все напечатано как Object. Но когда приходит время использовать книгу, она не работает (логически нет).

Sub Select_Sentence_Form_Test(wb_open As Object) 'As Excel.Workbook
    Dim frm As frmModelessForInput
    Set frm = New frmModelessForInput
' Here is where I set the property of the frmModelessForInput to open Excel workbook as suggested in the response
    Set frmModelessForInput.Book = wb_open
    With frmModelessForInput
        .str_word_doc_filename = str_active_document
        .str_no_copied = "0"
        .Show False
    End With
    Set frm = Nothing
End Sub

Тогда cmdDone_Click не работает со свойством , а пытается получить доступ к ActiveWorkbook, даже если отсутствует квалификатор объекта Excel.Application, который недоступен в этой процедуре. Это Word VBA, оно не «знает» ActiveWorkbook.

Вместо этого код должен использовать свойство Book (именно поэтому оно и было создано).

Private Sub cmdDone_Click()
    Unload frmModelessForInput
 '  When the "Done" button is pressed the contents of the str_clipboard variable is copied to the Windows clipboard
    Dim str_filename As String
    str_filename = getName(str_Excel_Filename)
    MsgBox "I will now copy the data to the Excel file."
'''        Dim wb_open As Object
'''        Set wb_open = ActiveWorkbook 'can' work without Excel.Application
    Call SendToClipboard(str_clipboard) 'This sub puts the contents of str_clipboard into the Windows clipboard
    ' Uses the Book property 
    Me.Book.ActiveSheet.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False, NoHTMLFormatting:=True
    MsgBox "Done pasting data to: " & getName(str_Excel_Filename)
End Sub

Обратите внимание, что я не проверял это, так как настройка среды заняла бы слишком много времени.

0 голосов
/ 05 сентября 2018

Это можно сделать, добавив новый Property в форму. В вашей форме добавьте следующий код:

Private m_Book As WorkBook

Public Property Get Book() As WorkBook
   Set Book = m_Book
End Property

Public Property Set Book(ByRef Value As WorkBook)
   Set m_Book = Value
End Property

Затем в свой код вызова добавьте рабочую книгу, которую вы хотите использовать, примерно так:

Set frmModelessForInput.Book = wb_open

или

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