Передача значения переменной в системный буфер обмена.

Автор Ириминаге, 17 июня 2022, 11:56

0 Пользователи и 1 гость просматривают эту тему.

Ириминаге

В СУБД BASE, из таблицы должна извлекаться информация, обрабатываться и передаваться в системный буфер обмена.
Все примеры, найденные в интернете, предполагают использование Слушателя, а мне он не нужен совершенно. Как можно передать значение переменной в буфер обмена, без этого метода?
Он верил в Мир и Здравый Смысл,
В себя, в людей, в любовь, в науку!
Но кто-то Кафку положил,
В его протянутую руку...

eeigor

#1
REM  *****  BASIC  *****
Option Explicit

Global sTxtCString As String


Sub CopyToClipBoard(sText)
Dim oClip As Object
Dim oTrans As Object  'transferable object to set as new content

' Create SystemClipboard instance.
oClip = CreateUnoService( _
"com.sun.star.datatransfer.clipboard.SystemClipboard")
oTrans = createUnoListener("Tr_", _
"com.sun.star.datatransfer.XTransferable")

' Set data.
' NOTE: xClipboardOwner=NULL means that the caller
' is not interested in lost ownership notifications.
oClip.setContents(oTrans, Null)
sTxtCString = sText

'oClip.flushClipboard() 'does not work
End Sub

Function Tr_getTransferData( _
aFlavor As com.sun.star.datatransfer.DataFlavor)
If (aFlavor.MimeType = "text/plain;charset=utf-16") Then
Tr_getTransferData() = sTxtCString
End If
End Function

Function Tr_getTransferDataFlavors()
Dim aFlavor As New com.sun.star.datatransfer.DataFlavor

aFlavor.MimeType = "text/plain;charset=utf-16"
aFlavor.HumanPresentableName = "Unicode-Text"
Tr_getTransferDataFlavors() = Array(aFlavor)
End Function

Function Tr_isDataFlavorSupported( _
aFlavor As com.sun.star.datatransfer.DataFlavor) As Boolean
If aFlavor.MimeType = "text/plain;charset=utf-16" Then
Tr_isDataFlavorSupported = True
Else
Tr_isDataFlavorSupported = False
End If
End Function


Цитата: Ириминаге от 17 июня 2022, 11:56Как можно передать значение переменной в буфер обмена, без этого метода?
Ctrl+C
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

Ириминаге

Именно это полотенце я в интернете и видел. И оно меня не устраивает, потому и задал вопрос. Контрол+с не подходит, потому как копируемое значение берется из переменной. В общем, нужно как в песне: "нажми на кнопку, получишь резултат, и твоя мечта осуществится, нажми на кнопку, ну что же ты не рад? Тебе больше не к чему стремиться!"
Он верил в Мир и Здравый Смысл,
В себя, в людей, в любовь, в науку!
Но кто-то Кафку положил,
В его протянутую руку...

eeigor

#3
Поместите этот код в отдельный модуль "Clipboard" и забудьте о нем.
Используйте так:
   Call CopyToClipBoard ("Ваш текст или значение переменной")

Боюсь, ваша проблема надуманна. А со временем появится класс типа "Clipboard", который скроет всё то, что вы не хотите видеть...
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

sokol92

#4
С моей точки зрения, приведенный в #1 пример очень полезен для обучения. Возможные вопросы для экспериментов в OC Windows (Linux, увы, пока не моя стихия):
1. Что делает каждый из макросов?

Вызываем функцию CopyToClipBoard с параметром, например, "english русский" и пробуем выполнить вставку из нового буфера обмена.
2. Непосредственно (выделяем ячейку и Shift+Insert) в ячейку Excel текст не добавляется (добавляется после перехода в режим редактирования с помощью F2). Почему? Если такой же текст скопировать в буфер обмена в текстовом редакторе (например, в Блокноте), то в ячейку Excel текст вставить можно.

В ячейку Calc текст, скопированный в буфер обмена с помощью CopyToClipBoard, вставляется непосредственно.
Владимир.

