И так, после вводной части, я попытался подвести заинтересованного читателя к проблемам, которые возникают при решении различных типовых, казалось бы, задач по автоматизации разных процессов для отечественного редактора «Р7» версии «Десктоп». Кому лень читать, то основная мысль у меня была такая: поскольку АПИ автоматизации нам предоставляется на языке javascript, то придется идти методами, которые он нам предоставляет, в том числе и с возможностями в той части АПИ редакторов, которое от нас заботливо упрятали. План на был статьи такой:
Средства взаимодействия с пользователем в макросах через АПИ«Р7» (вы сейчас здесь)
Мое собственное решение для построения сложных форм в макросах
Почти автоматическая генерация макросов
Прочее (по результатам этих статей)
В этой части я постараюсь не в самом полном объеме, но достаточном для начала,показать способы работы с пользователем в макросах.
Давайте ещё немного отскочу в сторону общей теории, и поясню, какие способы автоматизации есть в «Р7» вообще. Их два: плагины и макросы. Они достаточно существенно отличаются друг от друга, и даже АПИ у них, в общем‑то, не одинаковое, поэтому сделаю краткий обзор различий. тем кто не особо в курсе.
Макросы:
Хранятся внутри отдельного документа и, следовательно, они в полной мере перемещаемые между компьютерами. Могут иметься исключения, если макрос использует какие‑то глобальные библиотеки, подгружаемые в редакторы через специальные хаки, и требуемые для его (макроса) работы. Но это пока редкий сценарий использования. Проблему их с отсутствием в конкретном редакторе легко купируется проверками на наличие требуемых библиотек перед их использованием в макросе.
Из первого пункта следует, что макросы доступны только внутри одного документа, или его копий. Может оказаться затруднительным дальнейшее комбинирование при необходимости совмещения макросов из разных документов.
Выполняются макросы через запуск их внутри eval(), и это фактически означает, что забудьте о любой предварительной оптимизации их байт кода. А значит и скорость выполнения заведомо ниже, чем кода в плагинах (это не совсем так, ибо код, передаваемый внутрь plugin.callCommand() так же выполняется через eval(), но я (и не только я) знаю способы как это обходить). Так же возникают проблемы с объемом данных, которые может переварить такой код. Так же в них нельзя сделать параллельность потоков обработки через worker() и тому подобное
Ограниченные АПИ редакторов возможности для построения серьезных алгоритмов работы с данными
Изначально ограниченная возможность притянуть для вычислений, какие‑либо внешние библиотеки (это мы преодолеем!)
Каждый макрос в рамках документа — это просто скрипт, который не имеет штатных средств по взаимодействию с пользователем или другими макросами, кроме разве что запуска через привязки к фигурам на листе, да вывод результатов в документе или в консоль отладчика.
Плагины:
Отдельное расширение функциональности редакторов, привязанное к редактору в целом, и хранится на локальном хранилище самого компьютера, в специальной папке
Доступен для любых документов, в редакторах к которым привязан каждый конкретный плагин
Представляет собой по сути отдельную web страницу (даже если плагин не имеет визуальной составляющей), что позволяет использовать для работы огромный набор уже имеющихся, или специально разрабатываемых модулей на javascript, что делает плагины максимально кастомизируемыми, как по внешнему виду, так и по функциональным возможностям
Это же позволяет использовать распараллеливание кода на несколько потоков через использование механизма worker()
Сравнительно более простая и безопасная разработка и отладка кода, по сравнению с макросами. Можно использовать любую удобную среду разработку, которая используется во фронтэнд для верстки и отладки вэб контента. При этом подключать при необходимости современные и серьезные фреймворки типа «Svelte», «Angular», «Vue» и так далее Для сборки проекта в единое целое можно так же использовать любые бандлеры и упаковщики, лишь бы на выходе была структура кода и данных, понятная при загрузке редактору.
Широкий набор сценариев использования плагинов, определяемых его конфигурацией. Это могут быть визуальные\ не визуальные плагины. Системные плагины с автозагрузкой. Кастомизирующие уже имеющиеся возможности, или их дополняющие. Используемые для взаимодействия с внешними источниками данных и так далее
Много чего ещё…
Как видно даже из этого краткого сравнения, плагины вроде бы выигрывают у макросов с отрывом. Бери да пиши плагин под любые задачи, и «горя не знай»! Но есть и отдельный сценарий, который не так уж и редок: плагины надо переносить вместе с документами, если обработка данных в документе специфична и привязана к плагину. Да и само написание плагина в целом сложнее, ибо подразумевает наличия некоторых начальных условий и наборов файлов с обязательным внутренним форматом, два из которых обязательны для любого плагина (конфигурация в config.json, внешний вид и скрипт в *.html файле). Кстати, секунду саморекламы: я написал плагин, который позволяет очень просто начать создать другие плагины, но об этом потом. Макросы при этом можно писать и использовать сразу в редакторе. Да и для многих задач макросы легкий и необходимый минимум. Чаще всего нет смысла писать 100+ плагинов, которые к тому же замусоривают панель «Плагины» редактора и вообще не так уж и удобны для небольших или специфичных для конкретных документов задач.
Начнем программировать?
Итак, кто дочитал сюда, тот молодец! В списке особенностей макросов, я написал такой вот пункт: «Нет штатных средств интерактивного взаимодействия с пользователем (кроме привязки к фигурам на листе для запуска и вывод результатов на экране или в лог)„. Ну а вдруг есть необходимость, так построить алгоритм макроса, чтобы он хотя бы просто оповещал пользователя о чем‑то? К примеру, такой сценарий: макрос валидирует таблицу или документ, и при нахождении ошибок, должен оповестить пользователя об ошибке. А в случае если все хорошо, сказать ему и об этом. Казалось бы — тривиальная задача. В VBA решается в одну строку: “»
MsgBox "Это ваше первое окно оповещения!"
Знающий javascript предложит использовать alert() в макросе, и окажется не прав! Эта функция не работает в редакторе и никак не то что не оповестит, а окно с сообщением просто не появится на экране редактора! А штатных методов в АПИ не предусмотрено! Можно, конечно, зарезервировать какое‑то место в документе и писать сообщения в него (что например, в текстовых документах, не такая уж и простая задача может оказаться), но это не «комильфо» и вообще не правильно, как ни посмотри!
Что же нам теперь с этим делать? Ну что же, если нет в штатном АПИ, придется обратиться, ко мне к нештатному (скрытому)!
То, что я дальше буду описывать, во много уже является «секретом Полишенеля», и тем, кому это было надо, уже известны эти способы давно. Но, вполне может быть, что есть и те, кто не знает эти методы.
Скрытый объект Common
К счастью, от нас в макросах не скрыт насовсем ряд очень полезных объектов, которые позволяют нам использовать методы и объекты, необходимые в работе самому редактору. Одним из таких, и я бы назвал его — ключевым, является объект Common. Он очень важен для работы всего редактора в целом, поэтому работать с ним надо предельно аккуратно, стараясь ничего не вносить в работу уже имеющихся там объектов и методов! Если вы так и будете поступать, то в замен вам достанется «Лампа Алладина» вместе с кучей джинов внутри, из мира редактора Р7!
Что собой представляет объект Common? Это специальный глобальный объект, инициализируемый редактором на самой ранней стадии своей загрузки, в котором сосредоточены очень многие методы и объекты редактора. В частности практически все, из которых строится весь визуальный интерфейс редактора! К примеру, есть объекты создающие все панели, диалоговые окна редакторов, тулбары и так далее Именно поэтому, туда лезть не стоит, если хочется не только поэксперементировать но и поработать! Правда, есть и сравнительно безопасные методы, которые мы можем использовать в своих целях. В частности, в Common имеется следующий вложенный уровень UI, который используется, как понятно наверное из названия, для создания элементов пользовательского интерфейса (UI — User Interface). В частности, можно вызвать построение различного рода окошек, построенных на принципах DOM, и собственно это то, что нам и нужно
Рисуем окошко в макросе
Дальше я буду приводить листинг готовых макросов, которые можно сразу вставлять в редакторе макросов, и смотреть на результат. Сделать это можно вызвав штатный (идущий в составе) плагин «Макросы»:

Итак, вот код простейшего окошка:
(function()
{
//Создание самого окна
var win = new Common.UI.Window({
title: "Первое окно",
width: "100px",
height: "100px",
modal: true,
});
win.show(); //Показываем окно
})();
А вот результат:

Уже не плохо! Итак, если кратко описывать код, то мы создаем наше окошко через вызов системного класса UI.Windows, в опциях которой мы можем в полях width и height указать размер в пиксклях (можно потом менять динамически, или прописать «auto»); можем в title задать заголовок окна; и указали в modal, что окно должно быть модальным. Но как‑то малоинформативное у нас выходит окошко! И даже сказать честно, пока бесполезное. Давайте расширять возможности!
Есть ещё в параметрах такое очень важное нам поле, которое я пока не указывал — tpl. В него в виде строки можно передать html строку с описанием внутренней разметки окна. Давайте, к примеру, добавим в окошко, какое‑нибудь сообщение:
(function()
{
let template = `<div style="width:100%;height:100%;><span style="width:100%;font-weight:bold;padding:2px;">Привет, пользователь!</span>
</div>`;
//Создание самого окна
var win = new Common.UI.Window({
title: "Первое окно",
width: "100px",
height: "100px",
tpl: template,
modal: true,
});
win.show(); //Показываем окно
})();
Выполним макрос, нажав на кнопку «Выполнить», располагающуюся справа внизу плагина «Макросы»:

