Стараюсь писать про Аксапту, хотя частенько тянет в Офис
Использование OWC Spreadsheet в диалоге
Имеется диалог, при помощи которого пользователь задает параметры изменения срока службы у нескольких основных средств, которые в данный момент отфильтрованы и/или отмечены в гриде формы "Основные средства" (RAssetTable). Процесс инициируется кнопкой, расположенной на этой форме. Диалог выглядит так:
После нажатия на кнопку ОК новое значение срока службы (как можно догадаться из рисунка - одно и то же) прописывается всем выбранным ОС - одному или нескольким, отмеченным в гриде при помощи мышки и клавиш Ctrl или Shift. Код, выполняющий эту работу, выглядит следующим образом ( (с) GMCS ):
Помимо изменения поля LifeTime в таблице RAssetStandards для соответствующего ОС, происходит еще и сохранение записи в таблице истории RAssetLifeHist. Переменная historyDialog класса RAssetHistoryDialog определена в ClassDeclaration формы RAssetTable и предназначена для передачи в метод update таблицы RAssetStandards, в котором в конечном счете и выполняется вызов метода, отвечающего за сохранение в истории записи об изменении срока службы ОС.
Некоторое время назад нашим пользователям потребовалось внести изменения по срокам для нескольких средств, причем для каждого - разными индивидуальными значениями. И процедура обещает повторяться в будущем.
Нужно было как-то модифицировать исходный диалог, чтобы приспособить его к новым требованиям. Был выбран вариант с ActiveX - OWC Spreradsheet, и после внесения изменений диалог стал выглядеть так:
В связи с тем, что помещение элемента управления ActiveX в диалог не столь прозрачно, как, скажем, помещение текстового поля или поля даты, ниже будет приведен модифицированный код метода ChangeLifeTime, который обслуживает вторую картинку.
Код будет приведен в первом комментарии, так как попытка поместить его в это стартовое сообщение опять упёрлась в ограничение на 10К символов. В свою очередь, в комментариях не хотят размещаться картинки, но вроде я уже все необходимые разместил в этом сообщении...
После нажатия на кнопку ОК новое значение срока службы (как можно догадаться из рисунка - одно и то же) прописывается всем выбранным ОС - одному или нескольким, отмеченным в гриде при помощи мышки и клавиш Ctrl или Shift. Код, выполняющий эту работу, выглядит следующим образом ( (с) GMCS ):
X++:
void ChangeLifeTime() { DialogRunBase dialog = new Dialog(); DialogField dialogDate,dialogLifeTime,dialogStandardId; RAssetLifeTime dialogLifeTimeValue; RAssetStandardId dialogStandardValue; TransDate dialogDateValue; int i = 0; common urRec; RassetTable urRAssetTable; RassetStandards urRassetStandards; ; urRec = RAssetTable_ds.getFirst(1); if (! urRec) urRec = RAssetTable_ds.cursor(); if (urRec) { dialog.caption("Новые значения"); DialogDate = dialog.addField(typeId(TransDate)); DialogDate.value(today()); dialogStandardId = dialog.addField(typeId(RAssetStandardId)); dialogLifeTime = dialog.addField(typeId(RAssetLifeTime)); dialogDate.widthMode(formwidth::ColumnWidth); dialogStandardId.widthMode(formwidth::ColumnWidth); dialogLifeTime.widthMode(formwidth::ColumnWidth); if (dialog.run()) { dialogDateValue = DialogDate.value(); dialogStandardValue = dialogStandardId.value(); dialogLifeTimeValue = dialogLifeTime.value(); if (! (dialogDateValue && dialogStandardValue && dialogLifeTimeValue)) { checkFailed(strFmt("Заполните все поля")); return; } if (! RAssetStandardTable::Find(dialogStandardValue)) { checkFailed(strFmt("Значение '%1' не найдено в таблице модели учета", dialogStandardValue)); return; } While (urRec) { i++; RAssetTable_ds.findRecord(urRec); if (RAssetTable_ds) { historyDialog.lifetimeDate(dialogDateValue); ttsBegin; urRassetStandards = RassetStandards::find( urRec.(fieldNum(RAssetTable,AccountNum)),dialogStandardValue, true); urRassetStandards.Lifetime = dialogLifeTimeValue; urRassetStandards.update(historyDialog); ttsCommit; RAssetTable_ds.reread(); RAssetTable_ds.refresh(); } urRec = RAssetTable_ds.getNext(); } info(strFmt("Операция по смене срока службы по %1 ОС модели %2 успешно завершена", int2Str(i),dialogStandardValue)); } } }
Некоторое время назад нашим пользователям потребовалось внести изменения по срокам для нескольких средств, причем для каждого - разными индивидуальными значениями. И процедура обещает повторяться в будущем.
Нужно было как-то модифицировать исходный диалог, чтобы приспособить его к новым требованиям. Был выбран вариант с ActiveX - OWC Spreradsheet, и после внесения изменений диалог стал выглядеть так:
В связи с тем, что помещение элемента управления ActiveX в диалог не столь прозрачно, как, скажем, помещение текстового поля или поля даты, ниже будет приведен модифицированный код метода ChangeLifeTime, который обслуживает вторую картинку.
Код будет приведен в первом комментарии, так как попытка поместить его в это стартовое сообщение опять упёрлась в ограничение на 10К символов. В свою очередь, в комментариях не хотят размещаться картинки, но вроде я уже все необходимые разместил в этом сообщении...
Всего комментариев 1
Комментарии
-
А вот и модифицированный код:
Весь код метода, наверное, не так интересен - хотя бы потому, что его невозможно запустить в автономном режиме как джоб. Тем не менее, я привожу его полностью - хотя бы потому, что замена несущественного в рамках темы кода на комментарии вида "// bla-bla-bla" представляет собой дополнительную работу, которую мне делать не хочетсяX++:void ChangeLifeTime() { DialogRunBase dialog = new Dialog(); DialogField dialogDate,dialogLifeTime,dialogStandardId; RAssetLifeTime dialogLifeTimeValue; RAssetStandardId dialogStandardValue; TransDate dialogDateValue; int i = 0; common urRec; RassetTable urRAssetTable; RassetStandards urRassetStandards; DialogGroup dialogGroupSS; // группа, в которую помещается Spreadsheet FormGroupControl groupSS; // та же группа, только уже как контрол FormActiveXControl ss; // собственно Spreadsheet COM range; COM temp; COM currCell; COMVariant cv; int lastRow; int row; RassetId currRassetId; RAssetLifeTime currLifeTime; ; urRec = RAssetTable_ds.getFirst(1); if (! urRec) urRec = RAssetTable_ds.cursor(); if (urRec) { dialog.caption("Новые значения"); // KKu, 22.09.2009 --> модификация на случай разных сроков службы dialog.addGroup('Основные параметры'); // KKu, 22.09.2009 <-- DialogDate = dialog.addField(typeId(TransDate)); DialogDate.value(today()); dialogStandardId = dialog.addField(typeId(RAssetStandardId)); dialogLifeTime = dialog.addField(typeId(RAssetLifeTime)); dialogDate.widthMode(formwidth::ColumnWidth); dialogStandardId.widthMode(formwidth::ColumnWidth); dialogLifeTime.widthMode(formwidth::ColumnWidth); // KKu, 22.09.2009 --> модификация на случай разных сроков службы // без группы Spreadsheet показывался неуправляемо // только при помощи группы он более-менее обуздался dialogGroupSS = dialog.addGroup('В случае разных сроков службы'); groupSS = dialogGroupSS.formGroup(); groupSS.addControl(FormControlType::ActiveX, 'MySpreadSheet'); dialog.doInit(); ss = dialog.formRun().design().controlName('MySpreadSheet'); ss.className('{0002E541-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 10.0 //ss.className('{0002E559-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 11.0 ss.height(300); ss.width(600); // гасим ярлычки листов ss.DisplayWorkbookTabs(false); range = ss.Range('A1'); range.Value2('Инв. номер ОС'); range = ss.Range('B1'); range.Value2('Новый срок службы'); range = ss.Range('C1'); range.Value2('Инструкция'); range = ss.Range('C2'); range.Value2('Если Вы хотите выполнить обновление'); range = ss.Range('C3'); range.Value2('сроков службы для нескольких ОС'); range = ss.Range('C4'); range.Value2('разными значениями сроков,'); range = ss.Range('C5'); range.Value2('то поставьте "Срок службы" равным -1'); range = ss.Range('C6'); range.Value2('в группе полей "Основные параметры"'); range = ss.Range('C7'); range.Value2('и введите данные в колонки A и B,'); range = ss.Range('C8'); range.Value2('начиная со строки 2.'); range = ss.Range('A1:C1'); temp = range.Font(); temp.Bold(true); temp = range.EntireColumn(); temp.AutoFit(); // KKu, 22.09.2009 <-- if (dialog.run()) { dialogDateValue = DialogDate.value(); dialogStandardValue = dialogStandardId.value(); dialogLifeTimeValue = dialogLifeTime.value(); if (! (dialogDateValue && dialogStandardValue && dialogLifeTimeValue)) { checkFailed(strFmt("Заполните все поля")); return; } if (! RAssetStandardTable::Find(dialogStandardValue)) { checkFailed(strFmt("Значение '%1' не найдено в таблице модели учета", dialogStandardValue)); return; } // KKu, 22.09.2009 --> модификация на случай разных сроков службы if (dialogLifeTimeValue != -1) // KKu, 22.09.2009 <-- { // старое продолжение While (urRec) { i++; RAssetTable_ds.findRecord(urRec); if (RAssetTable_ds) { historyDialog.lifetimeDate(dialogDateValue); ttsBegin; urRassetStandards = RassetStandards::find( urRec.(fieldNum(RAssetTable,AccountNum)),dialogStandardValue, true); urRassetStandards.Lifetime = dialogLifeTimeValue; urRassetStandards.update(historyDialog); ttsCommit; RAssetTable_ds.reread(); RAssetTable_ds.refresh(); } urRec = RAssetTable_ds.getNext(); } } // KKu, 22.09.2009 --> модификация на случай разных сроков службы else { // новое продолжение // определяем последнюю строку lastRow = xlRanges::countRows(range.CurrentRegion()); for (row=2; row <=lastRow; row++) { // читаем из Spreadsheet Инв.номер ОС currCell = xlRanges::cellRC(range, row, 1, true); cv = currCell.Value(); currRassetId = cv.bStr(); // читаем из Spreadsheet Новый срок службы currCell = xlRanges::cellRC(range, row, 2, true); cv = currCell.Value(); currLifeTime = cv.double(); urRAssetTable = RAssetTable::find(currRassetId); if (urRAssetTable) { i++; historyDialog.lifetimeDate(dialogDateValue); ttsBegin; urRassetStandards = RassetStandards::find( urRAssetTable.AccountNum, dialogStandardValue, true); urRassetStandards.Lifetime = currLifeTime; // dialogLifeTimeValue; urRassetStandards.update(historyDialog); ttsCommit; info(strFmt('%1 --- %2', currRassetId, currLifeTime)); } } } // KKu, 22.09.2009 <-- info(strFmt("Операция по смене срока службы по %1 ОС модели %2 успешно завершена", int2Str(i),dialogStandardValue)); } } }
В интересующих нас в данный момент строчках кода, относящихся к Spreadsheet, имеются вызовы двух статических методов моего класса xlRanges, который я планирую подробно рассмотреть в одном из ближайших сообщений своего блога. Пока же чисто справочно приведу эти методы "as is":
X++:static int countRows(COM parentRange) { // COM parentRange может быть Excel.Application (подразумевается ActiveSheet) или Worksheet или Range // в случае Spreadsheet - Spreadsheet.Application или Worksheet или Range return any2int(COM::createFromObject( parentRange.Rows() ).Count()); } static COM cellRC(COM parentRange, int row, int col, boolean forSpreadsheet = false) { // COM parentRange может быть Excel.Application (подразумевается ActiveSheet) или Worksheet или Range // в случае Spreadsheet - Spreadsheet.Application или Worksheet или Range // row и col могут быть меньше единицы (0 и отрицательные) - и для Excel, и для Spreadsheet // но меньше единицы - только для Range (не для Application, и не для Worksheet) // возвращает объект Range COM cells; ; cells = parentRange.Cells(); if (! forSpreadsheet) // Excel return COM::createFromVariant( cells.Item( row, col )); else // Spreadsheet return cells.Item( row, col ); }
Запись от Gustav размещена 15.10.2009 в 17:50
Обновил(-а) Gustav 16.10.2009 в 17:55