mikekaganski

Цитата: sokol92 от 18 июня 2022, 19:171. Что делает каждый из макросов?

CopyToClipBoard создаёт сервис SystemClipboard, а также особый объект Basic, реализующий интерфейс XTransferable. Это очень интересный трюк: использование createUnoListener не для создания слушателя, а для реализации произвольного интерфейса. Насколько я понимаю, эта возможность не документирована. Она основана на реализации функции, которая создаёт SbUnoObject, а также дополнительные интерфейсы, позволяющие использовать интроспекцию для разрешения и вызова произвольных методов реализуемого интерфейса. Естественно, требуется реализовать методы этого интерфейса - и вот тут работают три других функции: Tr_getTransferData, Tr_getTransferDataFlavors и Tr_isDataFlavorSupported.

Буфер обмена на любой современной платформе позволяет иметь одновременно несколько представлений скопированного содержимого: скажем, в виде простого текста, таблицы в разных форматах (HTML, RTF, каком-нибудь нативном), картинки в разных форматах, ... - и приложение, в которое производится вставка, сможет выбрать лучший из доступных форматов, подходящий именно для него (скажем, вставка таблицы в Paint, вероятно, выберет не то, что выберет вставка в Word). Для достижения этого приложение, из которого идёт копирование, должно предоставить все реализуемые им типы содержимого буфера - и это реализуется объектом Transferable, который имеет методы для перечисления доступных типов, а также для получения данных нужного типа.

Ну а здесь реализуется самый примитивный вариант: предоставляется только тип UTF-16. Это позволяет не усложнять реализацию, поскольку Basic вообще не имеет нормальных средств для управления кодировками текстовых данных.

Цитата: sokol92 от 18 июня 2022, 19:172. Непосредственно ... в ячейку Excel текст не добавляется ... . Почему?

Похоже на баг (возможно, платформоспецифичный). После копирования системный буфер Windows содержит два типа данных: CF_UNICODETEXT с правильными данными (куда можно запихать и строку типа テストabcабв, которую ни в какой стандартной не-Unicode кодировке Windows не представишь), а также CF_TEXT. И вот она-то битая - содержит только нулевой завершающий байт (то есть фактически пустая).

Поскольку мы сами 8-битную кодировку не предоставляем, похоже, это внутренняя магия сервиса SystemClipboard, которая не умеет правильно создавать 8-битные данные из UTF-16, когда их не предоставляет Transferable.
С уважением,
Михаил Каганский

sokol92

Провел эксперимент.
Oткрыл документ, добавил в документ макросы из #1,  вызвал функцию CopyToClipBoard с параметром "english русский", закрыл документ.

Теперь текст из буфера обмена благополучно вставляется непосредственно в ячейку Excel. Интересно...

Не вставляется (как и раньше) в редактор VBE (Excel), что, по-видимому связано с тем, что VBE "понятия не имеет" о юникоде (и хранит текст макросов в кодировке кодовой таблицы Windows по умолчанию).

Владимир.

mikekaganski

#7
Хм. Отладка показывает, что это не CF_TEXT виноват, а ещё один вариант неочистки предыдущего значения результата функции. В соединении с наглым поведением Excel, который не спрашивает, какие форматы имеются в буфере, это приводит к тому, что в ответ на прямой запрос формата Biff8 Tr_getTransferData не назначает никакого результата, и там лежит предыдущее значение - которое оказывается строкой от предыдущего вызова (а он происходит сразу при вызове CopyToClipBoard, когда проверяется новое состояние кнопок вставки). То есть Excel на запрос данных в своём бинарном формате получает не отказ, а неверные данные, и выдаёт ошибку вставки.

Вот так оно работает:

Function Tr_getTransferData(aFlavor As com.sun.star.datatransfer.DataFlavor)
If (aFlavor.MimeType = "text/plain;charset=utf-16") Then
Tr_getTransferData() = sTxtCString
Else
   Tr_getTransferData = Empty
End If
End Function


tdf#149622
С уважением,
Михаил Каганский

sokol92

Владимир.