Да, понимаю что не очень-то красиво, но сейчас это и не первостепенная задача, стоящая перед нами! Красоту вы ведь можете навести и сами (или с моей помощью, но в другой раз).
Ну, хорошо! А как быть с контролами? Попробуем добавить кнопку к шаблону:
let template = `<div style="width:100%;height:100%;><span style="width:100%;font-weight:bold;padding:2px;">Привет, пользователь!</span><button> Нажми меня!</button> </div>`;
Вуаля:

Получилось! Так‑с, а как отследить её нажатие? Мы же имеем дело с классом окна? Может там есть готовые обработчики? Хм.. И тут над нами пролетает птица обломинго! Оказывается, в Common.UI.Windows нет методов, чтобы напрямую назначать обработчики для контролов создаваемых через tpl! И что же делать? Но выход есть! И их даже два!
Метод 1. Подключаемся к DOM элементам шаблона напрямую
К счастью, оказывается, внутри почти всех классов в Common.UI есть специальный метод render(), который мы можем переопределять для своих целей. Он вызывается автоматически при создании окна. В нем вполне можно проводить разного рода манипуляции, в том числе поискать созданный нами контрол кнопки и в случае успеха в поиске, назначить ему функцию обработчик. Итак, пробуем:
//Окно с кнопкой. Кнопка как элемент DOM
(function()
{
//Непосредственно шаблон окна.
let template = `<div style="width:100%;height:100%;"><span style="width:100%;font-weight:bold;padding:2px;">Привет, пользователь!</span>
<span id="button_holder" style="position:absolute;bottom:0;left:0;width:100%;padding:2px;text-align: center;">
<button id="button_id" style="width:max-content%;padding:2px;text-align: center;"> Нажми меня! </button></span></div>`;
function onClick(){
console.log("Кнопка нажата!")
}
//Создание самого окна
var win = new Common.UI.Window({
title: "Окно с кнопкой",
width: "100",
height: "100",
modal: true,
tpl: template,
});
//Без этой функции, мы ничего не можем добавить контроллер события нажатия на кнопке!
win.render = function () {
Common.UI.Window.prototype.render.call(win); //Инициализации по дефолту
//Ищем кнопку внутри шаблона окна
let button = win.$window.find('#button_id');
if(button&&button[0]) {
button[0].addEventListener('click', onClick);
}
};
win.show(); //Показываем окно
})();
Запускаем и смотрим что получилось:

Хорошо! А что с нажатием кнопки?

Порядок! Это был способ, к которому я пришёл как ни странно, только недавно. А сперва, я пользовался вот этим методом:
Метод 2. Создаем кнопку через Common.UI.Button
Как я писал ранее, я ни разу не фронтэндер по моему предыдущему опыту работы. Поэтому, первый описанный метод как то в голову мне сразу и не пришел! Сперва, поставив себе задачу найти способ как обработать нажатие кнопок, я стал искать там, где это уже однозначно решено: в исходниках «OnlyOffic»e на GitHub. Пришлось перерыть их целую кучу, чтобы понять как работает даже такое тривиальное действие, как добавлением кнопок и обработка их нажатий. Все оказывается и просто и сложно. В иерархии классов Common.UI имеются помимо Window, ещё большое число разного рода классов, которые описывают те или иные контролы, или даже целые их группы. В том числе, для кнопок есть Common.UI.Button. А для того, чтобы мы в рамках окна могли организовать взаимодействие с ними, нужно использовать классы конкретных контролов, и добавлять их в места, предусмотренные позиционно в шаблоне. Как по мне, путь долгий и муторный, но как я говорил выше — именно его и используют во всех формах, которые вы вызываете в «Р7».
Итак, снова беремся за клавиатуру (ну или делайте копипаст!) и немного переписываем наш предыдущий пример:
(function(){
//Непосредственно шаблон окна.
let template = `<div style="width:100%;height:100%;position:relative"><span style="width:100%;font-weight:bold;padding:2px;">Привет, пользователь!</span>
<span id="button_holder" style="position:absolute;bottom:0;left:0;width:100%;padding:2px;text-align: center;"></span></div>`;
//Функция, вызываемая при нажатии на кнопку
function onClick(){
console.log("Кнопка нажата!");
};
//Создание самого окна
var win = new Common.UI.Window({
title: "Окно с кнопкой!",
width: "auto",
height: "auto",
modal: true,
tpl: template,
});
//ВАЖНО! Без этой функции, ничего не добавится внутри окна!
win.render = function () {
Common.UI.Window.prototype.render.call(win); //Инициализации по дефолту
//Создать контрол нажимаемой кнопки с надписью " Нажми меня "
win.button = new Common.UI.Button({
caption: " Нажми меня",
style:"width:max-content",
}).on("click", onClick);
//Создание визуального представления кнопки внутри шаблона окна
let holder = win.$window.find('#button_holder');
if(holder) {
win.button.render(holder);
}
};
win.show(); //Показываем окно
win.setSize(100, 100); //Установить размеры
})();
Проверяем работу кода:

Проверим аналогично, работает ли кнопка, нажимая на неё. Снова смотрим, что там в логах?:

Отлично, всё, как и ожидалось!
Ещё я добавил вызов метода в объекте win.setSize(100, 100). Просто чтобы показать, как можно менять размер окна уже после его создания. Что к чему я расписал в комментариях к коду, и не буду акцентироваться на нём.
Кстати, так можно создать и привычные кнопки «Ок» и «Cancel» и добавить к ним соответствующие обработчики, в которых можно в конце добавить метод win.close() и это вызовет закрытие нашего модального окошка при их нажатии. Можете проверить, как это работает, добавив одну строчку в обработчике onClick() любой из примеров:
function onClick(){
console.log("Кнопка нажата!");
win.close();//Закроем окно
}
Стандартные popup окошки самого «Р7»
В принципе, можно сказать, что половину поставленной задачи мы и так решили — смогли из макросов делать оповещение пользователя и активировать тригерные события по нажатию на добавляемые кнопки. Но пойдем дальше и ещё упростим себе жизнь! В составе Common.UI имеется ряд готовых всплывающих окошек для разного вида оповещений. Ниже я приведу просто примеры кода их вызова, и внешний вид выводимых окошек:
Окошко «Внимание»

