Вставить как основной текст в документ Word, если это не таблица

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

Когда таблицы вставляются, они хотели бы сохранить форматирование таблицы (в идеале, используя форматирование назначения, но по одному шагу за раз). В результате своего исследования я обнаружил, что невозможно узнать, является ли скопированный текст таблицей, поскольку буфер обмена не хранит эту конкретную информацию в виде слова (если только это не изменилось с тех пор, как я прочитал сообщения), и я ничего не нашел. это предполагает, что в событии вставки есть что-то, что идентифицировало бы его как таблицу, если только оно не было сначала вставлено в пустой документ. Мне интересно, можно ли определить, является ли это таблицей из источника, пока источник, очевидно, все еще открыт, каким-то образом используя VBA?

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

Dim newText As String
    Dim clipboardText As String


Selection.TypeText vbCrLf
Selection.Style = "Body Text"

    clipboardText = GetClipboardText()

    newText = vbCrLf & clipboardText
     
    ' Applying formatting to the pasted text
    With Selection
        .Font.Bold = False
        .Font.Size = 11
        .Font.Color = wdColorBlack
        .Font.Name = "Calibri"
        .ParagraphFormat.Alignment = wdAlignParagraphLeft
        .ParagraphFormat.SpaceAfter = 1
        .Range.HighlightColorIndex = wdNoHighlight
    End With

   ' Pasting text at the current selection
    Selection.TypeText newText

Почему вы применяете все это ручное форматирование поверх стиля основного текста? Если именно так должен выглядеть основной текст, почему вы не изменили стиль, чтобы иметь такие настройки?

Timothy Rylatt 11.07.2024 08:40

Вы не копируете таблицу (только) из Excel? Если из Excel, то думаю можно (пусть и не так просто) определить, есть ли в буфере обмена таблица. Я, конечно, могу проверить, является ли это Range, и я думаю, что должна быть возможность определить, является ли соответствующий диапазон таблицей или частью таблицы... Чего вы хотите с этой точки зрения? Если диапазон в буфере обмена является частью таблицы, вставить всю таблицу? Все по столу DataBodyRange? Только скопированный диапазон (с сохранением исходного формата)? Или что? Кроме того, дело не в «буфере обмена Word», а в буфере обмена Windows.

FaneDuru 11.07.2024 09:56

@TimothyRylatt по какой-то причине текст не вставлялся как основной текст, поэтому я вставил настройки стиля в качестве уловки для них.

Mel Forsyth 12.07.2024 22:56

@FaneDuru чаще всего таблица будет взята из другого текстового документа.

Mel Forsyth 12.07.2024 22:56

Почему бы просто не использовать Selection.PasteAndFormat Type:=wdFormatPlainText см.: Learn.microsoft.com/en-us/office/vba/api/… и Learn.microsoft.com/en-us/office/vba/api/word.wdrecoverytype

Timothy Rylatt 12.07.2024 23:33

Чтобы форматирование таблицы работало правильно, базовый стиль должен быть «Обычный», который также должен соответствовать настройкам документа по умолчанию.

Timothy Rylatt 12.07.2024 23:42
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы не ответили на мой уточняющий вопрос, спустя некоторое время...

Итак, следующее решение проверяет, находится ли в буфере обмена (часть) таблицы Excel (listObject). Его можно легко адаптировать для проверки того, вся ли таблица скопирована, таблица DataBodyRange или что-то еще, если она логически/четко определена...

Код предназначен для работы в 64-битной версии VBA7. Его можно адаптировать и для работы в 32-битной версии.

  1. Скопируйте следующий код в новый стандартный модуль:
Option Explicit

Private Declare PtrSafe Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, ByVal lpString2 As Any) As LongPtr
Private Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr
Private Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As LongPtr) As Long
Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hwnd As LongPtr) As Long
Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal lngFormat As Long) As LongPtr 'modificat din Long in Any
Private Declare PtrSafe Function EnumClipboardFormats Lib "user32" (ByVal wFormat As Long) As Long
Private Declare PtrSafe Function GetClipboardFormatNameA Lib "user32" (ByVal wFormat As Long, ByVal lpString As String, ByVal nMaxCount As Long) As Long


