Возможно ли создать многостраничную форму в LO Base

Автор Kadet, 25 ноября 2019, 21:58

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

Kadet

Лист достаётся без проблем. Он у меня даже в глобальной переменной зашит.
Но в этом листе при нажатии любой из кнопок активной ячейкой является нулевая ячейка (0,0) по-умолчанию, или какая-нибудь другая, в которой ранее кликал, а не та, к которой привязана нажимаемая кнопка. А мне нужна именно эта ячейка, в которой сидит кнопка, которую я сейчас нажимаю. По сути нужен один только номер строки (oRow), в которой находится эта кнопка.

mikekaganski

#61
Нет прямого способа найти привязку кнопки (вот не знаю уж почему). Единственный вариант - это перебрать все элементы на текущей DrawPage (циклом по DrawPage(i) до DrawPage.Count-1), сравнивать у каждого элемента, является ли модель тем же объектом, что и модель текущего события (EqualUnoObjects), и уже тогда получить Anchor найденного объекта:


Function GetAnchor(ByRef oButton As Object) As Object
Dim oDrawPage As Object, i As Long, obj As Object
oDrawPage = ThisComponent.CurrentController.ActiveSheet.DrawPage
For i = 0 To oDrawPage.Count - 1
obj = oDrawPage(i)
If (EqualUnoObjects(obj.Control, oButton)) Then
GetAnchor = obj.Anchor
Exit Function
End If
Next i
End Function

...

buttonAnchor = GetAnchor(oEvent.Source.getModel())


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


Function GetAnchor(ByRef oButton As Object) As Object
Dim oDrawPages As Object, oDrawPage As Object, i As Long, j As Long, obj As Object
obj = oButton
Do While (Not(obj Is Nothing) And Not HasUnoInterfaces(obj, "com.sun.star.drawing.XDrawPagesSupplier"))
If (HasUnoInterfaces(obj, "com.sun.star.container.XChild")) Then
obj = obj.Parent
Else
obj = Nothing
End If
Loop
If (Not(obj Is Nothing)) Then
oDrawPages = obj.DrawPages
For i = 0 To oDrawPages.Count - 1
oDrawPage = oDrawPages(i)
For j = 0 To oDrawPage.Count - 1
obj = oDrawPage(j)
If (EqualUnoObjects(obj.Control, oButton)) Then
GetAnchor = obj.Anchor
Exit Function
End If
Next j
Next i
End If
End Function


Однако если идти в обход не претит, то возможно, всё же быстрее использовать дополнительно к свойству Name ещё и свойство Tag, и/или хранить всю информацию (и номер заказа, и номер строки, и ещё всё что угодно) в одной строке, разделённой спецсимволами (например, "|" или вообще недоступными пользователю, типа Chr(1)), и пользовать Split для получения массива значений из такой строки.
С уважением,
Михаил Каганский

Kadet

mikekaganski, спасибо! Самая простая идея, думаю, использовать таки свойство Tag для передачи номера строки.

А я так хотел уйти от перебора. Там можно и гораздо проще сделать. Дело в том, что в 0 столбце этой же строки, в которой кнопка, занесено тоже значение номера заказа. И можно просто перебором сравнивать все значения нулевого столбца, пока не будет совпадения с Name кнопки.

Однако, всё таки, сдаётся мне, что есть какой-то метод прямого доступа к адресу привязки.
Ну а пока, попробую Tag или перебор ячеек.

mikekaganski

Цитата: Kadet от 10 декабря 2019, 13:28Однако, всё таки, сдаётся мне, что есть какой-то метод прямого доступа к адресу привязки.
Да нет такого метода.
Когда вызывается событие, его источник - элемент формы. У форм и их элементов нет знания о их родительском листе (DrawingPage). У формы есть набор своих объектов (view - со своими свойствами), которые ссылаются на модель кнопки. А у DrawingPage - свои объекты view (со своими свойствами, в числе которых привязка), ссылающиеся на ту же модель. Модель вообще ничего о своих view не знает. Так что перебор - единственный доступный способ.

Конечно, можно ещё воспользоваться тем, что кнопка позволяет добавлять себе свойства динамически - но при наличии Tag это в общем-то не добавляет ничего полезного.
С уважением,
Михаил Каганский

Kadet

Проверил метод Tag. Прекрасно работает. Спасибо за идею.

mikekaganski

Да кстати, у Вас постоянно кнопки добавляются, но не удаляются. При очистке делатей кнопки остаются болтаться, и там их у вас накопится столько, что оно начнёт падать. Так что всё-таки Вам понадобится искать ControlShape для модели, и удалёть его с DrawPage в DETAL_del:


Function GetControlShape(ByRef oButton As Object) As Object
Dim oDrawPages As Object, oDrawPage As Object, i As Long, j As Long, obj As Object
obj = oButton
Do While (Not(obj Is Nothing) And Not HasUnoInterfaces(obj, "com.sun.star.drawing.XDrawPagesSupplier"))
If (HasUnoInterfaces(obj, "com.sun.star.container.XChild")) Then
obj = obj.Parent
Else
obj = Nothing
End If
Loop
If (Not(obj Is Nothing)) Then
oDrawPages = obj.DrawPages
For i = 0 To oDrawPages.Count - 1
oDrawPage = oDrawPages(i)
For j = 0 To oDrawPage.Count - 1
obj = oDrawPage(j)
If (HasUnoInterfaces(obj, "com.sun.star.drawing.XControlShape")) Then
If (EqualUnoObjects(obj.Control, oButton)) Then
GetControlShape = obj
Exit Function
End If
End If
Next j
Next i
End If
End Function

Sub DETAL_del(oEvent)
Dim oDoc, oController, oSheet, oRange, oRow, oShape

oDoc = ThisComponent

oDoc.lockControllers()
On Error GoTo Cleanup

oController = oDoc.CurrentController

oSheet = oDoc.sheets(0)
oShape = GetControlShape(oEvent.Source.getModel())
oRow = CInt(oEvent.Source.getModel().Name)
HideRows1(oDoc, oSheet, oRow-1, oRow)
oSheet.DrawPage.remove(oShape)
oRange = oSheet.getCellRangeByPosition(0,oRow-1,100,oRow)
oRange.clearContents(255)
oRange = oSheet.getCellRangeByPosition(11,oRow-2,11,oRow-2)
oController.select(oRange)

Cleanup:
oDoc.unlockControllers()
End Sub
С уважением,
Михаил Каганский

Kadet

А разве "oRange.clearContents(1023)" не удаляет все хвосты? Мне Rami рекомендовал этим методом пользоваться и говорил, что все хвосты подчищает "одним движением"?!.

mikekaganski

Ну, непонятно происхождение константы 1023 (в коде у Вас вообще 255 - см. тут). Но таки да, попытка очистки производится - но тут есть закавыка. Объект должен полностью находится внутри удаляемого диапазона, и это накладывает ограничения. Во-первых, нельзя просто взять размер ячейки и назначить кнопке (вы так и не делали - Вы назначили высоту на 50 меньше, что помогло ... бы, если бы не); во-вторых, удаление должно быть не в скрытом диапазоне: скрытый диапазон имеет высоту 1, тогда как высота кнопки больше -> никогда кнопка не окажется внутри скрытого диапазона.

Так что проще и надёжнее объекты удалять вручную.
С уважением,
Михаил Каганский

Kadet

#68
А если просто удалить всю форму, в которой сидят эти кнопки, да ещё сверху "полирнуть" clearContents(1023)?
Я всё же не пойму. Вначале я делал так - удалял всю форму, в которой формировались кнопки, а ячейки чистил clearContents(255) (нашёл этот параметр эмпирическим путём). Rami сказал, что проще и лучше чистить просто clearContents(1023), мол при прежнем методе остаются некие невидимые рамки и следы от кнопок.
Теперь выясняется, что и clearContents(1023) не может всё почистить до конца.

Дабы избежать ненужных подений базы, которые случаются, я бы хотел разобраться. Не очень хочется запускать достаточно массивный и громоздкий чистильщик, в особенности когда мои юзеры весьма нетерпеливые и тыкают всё время куда попало, не дожидаясь окончания процедур (а закрывать такие возможности тоже нельзя ибо будет хуже).
Так вот, есть ли возможность посмотреть после проведённой чистки почистился ли лист calc до конца или таки нет?

rami

Цитата: Kadet от 10 декабря 2019, 19:08А если просто удалить всю форму, в которой сидят эти кнопки, да ещё сверху "полирнуть" clearContents(1023)?
Тогда и кнопка запуска макроса "Кнопка" сотрётся.

Цитата: Kadet от 10 декабря 2019, 19:08Теперь выясняется, что и clearContents(1023) не может всё почистить до конца.
clearContents(1023) чистит всё, но и clearContents(255) может быть достаточно для ваших целей. Если скрываемый диапазон меньше чем очищаемый, то удаляет нормально. А зачем вы скрываете?