let winWarning= Common.UI.warning({
width: "auto",
msg: "Внимание!",
buttons:['ok']
});
Окошко «Подтверждение»

let winСonfirm= Common.UI.confirm({
width: "auto",
msg: "Подтверждение",
buttons:['ok']
});
Окошко «Информации»

let winInfo= Common.UI.info({
width: "auto",
msg: "Моя информация!",
buttons:['ok']
});
Окошко «Ошибка»

let winError= Common.UI.error({
width: "auto",
msg: "Ошибка!",
buttons:['ok']
});
Универсальное оповещение
В принципе, все просто. На самом деле, если вглядеться внимательно, то становится понятно, что эти окна вызываются не как создание нового объекта, через new, а через встроенные функции, которые большую часть работы по созданию, настройке заголовка, рисования иконки внутри окошка соответствующего типа, и так далее — берут на себя. Если же продолжать копаться в исходниках, то вообще можно обнаружить весьма удобную для оповещения функцию, которая возьмет на себя всё то,что мы ранее делали самостоятельно через создание объекта Common.UI.Window, а именно
let winAlert= Common.UI.alert({
title:"Предупреждение",
width: "auto",
msg: "Предупреждаю!",
buttons:['ok']
});
Данный код создаст следующее окошко:

Таким образом, можно выводить свои сообщения, без необходимости делать какую‑либо черновую работу. Кстати говоря, все выше перечисленные функции стандартных окошек оповещения в своей основе используют вызов именно этой функции Common.UI.alert().
Подключаем callback функции обработки нажатия кнопок у стандартных окошек оповещения.
Итак, мы уже умеем создавать окошки и выводить в них информацию. Но, может возникнуть необходимость как то оповестить код пользователя, что окно было закрыто. В javascript, мы либо можем навесить обработчик события на закрытие окна (а это и долго и ещё найди, где оно это окошко во всем нагороженном DOM редактора), либо использовать callback функции. К счастью для нас, уже готовое поле есть в опциях при создании окна. Называется оно, не поверите, callback!
И так, если мы хотим чтобы после закрытия действия, что‑то произошло в алгоритме работы макроса дальше, то для этого, просто передаем при создании окна нашу функцию, которая вызывается по нажатию на кнопки, которые мы описали в поле buttons. Напоминаю, речь идет о преднастроенных окошках! В Common.UI.Window таких полей в конструкторе нет!:
let winAlert= Common.UI.alert({
title:"Моё окошко",
width: "auto",
msg: "Моё сообщение",
buttons:['ok'],
callback:function(btn) {
if(onClick&&btn==='ok')
onClick();
}
});
Что на счёт пользовательского ввода?
Итак, с выводом информации более‑менее понятно. Что на счёт его ввода? К сожалению, тут таких заранее написанных функций нет, и всё придется писать ручками. Хотя и есть несколько типовых операций, типа выбора диапазона для таблиц, или даже более сложных, которые можно вызывать из макросов сравнительно простым способом. Для диапазонов я покажу в конце этой статьи, а про остальные — не буду пока, ибо и так не маленькая статья выходит. Может быть как‑нибудь потом!. Давайте создадим способом Р7-ниндзя, окошко с полем ввода. И чтобы сделать задачу более повторяемой на будущее, оформим сразу всю задачу в виде функции, наподобии того, как это сделано для стандартных окошек вывода. Разве что параметры я буду передавать по старинке, через запятую, а не одним объектом (мне так просто удобнее). Код:
/*
Макрос пользовательского ввода одного поля
*/
(function()
{
function onClose(userInput){
if(userInput)
console.log("Пользовательский ввод:", userInput);
}
function userInputWindow(
titleWindow,
inputFieldLabel,
wWindow = 200,
hWindow = 130,
onCloseFunction = null
) {
//Непосредственно шаблон окна.
var template = `<div style="height:100%;"position:relative;display:grid;grid-template-rows:max-content auto max-content;">
<label style="height:max-content;padding:2px;font-weight:bold;">${inputFieldLabel} </label>
<div id="input_span" class="input-row" style="height:max-content;margin-bottom: 5px;"></div>
<div id="button_holder" style="position: absolute;left: 0;bottom: 0;;width:100%;height:max-content;padding:2px;text-align: center;">
<span id="button_ok"></span><span id="button_cancel"></span>
</div>
</div>`;
var winInput = new Common.UI.Window({
title: titleWindow,
tpl: template,
closable: true,
modal: true,
}); //Создание самого окна
winInput.value=null;
//ВАЖНО! Без этой функции, ничего не добавится внутри окна!
winInput.render = function () {
Common.UI.Window.prototype.render.call(winInput); //Инициализации по дефолту
//Добавляем внутри окна класс ввода данных.
// Очень важно указать правильный контейнер для размещения в el:$('#input_span')!
if(this.$window){
this.input = new Common.UI.InputField({
el: $('#input_span', winInput.$window),
style : 'width: 100%;padding:2px;height:20px;'
});
//Непосредственный DOM элемент ввода, по которому будет искаться значение введенное пользователем
let captionInput = winInput.input.$el.find("input");
//Обработка события изменения поля ввода
if(captionInput){
$(captionInput).change(()=>{winInput.value=$(captionInput).val()});
}
//Кнопка с надписью "Cancel"
winInput.btnCancel = new Common.UI.Button({
cls: 'normal',
caption: "Cancel",
style:"width:max-content;margin-left:2px;",
}).on("click", winInput.onCancel_);
//Кнопка с надписью "Ok"
winInput.btnOk = new Common.UI.Button({
cls: 'normal',
caption: "Ok",
style:"width:max-content",
}).on("click", winInput.onOk_);
//Создание DOM объектов кнопок внутри соответствующих позиций в шаблоне
let button = winInput.$window.find("#button_cancel");
if(button) {
this.btnCancel.render(button);
}
button = winInput.$window.find("#button_ok");
if(button) {
this.btnOk.render(button);
}
}
};
//Обработчки нажатия кнопок, как методы объекта окна
winInput.onOk_ = function () {
if(onCloseFunction)
onCloseFunction(winInput.value);
winInput.close();
};
winInput.onCancel_ = function () {
if(onCloseFunction)
onCloseFunction(null);
winInput.close();
};
winInput.show(); //Показываем окно
winInput.setSize(wWindow, hWindow); //Установить размеры
return winInput;
};
userInputWindow("Пользовательский ввод","Введите ваши ФИО",300,150,onClose);
})();
Запускаем и печатаем ФИО:

Смотрим лог:

В принципе такую задачу можно было и организовать ввод и через вставку поля ввода <input> в шаблоне, но в любом случае, задача решаема, и таким образом можно организовать и множественный ввод, и ввод через списки, и отметку позиций через флажки или селекторы и так далее Код будет в принципе почти аналогичным, и поэтому я не буду углубляться дальше. Путь я вам показал! Ах да, я же обещал ещё один «хак» описать — выбор диапазонов в таблицах!
Выбор диапазонов в таблицах
Данный метод пользовательского ввода, может быть очень полезен для макросов с таблицами, и иного способа выбора диапазона привычным перетаскиванием мышкой области выделения, кроме как использовать готовое окно ввода от разработчиков, просто нет, насколько я знаю. А необходимость указать диапазон для тех или иных целей порой просто необходима! Нет, можно конечно сделать и окошко с полем ввода, по методу, описанному выше, чтобы пользователь вводил там диапазон вручную. Но это может приводить к ошибкам (я вот, например, вообще мгновенно забываю требуемые начальные и конечные адреса в диапазонах). К счастью, есть уже готовый метод, и остается его только подключить в свой макрос. Опять же, не буду сильно распинаться. Просто привожу код:
/*
Макрос пользовательского ввода диапазона
*/
(function()
{
function onClose(userInput){
if(userInput)
console.log("Пользовательский ввод:", userInput);
}
function cellRegionWindow(rangeBegin="",onClose = null) {
//Код вызова стандартного диалогового окна выбора диапазона
var winRegion = new parent[0].SSE.Views.CellRangeDialog({
handler: function(dlg, result){
if (result == 'ok') {
winRegion.cellrng = dlg.inputRange.value;
}
}
}).on('close', function() {
if(onClose&&winRegion.cellrng)
onClose(winRegion.cellrng);
});
//Показываем диалоговое окно выбора диапазона ячеек
winRegion.show();
winRegion.setSettings({
api : parent[0].g_asc_plugins.api,
//Данные начала диапазона
range : rangeBegin.length?rangeBegin:"",
//Тип таблицы для обрабатываемого диапазона. Возможные варианты
// -Chart(Пример:Лист1!$E$3:$I$6)
// -FormatTable(пример:$E$3:$I$6)
// -PivotTableData
type : parent[0].Asc.c_oAscSelectionDialogType.Chart
});
}
cellRegionWindow("A1",onClose);
})();
На сей раз, код макроса «наполнен» прямо целым «роем» функций скрытого АПИ, и для его понимания требуется серьезное погружение, чего я делать пожалуй не стану. Сильно я так же не буду комментировать, разве что скажу что:
parent[0].SSE.Views — это уже готовый, созданный объект табличного редактора (SSE — это объект АПИ табличного редактора) и поэтому лучше ничего в коде не меняйте, если не хотите разом всё обрушить!
Parent[0].g_asc_plugins — это тоже очень интересный объект, описывающий АПИ плагинов, и в ряде случаев так же может быть весьма полезным для работы в макросах, но эта тема пока весьма далеко за скобками нынешней беседы.
Итак, запускаем этот макрос, и на экране должны получить нечто такое вот:

