Форум поддержки пользователей. LibreOffice, Apache OpenOffice, OpenOffice.org

Форум поддержки пользователей. LibreOffice, Apache OpenOffice, OpenOffice.org

22 Май 2022, 14:25 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
Новости: Доступно и просто о работе в офисных пакетах
 
   Начало   Помощь Поиск Войти Регистрация    задать вопрос  
Страниц: « 1 2 3   Вниз
  Печать  
Автор Тема: Функции для работы с диапазонами как множеством ячеек  (Прочитано 2766 раз)
0 Пользователей и 1 Гость смотрят эту тему.
mikekaganski
Гуру
*******
Offline Offline

Пол: Мужской
Расположение: Хабаровск -> Москва
Сообщений: 2 726


« Ответ #30: 28 Апрель 2022, 13:19 »

Не в порядке критики, а так, в порядке размышлений, скажу следующее. Непросто найти компромисс между универсальностью применения функции и сложностью её реализации. Вы придерживаетесь первого (функция принимает аргумент в любом виде), а я напротив: более явно определяю параметры функции и облегчаю реализацию. Вы "помогаете" пользователю, а я "дисциплинирую" его.

Лучше всего дисциплинирует пользователя уничтожение поддержки всех языков написания макросов, кроме ассемблера.

Не в порядке критики, а так, в порядке размышлений, скажу следующее. Заставлять пользователя городить повторяющиеся куски кода всякий раз, когда он хочет вызвать функцию, которая технически способна скрыть эту работу, при этом не создавая неопределённости и неожиданного поведения - мало похоже на полезное использование вычислительной техники.
Записан

С уважением,
Михаил Каганский
eeigor
Опытный пользователь
***
Offline Offline

Пол: Мужской
Сообщений: 1 088


« Ответ #31: 28 Апрель 2022, 13:46 »

Михаил, Вы, будучи профессионалом в данной области, оказываете некоторое давление на пользователя, сковывая его активность. А надо просто помогать, что Вы и успешно, и нередко делаете, но… не будьте столь категоричны к нам. Вы нам нужны для другого.

А что касается универсальности, то метод addRangeAddress мог бы и принять CellAddress, как, к примеру, сервис SheetCellRange поддерживает SheetCell (пишу по памяти). Но пошли другим путём: добавили к ячейке свойство RangeAddress. О чём узнал только сегодня, ибо не логично, но понятно зачем.
« Последнее редактирование: 28 Апрель 2022, 13:51 от eeigor » Записан

Ubuntu 18.04 LTS • LibreOffice 7.3.2.2 Community
sokol92
Опытный пользователь
***
Offline Offline

Пол: Мужской
Сообщений: 909


WWW
« Ответ #32: 28 Апрель 2022, 15:03 »

метод addRangeAddress мог бы и принять CellAddress
В методах UNO, если типом параметра указана структура, то никаких "вольностей" не допускается.

Сервис SheetCell не включает себя сервис SheetCellRange и наоборот.

Код:
Sub Test
  Dim oCell, oCell2
  With ThisComponent.Sheets(0)
    oCell=.getCellByPosition(0, 0)
    oCell2=.getCellRangeByPosition(0, 0, 0, 0)
  End With
End Sub

В приведенном выше макросе переменная oCell будет содержать ссылку на объект, который, в частности, поддерживает сервисы SheetCell и SheetCellRange.
Переменная oCell2 будет содержать ссылку на объект, который, в частности, поддерживает SheetCellRange и не поддерживает SheetCell.

Записан

Владимир.
eeigor
Опытный пользователь
***
Offline Offline

Пол: Мужской
Сообщений: 1 088


« Ответ #33: 28 Апрель 2022, 16:42 »

Владимир, спасибо
Записан

Ubuntu 18.04 LTS • LibreOffice 7.3.2.2 Community
eeigor
Опытный пользователь
***
Offline Offline

Пол: Мужской
Сообщений: 1 088


« Ответ #34: 29 Апрель 2022, 06:30 »

Если оперировать поячеечно, то несложно выполнить любую операцию с множествами ячеек. Но в функциях Intersect и Union были задействованы штатные возможности.
В коде ниже при вычитании (Difference) использована функция GetCellCollection.
В качестве ключа элемента коллекции ячеек задано имя ячейки AbsoluteName. По ключу и удаляем (вычитаем) ненужные ячейки.
В примере от @sokol92 использован словарь (Map) с ключом в виде отформатированной комбинации свойств (индексы листа, столбца, строки...). Сделано это для решения проблемы сортировки ячеек при их помещении (put) в словарь. Таким образом, если использовать этот подход, то и ключ будет соответствующим при удалении ячейки из словаря.
Работать с VBA Collection проще, но возникла проблема с сортировкой ячеек перед их добавлении в коллекцию. В ответе #21 приведен пример сортировки, если бы это был не Basic, а Python. В ответе #22 показан способ сортировки через выделение на листе, но он имеет баг при выделении диапазонов, расположенных на нескольких листах (возможный, но менее вероятный случай).
Впрочем, несложно реализовать функцию AddToSortedCollection
  Function AddToSortedCollection(col As Collection, vNewItem, Optional sKey$) As Boolean