Kadet

#70
Вообще-то под скрываемым диапазоном у меня ничего никогда нет... не должно быть.
Там как бы несколько скрытых диапазонов. От 0 до 100 это раздел набора деталей. А всё, что свыше - не переделанные остатки от прежних не совсем удачных идей. Поначалу я вообще делал "красоту", прорисовывая слои и много слойные "пачки" в зависимости от количества штук заготовок того или иного раскроя. Прорисовку делал узенькими и тоненькими ячейками с прорисовкой сетки. Получилось весьма сложно, длительно и, вопреки ожиданиям, не красиво. В итоге основную часть хвостов от этой идеи я почистил, а часть неуглядел. Да и времени на это не было. Глубоко не стал заморачиваться. Может быть сейчас займусь и подчищю остатки.

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

rami

Если в скрываемых местах нет кнопок, то не понимаю в чём проблема со стиранием кнопок?

Kadet, есть идея с передачей нужных параметров помимо "Tag", с помощью "ActionCommand" события кнопки, это легко, нужно добавить одну строку кода в функцию "Sub AddButton(oCol, oRow, nam, label, width, color, macro)". Напишу в следующем ответе.

rami

Цитата: mikekaganski от 10 декабря 2019, 12:24Нет прямого способа найти привязку кнопки (вот не знаю уж почему).
К ячейке привязывается не сама кнопка, а ControlShape внутри которой находится кнопка, с другой стороны, событие передаёт кнопку, а не ControlShape.

Свойство "Tag" используется как "записная книжка" у модели многих элементов управления, но у кнопки есть ещё один простой и более доступный метод (и свойство) "setActionCommand", это значение легко достаётся из события:
Sub AddButton(oCol, oRow, nam, label, width, color, macro)
Dim oSheet, vCell, oDrawPage, oControlShape, oButtonModel, sScriptURL$, oForm, but
Dim aSize As new com.sun.star.awt.Size
Dim aEvent As new com.sun.star.script.ScriptEventDescriptor

oSheet = oDoc.sheets(0)
oDrawPage = oSheet.DrawPage

oControlShape = oDoc.createInstance("com.sun.star.drawing.ControlShape")
vCell = oSheet.getCellByPosition(oCol, oRow)
oControlShape.setPosition(vCell.Position)
aSize.Width = width
aSize.Height = 400
oControlShape.setSize(aSize)

oButtonModel = CreateUnoService("com.sun.star.form.component.CommandButton")
oButtonModel.Label = label
oButtonModel.FontStyleName = "Полужирный"
oButtonModel.FontWeight = 150
oButtonModel.FontHeight = 10
oButtonModel.TextColor = color
oButtonModel.VerticalAlign = com.sun.star.style.VerticalAlignment.MIDDLE
oButtonModel.Name = nam & oRow
oButtonModel.Printable = False

oControlShape.setControl(oButtonModel)
oDrawPage.add(oControlShape)

'добавляем в событие для данной кнопки значение ActionCommand, например, имя и номер строки
oDoc.CurrentController.getControl(oButtonModel).setActionCommand("ActionCommand: " & nam & oRow)

sScriptURL = "vnd.sun.star.script:Standard.Module1." & macro & "?language=Basic&location=document"
oForm = oDrawPage.getForms().getByIndex(0)
With aEvent
.AddListenerParam = "asd"
.EventMethod = "actionPerformed"
.ListenerType = "XActionListener"
.ScriptCode = sScriptURL
.ScriptType = "StarScript"
End With
oForm.registerScriptEvent(oForm.Count-1, aEvent)

oControlShape.Anchor = vCell
oControlShape.MoveProtect = True
oControlShape.SizeProtect = True

oDoc.CurrentController.setFormDesignMode(false) 'выйти из режима редактирования
End Sub

Sub ButtonPushEvent(ev as com.sun.star.awt.ActionEvent) 'срабатывает при нажатии кнопок
msgbox ev.ActionCommand 'получаем значение ActionCommand
End Sub

Kadet

Цитата: rami от 10 декабря 2019, 22:52есть идея с передачей нужных параметров помимо "Tag", с помощью "ActionCommand" события кнопки
Добавил событие, по вашей рекомендации. Ожидал при нажатии кнопок увидеть некое сообщение по msgbox, но пока ничего не увидел. Попробую пошагово прогнать.

rami

Если msgbox не вызывается, то макроось не назначался или что-то не срослось. К двум указанным макросам добавьте макрос DemoCalc из документа DEMO4 что я выложил раньше.