Sub testIsTableInClipboard() 'place a table (part) in memory and TEST IF CLIPBOARD CONTAINS a table (part)
   Debug.Print IsTableInClipboard
End Sub                      'then copy something else (text, an ordinary range etc.) and test it again...

'or paste the clipboard content using Excel table format:
Sub testPasteExcelTable() 'paste the table formatted as Excel table:
    If IsTableInClipboard Then
        Selection.PasteExcelTable False, False, False 'Pastes and formats a Microsoft Excel table.
        'expression. PasteExcelTable( _LinkedToExcel_ , _WordFormatting_ , _RTF_ ) 'method's parameters
    End If
End Sub

Function IsTableInClipboard() As Boolean 'it checks if an EXCEL TABLE (
    Dim dataHwnd As LongPtr                 'pointer to clipboard data
    Dim intOffset As Integer                'for parsing clipboard data
    Dim strClipData As String               'clipboard data
    Dim strGetClipRange As String           'return range address (wb and ws)
    Dim rngFormatID As Long                 'id number for link format (Range)
    Dim strWorkbookName As String           'the range workbook to be used to set Excel Session!
    Const intMaxSize As Integer = 256       'limit for r1c1 to a1 conversion
    
    rngFormatID = getRangeFormatID("Link")      'extracting the id number for "link" format (Range)
    If OpenClipboard(0&) = 0 Then GoTo safeExit 'go to code end to unlock and close clipboard and exit

    dataHwnd = GetClipboardData(rngFormatID)    'pointer to clipboard data
    If dataHwnd = CLngPtr(0) Then GoTo safeExit 'could not allocate memory
    
    dataHwnd = GlobalLock(dataHwnd)             'lock clipboard memory, so we can reference
    If IsNull(dataHwnd) Then GoTo safeExit      'if could not lock clipboard memory
    
    intOffset = 0                               'start parsing data
    strClipData = Space$(intMaxSize)            'initialize string
    Call lstrcpy(strClipData, dataHwnd + intOffset)        'copy pointer to string
    If strClipData = Space$(intMaxSize) Then GoTo safeExit 'not excel range on clipboard
    strClipData = Mid(strClipData, 1, InStr(1, strClipData, Chr$(0), 0) - 1) 'trim null character
    If strClipData <> "Excel" Then GoTo safeExit           'not excel range on clipboard
    
    intOffset = intOffset + 1 + Len(strClipData)           'next offset
    strClipData = Space$(intMaxSize)                       'reset string
    Call lstrcpy(strClipData, dataHwnd + intOffset)        'book and sheet next to it
     strWorkbookName = VBA.Replace(Split(strClipData, "]")(0), "[", "") 'the workbook name where from the range belongs!
     'Debug.Print strWorkbookName: Stop
    strClipData = Mid(strClipData, 1, InStr(1, strClipData, Chr$(0), 0) - 1) 'trim null character
    strGetClipRange = "'" & strClipData & "'!"             'get workbookbook and sheet
    intOffset = intOffset + 1 + Len(strClipData)    'next offset
    strClipData = Space$(intMaxSize)                'initialize string
    Call lstrcpy(strClipData, dataHwnd + intOffset) 'range next
    strClipData = Mid(strClipData, 1, InStr(1, strClipData, Chr$(0), 0) - 1) 'trim null character
    strGetClipRange = strGetClipRange & strClipData 'add range to extracted string (xlR1C1 style)
    
    'Dim exApp As Excel.Application, ClipBRange As Excel.Range, tbl As Excel.ListObject 'i tneeds reference to Excel...
    Dim exApp As Object, ClipBRange As Object, tbl As Object
    Set exApp = GetObject(strWorkbookName).Application
     strGetClipRange = exApp.ConvertFormula(strGetClipRange, xlR1C1, xlA1)    'convert the range style
     Set ClipBRange = exApp.Range(strGetClipRange)    'range in a1 style
     Set tbl = ClipBRange.ListObject                  'check if ClipBRange is part of an Excel table
     If Not tbl Is Nothing Then                       'if tbl is not nothing
        Call GlobalUnlock(dataHwnd) 'unlock clipboard memory
        Call CloseClipboard         'close ClipBoard
        Set exApp = Nothing         'release Excel app from memory
        IsTableInClipboard = True: Exit Function      'make it True and exit function
     End If