Теперь перетаскивая мышкой, можно выбрать диапазон:

Подтверждаем через кнопку «Ок» и смотрим что в консоли:

Таким образом, можно получать данные в разных форматах (в комментариях кода я расписал что и как). Вам остается лишь распарсить строку с полученным диапазоном, и использовать данные по назначению.
Заключение
В общем, примерно так можно упростить себе жизнь, при написании макросов в Р7. Но что делать, если нам нужно ввести большое количество разнообразных данных, да ещё и желательно с валидацией, чтобы потом разместить это все по разным участкам документа или таблицы? В принципе, я уже дал вам «инструмент», который вы можете использовать! Но это конечно долгий и довольно трудоёмкий путь. А можно использовать мою наработку, о которой я планирую рассказать в третьей статье цикла.

Она позволяет получать разом вот такие формы, да ещё и с валидацией полей, и возможностью сразу получать координаты мест в документе, куда данные каждого поля нужно внедрить. Причем, есть механизм генерации подобных полей сразу с помощью одного запроса к ИИ, дабы себя не утруждать особо генерацией форм (форма на скриншоте как раз, так и была создана!). И более того — целый плагин по генерации и внедрению этого всего сразу в документ! Так что, остаюсь на связи, если вам нужны такие вот решения.
economist75
Полезно, спасибо. Достаточно сильно не похоже на VBA, с которым не одна система автоматизации офисного софта конкурировать по удобству и краткости обращения к объектной модели не смогла.