которая добавит новый элемент на правильное место (метод Add имеет параметр, определяющий место вставки i: col.Add vNewItem, sKey, i)
Тогда для правильной сортировки придется изменить ключ (подход от @sokol92), отформатировав строку исходя из:
Each spreadsheet can have up to 10 000 sheets, and each sheet can have a maximum of 1 048 576 rows and a maximum of 1 024 columns.

Difference()
Код:
Function Difference(RangeAddress As com.sun.star.table.CellRangeAddress _
 , RangeAddresses() As com.sun.star.table.CellRangeAddress) As Object
''' Subtract other cell ranges (or a range) from the specified cell range.
''' Argument:
''' RangeAddress: The specified cell range (its address).
''' RangeAddresses():
''' A sequence of other cell ranges (their addresses)
''' to be subtracted (excluded) from the specified range.
''' Return a new range with elements in the range that are not in the others.
''' range - other - …  '(S = A \ B)

On Local Error GoTo HandleErrors
Dim oRanges As Object, oCell As Object
Dim A As New Collection, B As New Collection

A = GetCellCollection(Array(RangeAddress))
B = GetCellCollection(RangeAddresses())

On Local Error Resume Next
For Each oCell In B
A.Remove oCell.AbsoluteName
Next
On Local Error GoTo HandleErrors

oRanges = ThisComponent.createInstance("com.sun.star.sheet.SheetCellRanges")
For Each oCell In A
oRanges.addRangeAddress(oCell.RangeAddress, True)
Next

Difference = IIf(oRanges.Count, oRanges, Nothing)
Exit Function

HandleErrors:
Msgbox "Error " & Err & " at line " & Erl & ": " & Error _
, MB_ICONSTOP, "macro:Difference()"
End Function

Sub Test_Difference()
Dim oRanges As Object, oRange1 As Object, oRange2 As Object

With ThisComponent.CurrentController.ActiveSheet
oRange1 = .getCellRangeByName("B3:F25")
oRange2 = .getCellRangeByName("B4:G4")
End With

oRanges = Difference(oRange1.RangeAddress, Array(oRange2.RangeAddress))
MsgBox oRanges.AbsoluteName
End Sub
« Последнее редактирование: 1 Май 2022, 12:02 от eeigor » Записан

Ubuntu 18.04 LTS • LibreOffice 7.3.2.2 Community
eeigor
Опытный пользователь
***
Offline Offline

Пол: Мужской
Сообщений: 1 088


« Ответ #35: 1 Май 2022, 11:55 »

SymmetricDifference()
Код:
Function SymmetricDifference(RangeAddress As com.sun.star.table.CellRangeAddress _
 , RangeAddress2 As com.sun.star.table.CellRangeAddress) As Object
''' Substract a cell range that is in both passed ranges, but not at their intersection (disjunctive union).
''' Arguments:
''' RangeAddress: The specified cell range address.
''' RangeAddress2: The other cell range address.
''' range ^ other  'S = A Δ B = (A ∪ B) \ (A ∩ B) = (A \ B) ∪ (B \ A)
''' Return new range(s) as com.sun.star.sheet.XSheetCellRanges with elements
''' either in the specified range or in the other range, but not both.

On Local Error GoTo HandleErrors
Dim oRanges As Object
oRanges = Difference(RangeAddress, Array(RangeAddress2))
oRanges.addRangeAddresses(Difference(RangeAddress2, Array(RangeAddress)).RangeAddresses, True)

SymmetricDifference = IIf(oRanges.Count, oRanges, Nothing)
Exit Function

HandleErrors:
Msgbox "Error " & Err & " at line " & Erl & ": " & Error _
, MB_ICONSTOP, "macro:SymmetricDifference()"
End Function

Sub Test_SymmetricDifference()
Dim oRanges As Object, oRange1 As Object, oRange2 As Object

With ThisComponent.CurrentController.ActiveSheet
oRange1 = .getCellRangeByName("B3:F25")
oRange2 = .getCellRangeByName("B4:G4")
End With

oRanges = SymmetricDifference(oRange1.RangeAddress, oRange2.RangeAddress)
MsgBox oRanges.AbsoluteName
End Sub

« Последнее редактирование: 1 Май 2022, 11:57 от eeigor » Записан

Ubuntu 18.04 LTS • LibreOffice 7.3.2.2 Community
eeigor
Опытный пользователь
***
Offline Offline

Пол: Мужской
Сообщений: 1 088


« Ответ #36: 1 Май 2022, 12:57 »

InvertSelection()
Код:
Sub InvertSelection(oTarget As Object)
''' Invert the current selection that intersects the target range.
''' Argument:
''' oTarget: One cell or cell range(s).

