Удаление строки с непустыми ячейками в Calc

Автор siti, 11 апреля 2022, 13:43

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

siti

Может быть есть добрые люди которые помогут с макросом. Знания близки к нулю в VB, но срочно понадобилось сделать следующее:
На листе в Calc надо удалить те строки в которых все ячейки в строке не пустые в выделенном пользователем цельном произвольном диапазоне ячеек.
То есть удалять именно строку целиком, а не ячейки из выделения.
В примере на картинке надо удалить строки 12 и 13

Поиском в сети не смог разобраться как работать с выделениями  :(

economist

1) Напишите с пустом столбце справа формулу, учитывающую пустоту ячеек вида =И(D2="";E2="";F2="")
2) Включите Автофильтр по этому столбцу и оставьте в нем только то, что нужно удалить
3) Выделите удаляемые строки и удалите

Макрорекордер запишет 95% этих действий, вот и макрос...
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

sokol92

Если выделен прямоугольный диапазон ячеек, то проблемы нет:
' Удаляет строки выделенного прямоугольного диапазона ячеек
Sub RemoveSelectionRows
  Dim oSel
  oSel=ThisComponent.CurrentSelection
  If oSel.supportsService("com.sun.star.sheet.SheetCellRange") Then
    oSel.SpreadSheet.removeRange oSel.RangeAddress, com.sun.star.sheet.CellDeleteMode.ROWS
  End If 
End Sub
Владимир.

siti

#3
Цитата: economist от 11 апреля 2022, 14:181) Напишите с пустом столбце справа формулу, учитывающую пустоту ячеек вида =И(D2="";E2="";F2="")
Попробовал. Для фиксированного кол-ва столбцов решение отличное, но если мне надо брать не весь диапазон из формулы, то при удалении лишних столбцов формула ломается. Пишет #ССЫЛ
Мне нужно из 12 столбцов каждый раз выделение из разного кол-во столбцов анализировать на полную занятость в строках выделения и удалять (или разом отфильтровывать) их.

siti

#4
Цитата: sokol92 от 11 апреля 2022, 14:29Если выделен прямоугольный диапазон ячеек, то проблемы нет:
Это просто удаляет строки выделенного диапазона.
Мне нужно удалить строку только если все значения в строке выделения не пустые.

sokol92

Прошу прошения, невнимательно прочитал стартовое сообшение. Попробуйте так (RemoveSelectionFullRows):
Sub RemoveSelectionFullRows() 
  Dim oSel
  oSel=ThisComponent.CurrentSelection
  If oSel.supportsService("com.sun.star.sheet.SheetCellRange") Then
    RemoveRangeFullRows oSel
  End If 
End Sub

' Удаляет (полные) строки прямоугольного диапазона ячеек, если в строке все ячейки не пустые.
Sub RemoveRangeFullRows(ByVal oRange)
  Dim oRange2, arr, v, adr, bDel As Boolean, i As Long, i1 As Long, i2 As Long
  arr=oRange.DataArray
  i2=-1
 
  For i=Ubound(arr) To 0 Step -1 ' строки удаляем снизу вверх
    bDel=True
    For Each v In arr(i)
      If v="" Then
        bDel=False
        Exit For
      End If 
    Next v
   
    If  bDel Then ' i-я строка диапазона должна быть удалена. Запоминаем.
      If i2=-1 Then i2=i
      i1=i
    Else
      If i2>=0 Then
        oRange2=oRange.getCellRangeByPosition(0, i1, 0, i2)
        oRAnge2.SpreadSheet.removeRange oRange2.RangeAddress, com.sun.star.sheet.CellDeleteMode.ROWS         
        i2=-1
      End If 
    End If 
  Next i
   
  If i2>=0 Then
    oRange2=oRange.getCellRangeByPosition(0, i1, 0, i2)
    oRAnge2.SpreadSheet.removeRange oRange2.RangeAddress, com.sun.star.sheet.CellDeleteMode.ROWS
  End If 
   
End Sub 
Владимир.

eeigor