safeExit:
    Call GlobalUnlock(dataHwnd)     'unlock clipboard memory
    Call CloseClipboard             'close ClipBoard
End Function

Function getRangeFormatID(strFormatName As String) As Long 'it looks that for a range the ID is not a constant...
    Dim FormatId As Long, retFormat As String, formatLength As Integer
    If OpenClipboard(0&) = 0 Then Exit Function   'could not open clipboard
    formatLength = Len(strFormatName) + 30        'we only need a couple extra to make sure there isn't more
    FormatId = 0 'initialized at zero
    Do
        retFormat = Space(formatLength)           'initialize string
        GetClipboardFormatNameA FormatId, retFormat, formatLength 'get the id name
        retFormat = Trim(retFormat)               'trim spaces
        If retFormat <> "" Then                   'if some string remained
            retFormat = Left(retFormat, Len(retFormat) - 1) 'get rid of terminal character
            If retFormat = strFormatName Then     'if it matches strFormatName
                getRangeFormatID = FormatId       'return the correspondent id number
                Exit Do                           'exit Loop
            End If
        End If
        FormatId = EnumClipboardFormats(FormatId) 'get the next id number
    Loop Until FormatId = 0                       'exit the loop after last id number
    Call CloseClipboard                           'close clipboard
End Function
  1. Поместите таблицу Excel или ее часть в буфер обмена, а затем поиграйте с подпрограммой тестирования testIsTableInClipboard. Оно вернется True. Затем скопируйте что-нибудь еще (строки, файлы, обычный диапазон и т. д.) и запустите его снова. На этот раз оно вернется False

Каждая строка кода прокомментирована таким образом, чтобы ее было легко понять (я думаю). Если что-то не совсем понятно, не стесняйтесь обращаться за разъяснениями.

Пожалуйста, оставьте отзыв после тестирования.

@jonsson Разве вы не нашли время протестировать предложенное выше решение? Если проверить, не сделал ли он то, что вам нужно?

FaneDuru 12.07.2024 09:08

В вопросе нет ничего, что указывало бы на то, что Excel является источником таблицы.

Timothy Rylatt 12.07.2024 14:26
Ответ принят как подходящий

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

Но, возможно, слишком медленно для тех случаев, когда они не вставляют таблицу.

Function IncludesATable() As Boolean
Dim d As Word.Document
Application.ScreenUpdating = False
On Error Goto problem
With Application.Documents.Add(Visible:False)
  .Content.Paste
  IncludesATable = (.Content.Tables.Count > 0)
  .Close SaveChanges:=wdDoNotSaveChanges
End With

problem:
Application.ScreenUpdating = True
End Function

' Test routine
Sub TableNoTable()
If IncludesATable Then
  Selection.TypeText "There's a table."
Else
  Selection.TypeText "There isn't a table."
End If
End Sub

Спасибо @jonsson, это решит проблему вставки таблиц независимо от источника. Кажется, он не слишком запаздывает, но посмотрим, получу ли я какие-либо жалобы, поскольку в настоящее время документ создается с использованием копирования и вставки.

Mel Forsyth 12.07.2024 23:31

@MelForsyth Что ж, если вам действительно нужно вернуться к чему-то, что проверяет содержимое буфера обмена, вы можете просто проверить клип формата HTML и найти элемент <TABLE>.

jonsson 13.07.2024 09:22

Другие вопросы по теме