On Local Error GoTo HandleErrors
Dim oSelection As Object, oRanges As Object, oRange As Object

oSelection = ThisComponent.CurrentSelection
If oSelection.supportsService("com.sun.star.sheet.SheetCellRanges") Then
oRanges = oSelection
oRanges = Difference(oTarget.RangeAddress, oRanges.RangeAddresses)
ElseIf oSelection.supportsService("com.sun.star.sheet.SheetCellRange") Then
oRange = oSelection
oRanges = Difference(oTarget.RangeAddress, Array(oRange.RangeAddress))
Else
MsgBox "No single cell or range(s) selected." _
, MB_ICONEXCLAMATION, "Selection Error"
Exit Sub
End If

ThisComponent.CurrentController.select(oRanges)
Exit Sub

HandleErrors:
Msgbox "Error " & Err & " at line " & Erl & ": " & Error _
, MB_ICONSTOP, "macro:InvertSelection"
End Sub

Sub Test_InvertSelection()
Dim oRanges As Object, oRange As Object

With ThisComponent.CurrentController.ActiveSheet
oRange = .getCellRangeByName("B3:F25")
End With
oRanges = oRange.queryEmptyCells()
ThisComponent.CurrentController.select(oRanges)
MsgBox "Before:" & Chr(10) & ThisComponent.CurrentSelection.AbsoluteName
Call InvertSelection(oRange)
MsgBox "After:" & Chr(10) & ThisComponent.CurrentSelection.AbsoluteName
End Sub

Но тут требуется решить, как быть с текущей ячейкой в пределах целевого диапазона: считать её выделением или нет?
Edit:
Как отличить активную ячейку от выделенной (цветом)?
« Последнее редактирование: 1 Май 2022, 19:42 от eeigor » Записан

Ubuntu 18.04 LTS • LibreOffice 7.3.2.2 Community
eeigor
Опытный пользователь
***
Offline Offline

Пол: Мужской
Сообщений: 1 088


« Ответ #37: 1 Май 2022, 13:03 »

Вопрос решён в основном. За мной один баг с "задвоением" расположенных на разных листах диапазонов при их выделении (ответ #23).
Требуется окончательно решить, какой метод получения ячеек использовать: VBA Collection vs EnumerableMap. Именно вспомогательная функция GetCellCollection и стала основной в этом "инструментальном" наборе.

Повторю: тема была направлена на решение конкретной задачи.


Edit:
Возможно, будут какие-то замечания/предложения по этому набору (прежде всего, в части сигнатуры процедур). Высказывайтесь... Работа проводилась с заделом на будущее.
« Последнее редактирование: 1 Май 2022, 13:33 от eeigor » Записан

Ubuntu 18.04 LTS • LibreOffice 7.3.2.2 Community
eeigor
Опытный пользователь
***
Offline Offline

Пол: Мужской
Сообщений: 1 088


« Ответ #38: 1 Май 2022, 21:23 »

За мной один баг с "задвоением" расположенных на разных листах диапазонов при их выделении (ответ #23).
Bug report
Записан

Ubuntu 18.04 LTS • LibreOffice 7.3.2.2 Community
kompilainenn
Мастер
*****
Offline Offline

Сообщений: 3 447



« Ответ #39: 1 Май 2022, 21:49 »

Bug report
проблема в работе макроса или в работе самого Calc?
Записан

Поддержать разработчиков LibreOffice можно тут, а наш форум вот тут
eeigor
Опытный пользователь
***
Offline Offline

Пол: Мужской
Сообщений: 1 088


« Ответ #40: 1 Май 2022, 21:56 »

Проблема в методе select при выделении ячеек, расположенных на нескольких (зд. двух) листах. Ячейки первого листа выделяются в том числе и на втором, а ячейка второго листа в примере (файл приложен) выделяется в том числе и на первом листе. В результате количество ячеек удваиваится.

* multisheet-selection-error.ods (45.2 Кб - загружено 0 раз.)
Записан

Ubuntu 18.04 LTS • LibreOffice 7.3.2.2 Community
Страниц: « 1 2 3   Вверх
  Печать  
 
Перейти в:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!