#6
Возможен другой алгоритм решения этой задачи.
1. Вы выделяете требуемый диапазон.
2. Макрос получает пустые ячейки в выделенном диапазоне. Здесь неважно, если в строке может быть более одной пустой ячейки.
Предполагается, что удобно выделять столбцы целиком. Поэтому ниже используется уже ставшая стандартной пользовательская функция UsedArea().
   oSheet = ThisComponent.CurrentController.ActiveSheet
   oUsedArea = UsedArea(oSheet)
   oRanges = ThisComponent.CurrentSelection _
    .queryIntersection(oUsedArea.RangeAddress).queryEmptyCells()
3. Макрос удаляет те строки, в которые не попали пустые ячейки.
Цикл снизу вверх, как у @sokol92, но с проверкой индекса удаляемой строки.

Edit 1:
С другой стороны, полезно писать процедуры, которыми вы сможете воспользоваться в дальнейшем.
Тогда эту задачу можно разбить на 3 действия:
Выберите диапазон.
Макросы:
1. Выделить пустые ячейки в выбранном пользователем диапазоне (SelectEmptyCells).
2. Распространить выделение ячейки (ячеек в одной строке) диапазона на всю строку (SelectEntireRows).
3. Инвертировать выделение (InvertSelection(Reference As Object), где Reference - это объект Range(s), в котором что-то да выделено).
На экране будет то, что вы могли бы получить, работая вручную.
Самостоятельно удалите выделенные строки.

При таком подходе у вас будет что-то оставаться для использования в будущем. Пишите полезными блоками.
В частности, выделение пустых ячеек в выделенном диапазоне - это полезная процедура, и у меня (и не только) она давно написана. Потому что она есть в Excel и нужна в Calc. Стало быть, в Вашей задаче для меня интерес представляет инверсия выделения (как в окне Автофильтра): это может пригодиться.

Дальше – в зависимости от вашей заинтересованности. @sokol92 в принципе решил вашу задачу.


Edit 2: OFF TOPIC : Кто-нибудь уже реализовал это? Поделитесь...

Что в LO BASIC есть из функций для работы с множествами (диапазонами), кроме пересечения? В Python есть всё.
Объединение, разность, симметричная разность?..

[Union] = rgA + rgB
[Union] = oRanges.addRangeAddresses(Array(rgA.RangeAddress, rgB.RangeAddress), bMergeRanges:=True)  'Может так?

[Difference] = rgA - rgB
[Difference] = oRanges.removeRangeAddress(rgB.RangeAddress)  'И так?

[SymmetricDifference] = Union(rgA, rgB) - Intersect(rgA, rgB)

И тогда для решения задачи автора мы бы вычли из исходного (выделенного пользователем) диапазона те строки, что содержат пустые ячейки, и полученную разницу снова выделили бы. Это и есть результат. Проблемка с "вычитанием". Есть готовая реализация? То, что выше, я не пробовал...
Но если "загнать-добавить" весь исходный диапазон в объект oRanges и "вычесть-удалить" из него выделенные строки (не целые, а в пределах выделенного исходного диапазона), то теоретически мы получим результат, который надо выделить снова и удалить. Или не получим... Мысли вслух.
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

siti

Всем огромное спасибо.
Метод sokol92 подошел мне максимально, плюс он позволил мне добавить еще одно условие по содержанию другого ключа в ячейке, помимо пусто/не пусто.

siti

Цитата: sokol92 от 11 апреля 2022, 15:39Прошу прошения, невнимательно прочитал стартовое сообшение. Попробуйте так (RemoveSelectionFullRows):
Код:
А в этом методе возможно получить адрес анализируемой ячейки v In arr(i) не прибегая к переменным счетчикам (i)?
Использую данную процедуру для анализа содержимого выделения и хочу выделять цветом определенные ячейки.
Если приблизить к теме топика то, например выделить цветом не пустую ячейку.

eeigor

#9
Цитата: siti от 11 мая 2022, 10:50А в этом методе возможно получить адрес анализируемой ячейки v In arr(i) не прибегая к переменным счетчикам (i)?
Вы ведь перебираете построчно (i - индекс строки)...
Чтобы получить ссылку на ячейку, нужен ещё индекс столбца j. Тогда: oCell = oSheet.getCellByPosition(j, i)

