Домашняя страничка Локшина Марка.
Раздел: Советы




Работа с внешними програмами

Запустить внешнюю программу в PowerBuilder можно с помощью вызова функций Windows API CreateProcess(Ex) или ShellExecute(Ex) (вторая функция может не только запускать исполняемые файлы, но и запускать приложения асоциированные с документами). Можно, конечно воспользоваться и стандартной PowerBuilder'овской
Run("Имя программы",windowstate),
но максимум, чем вы сможете управлять при таком подходе - размер окна при старте программы. Гораздо же практичнее использовать вышеупомянутые функции (реализация ShellExecuteEx есть в библиотеке
WinAPI).
Воспользовавшись функцией ShellExecuteEx для запуска программы вы получаете ее заголовок (handle). Далее, используя его в качестве параметра для функций TerminateProcess или GetExitProcessCode вы можете завершить работу программы или проверить, работает ли еще программа (существует еще целый ряд функций для работы с внешними программами, но об этом следует читать в документации Microsoft'а), кроме того, можно посылать сообщения созданому приложению.

Как получить отображаемое поле в DDDW

MessageBox("LookUpDisplay", string(dw_1.describe ("evaluate('"+&
"LookUpDisplay(field_name)',1)")))

Как динамически изменять меню

Пример генерации уровня меню:
menu mi,m
m = create menu
for li_item = 1 to UpperBound(as_items[])/ 2 // массив с именами меню и их тегами
// пункты меню - это созданное в painter'e меню из одного пункта,
// со скриптом clicked который по тегу определяет что делать

mi = create m_dyn_menu_item
m.item[li_item] = mi.item[1].item[ 1] // вот так вот :))
m.item[li_item].text = as_items[li_item * 2 - 1]
m.item[li_item].tag = as_items[li_item * 2]
next
// замена подменю номер n на новое
// если n = UpperBound(m_mdi.item[]) + 1 то пункт меню добавляется в конец.

m_mdi.item[n]= m
m_mdi.item[n].Hide()
m_mdi.item[n].Show()
From: "Anatoly Moskovsky"
avm@trais.com.ua

Печать на принтер минуя DataWindow

В PowerBuilder'е присутствует группа функций для печати объектов на принтере, минуя DataWindow:
PrintLine(...)
PrintBitMap(...)
PrintOval(...)
PrintRect(...)
PrintRoundRect(...)
PrintText(...)
PrintDefineFont (...)
PrintSetFont(...)

Получение/изменение высоты Detail поля в DataWindow

А знаете ли вы, что высоту Detail поля в DataWindow можно менять независимо для каждой строки вызывая функцию
dw_control.SetDetailHeight ( startrow, endrow, height )
и получить высоту каждой строки следующим способом (здесь узнается высота второй строки): dw_control.Describe( "evaluate('RowHeight()',2)")

Изменение позиции H Split Scrolling в DataWindow

А знаете ли вы, что позицию вертикальной разделяющей полосы в DataWindow (H Split Scrolling) можно менять:
dw_control.Object.DataWindow.HorizontalScrollSplit

Как получить критерий фильтра и сортировки в DataWindow

Текущиц критерий фильтра для DataWindow можно получить, вызвав функцию:
dw_control.Describe( "DataWindow.Table.Filter")
а сортировки:
dw_control.Describe( "DataWindow.Table.Sort")

Каким образом разорвать страницу после определенной строки

Заводим поле, в котором будем хранить номер страницы. Делаем гpуппу этому полю, отмечаем в гpуппе свойство New Page On Group Break (Rows/Create Group/Definition), далее заполняем у каждой строки это поле - на какой странице она должна находиться. В принципе можно не номера страниц, а просто при желанин сделать разрыв страницы после определенной строки увеличивать значение это поля.

Как "красиво" удалять строки.

long i
for i = dw_1.RowCount() to 1 step - 1
//Обработка i-й строки, здесь ее можно удалять, цикл все равно будет
//выполняться dw_1.RowCount() раз (на момент начала цикла).
next

Как "сбросить" границу массива переменного размера.

Если вы объявили массив, допустим как long mas[], и уже выполнили присвоение mas[5] = 1, то все элементы mas с индексами от 1 до 4 будут равны 0. Если после этого будет необходимо еще один раз воспользоваться массивом mas, но записать туда будет необходимо меньшее число элементов, то "сбросить" границу мессива можно следующим кодом:
long mas[],clr[]
mas[5] = 1
MessageBox("Верхняя граница mas[]", UpperBound(mas[]))
mas[]=clr[]
MessageBox("Верхняя граница mas[]", UpperBound(mas[]))

Каким образом можно ускорить работу с массивами переменного размера.

Если заранее известно, что в массив нужно положить N элементов, то начав присваивать с N элемента (или хотя-бы присвоив N-му элементу до начала операции присвоения "фиктивное" значение) можно существенно поднять скорость присвоения. Связано это с тем, что PowerBuilder каждый раз при присвоении типа mas[UpperBound(mas[]) + 1] = 1 выделяет фрагмент памяти под массив.
Даже если неизвестно точное число элементов, и логика программы позволяет, то периодически можно использовать что-то типа mas[UpperBound(mas[])*1.25 + 1] = 0. Вообще-то этим должен был бы озаботится Sybase, впрочем как и еще много чем...

Каким образом можно установить/получить список библиотек используемых программой.

Это можно сделать с помощью функции SetLibraryList(...). Естейственно, вызывать данную функцию необходимо до обращения к объектам из библиотек которые вы собираетесь добавить с помощью SetLibraryList(...).
Дополнение.
Для того, чтобы получить список библиотек используемых программой можно воспользоваться функцией GetLibraryList(...), но это подходит только для PowerBulider версии 7.0+. В более ранних версиях можно использовать следующий код:
string LibList=ProfileString( "pb.ini", "Application",
"$d:\pbuilder\pb6\appgal\CashTrak\cashtrak.pbl(CashTrack)" )
Значение функции ProfileString(...) будет вычисленно для переменной LibList на момент компиляции. Остается только разобрать строку LibList для выделения библиотек.
Дополнение From: "Andrew Zorin"
azorin@online.ru

Динамическое создание объектов в окне.

Для динамического создания объектов во время исполнения в PowerBuilder'е используется функция OpenUserObject(...). Для уничтожения существующего объекта созданного этой функцией необходимо вызвать функцию CloseUserObject(...). Данной функцией можно открыть только объекты созданные в User Object painter.

Динамическое изменение порядка групп в отчете.

Мне известно, как минимум, четыре подхода для решения данной задачи:
1. Динамическое генерирование запросов с клиента с необходимыми условиями.
Это способ весьма трудоемкий, и помимо всего "завязывает" на себя определенный род договоренностей ( к примеру - о структуре базы), однако конечный результат может быть весьма неплохим, кроме того, можно не ограничиваться только изменением порядка групп в отчете.
2. Изменение синтаксиса DataWindow.
Достаточно быстро работает, но, как известно, синтаксис DataWindow не документирован, что порождает дополнительные трудности и возможные проблемы с переносимостью программы на другие версии PowerBuilder'а. Кроме того этот способ требует дополнительного DataWindow или DataStore для хранения резльтатов пока изменяется синтаксис основного DataWindow. Преимущество данного способа в том, что можно создать число групп больше, чем предусмотренно в Design Time.
3. Заведение суррогатных полей для группировки.
Идея достаточно проста - завести дополнительные поля (назовем их ID1,ID2,...,IDn), по количеству равных числу групп отчета и создать группы именно по этим полям и далее, заполнить их возрастающими значениями с той последовательности, в которой надо группировать. Несколько советов по реализации. Для начала динамически сфорируйте строку и установите сортировку в том порядке, в котором вам надо группировать, что-то типа:
dw_1.SetSort("field_3 A field_1 A field_2 A")
dw_1.Sort()
После этого достаточно будет пробежаться по всем строкам dw_1 (либо один раз по всем field_1..field_n, либо бегать n раз, но в каждый проход только по какому-то одному field_i - по вкусу) увеличивая какие-то внутренние счетчики изменений полей field_1..field_n при каждом встеретившемся изменении полей и заносить их значения в ID1..IDn соответственно. После этого поставить сортировку по полям ID1..IDn. Вся реализация занимает, от силы, 40-50 строк.
4. Группы можно определять по вычисляемым полям (computed field). Таким образом, можно просто определить группу по вычисляемому полю, а затем сменить его expression.
Четвертый способ From: "Andrew Zorin"
azorin@online.ru

Ошибки при задании порядка сортировки в DataWindow.

Достаточно часто приходится видеть как начинающие, да и не только, программисты с ошибками устанавливают порядок сортировки в DataWindow (DataStore) в следующей, весьма распространенной, ситуации. Есть справочник с двумя полями - код записи (ID) и название (NAME) и наша задача заключается в сортировке по полю NAME. Но просто задать сортировку по полю NAME нельзя, т. к. в случае наличия записей с одинаковым значением NAME но разным ID получим непредсказуемый результат. Сортировка по ID нас от этого избавляет, но человеку в таком списке найти что-либо очень затруднительно. Естейственно, необходимо сортировать по NAME, а затем по ID. Другое дело, что ситуация эта достаточно странная, и если из логики задачи следует, что NAME должен быть уникальным, то можно оставить сортировку только по NAME, а контроль уникальности вести в момент занесения записи (например, с использованием unique constraints).

Печать и просмотр HTML средствами Windows.

Просмотр HTML достигается посредством вызова функции ShellExecuteEx со следующими значениями аттрибутов структуры SHELLEXECUTEINFO: SEI.lpfile="C:\MYPATH\myfile.htm"
Для этого необходима установка какого-либо просмоторщика HTML файлов.
А печать:
SEI.lpfile="rundll32.exe"
SEI.lpparameters="MSHTML.DLL,PrintHTML C:\MYPATH\myfile.htm"
при этом вызывается диалог печати Internet Explorer'а. Естейственно, предварительно он должен быть установлен на машине. Реализация функции Windows API SchellExecuteEx есть в библиотеке
WinAPI.

Как получить DWObject для колонок DataWindow.

Для версии PB 6:
DWObject dwo dwo = dw_1.object.get_attribute( "column_name",True)
Для PB 7, 8 и 9:
dwo = dw_1.object.__get_attribute( "column_name",True)
From: "Anatoly Moskovsky"
avm@trais.com.ua

Как получить значения колонок и текста в DataWindow типа Crosstab.

Предположим, что колонка, по которой разворачивается отчет называется colname, а текст textname. Тогда для обращения к соответствующим столбцам нужно использовать следующие имена:
№ колонки Данные Текст
1colnametextname
2colname_1textname_1_t
3colname_2textname_2_t
4colname_3textname_3_t
5colname_4textname_4_t
.........
Примечание: для того, чтобы таким образом можно было обращаться к объектам DataWindow необходимо выполнить команду:
dw_1.Modify("DataWindow.Crosstab.StaticMode = Yes" )
Как получить доступ к вложенным отчетам (nested reports).

Доступ к значениям лежащим в nested report можно получить через "точечную нотацию". Однако это весьма плохой способ - можно получить только доступ к данным, и то остается открытым вопрос о том, если число строк во вложенном отчете равно 0 - тогда при попытке обращения к данным отчета произойдет ошибка. В PowerBuilder не предусмотренно интерфейса для доступа к вложенным отчетам, однако его можно обмануть, исправив тип отчета на компоизтный и воспользовавшись функцией GetChild(...). Пример:
string s
long ll_rc,i
DataWindowChild dwch

s=dw_1.Describe( "DataWindow.Processing")
dw_1.Modify("DataWindow.Processing=5")
ll_rc = dw_1.RowCount()

for i = 1 to ll_rc
dw_1.GetChild("ds_nested_items",dwch)
MessageBox("",dwch.RowCount())
dw_1.RowsMove(1,1, Primary!,dw_1,ll_rc + 1,Primary!)
next

dw_1.Modify("DataWindow.Processing=" + s)



Адрес для связи с автором:
fidonet 2:5025/3.147 Mark_Lokshin@p147.f3.n5025.z2.fidonet.org
e-mail lokshin_mark@mail.ru

Hosted by uCoz