А вообще, много воды утекло с тех пор, и была реализована тема.
В вашем распоряжении следующие процедуры:
Intersection(), Union(), Difference(), SymmetricDifference(), GetCellCollection(), InvertSelection

Теперь можно пойти другим путем:
1. Выделить пустые ячейки в выбранном пользователем диапазоне (SelectEmptyCells). Для этого надо получить диапазоны, содержащие пустые ячейки, и выделить их. Есть 2 метода: oRanges = oRange.getEmptyCells(), ThisComponent.CurrentController.select(oRanges).
2. Распространить выделение ячейки (ячеек в одной строке) диапазона на всю строку (SelectEntireRows). Тоже не сложно (свойство Rows, метод getRows).
3. Инвертировать выделение (InvertSelection). Готовая процедура: вызывает Difference(), а последняя использует GetCellCollection().

А функция GetCellCollection вернёт именно ячейки со всеми их свойствами.

Edit:
Может, перепишем макрос, и заодно протестируем этот набор "инструментов"? Но, похоже, Вам следует уточнить условия задачи...
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

siti

Цитата: eeigor от 11 мая 2022, 11:46Вы ведь перебираете построчно (i - индекс строки)...
Чтобы получить ссылку на ячейку, нужен ещё индекс столбца.
в принципе да, я уже тоже догадался добавить i3 (условно).
Вопрос снимается, как глупый.

В вашей реализованной теме мне кажется немного не то, что мне требуется. Я уже анализирую текст содержимого ячейки в цикле, а не просто пусто/занято. И надо выделить ячейку при определенном условии.

eeigor

#11
Да, но функция GetCellCollection позволяет работать с ячейками без всяких индексов в инвертированном диапазоне.
For Each oCell In оCellCollection
   MsgBox oCell.String  'oCell.AbsoluteName
   If oCell.String Like "*abc*" Then
       ThisComponent.CurrentController.select(oCell)  'contains "abc"
       Exit For
   End If
Next


Ячейки, отвечающие условию, надо добавить в объект диапазонов (addRangeAddress) поячеечно и выделить разом. Если речь идет об одной ячейке, то ещё проще (как показано выше).

Вы напрасно не сформулировали всю задачу целиком. Мы бы предложили более эффективное решение (а не как сделать то, что, возможно, не нужно совсем). Подумайте над этим...
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

siti

#12
Ругается "Свойство или метод не найдены: RangeAddresses."

Sub Test_GetCellCollection2()
Dim oSheet As Object, oRanges As Object, oRange As Object, oCell As Object
Rem Dim Cells As New Collection  'CellCollection
Dim Cells As Object: Cells = New Collection

oSheet =  ThisComponent.CurrentController.ActiveSheet
oRange = oSheet.getCellRangeByName("D9:O12")
Cells = GetCellCollection(oRange.RangeAddresses())

For Each oCell In Cells
'   MsgBox oCell.String  'oCell.AbsoluteName
    If oCell.String Like "*Авито*" Then
        ThisComponent.CurrentController.select(oCell)  'contains "abc"
        Exit For
    End If
Next
End Sub


eeigor

Цитата: siti от 11 мая 2022, 12:33а что значит "в инвертированном диапазоне"?
Это ваша тема: выделить пустые ячейки, распространить выделение на строку и инвертировать выделение, исключив строки с пустыми ячейками. Тогда выделены будут оставшиеся строки рабочего диапазона.
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

siti

Ошибка:Необходимо задать размерность массива.
что-то не так делаю


Sub Test_GetCellCollection2()
Dim oSheet As Object, oRanges As Object, oRange As Object, oCell As Object
Rem Dim Cells As New Collection  'CellCollection
Dim Cells As Object: Cells = New Collection

oSheet =  ThisComponent.CurrentController.ActiveSheet
oRange = oSheet.getCellRangeByName("D9:O12")
Cells = GetCellCollection(oRange)

For Each oCell In Cells
'   MsgBox oCell.String  'oCell.AbsoluteName
    If oCell.String Like "*Авито*" Then
        ThisComponent.CurrentController.select(oCell)  'contains "abc"
        Exit For
    End If
Next
End Sub