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

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

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

Войти
Новости: Доступно и просто о работе в офисных пакетах
 
   Начало   Помощь Поиск Войти Регистрация    задать вопрос  
Страниц: 1   Вниз
  Печать  
Автор Тема: [Решено] Что есть "ActiveCell" в LO Calc?  (Прочитано 639 раз)
0 Пользователей и 1 Гость смотрят эту тему.
eeigor
Форумчанин
***
Online Online

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



« Стартовое сообщение: 13 Март 2021, 09:55 »

Вопрос носит частично теоретический характер, но имеет практическое значение в принципе.

Было бы неплохо дать возможность пользователю просто выделить весь столбец (несколько столбцов), ведь строк с данными ниже может быть очень много, а затем "отсечь" текущую область (current region) и уже потом выполнить какой-то макрос.
Вот эта задача, к примеру, тоже несёт в себе рассматриваемую проблему.

И это несложно сделать с использованием метода UNO, а уже потом выполнить что-то своё.
Код:
Sub UnoSelectData
    Dim document As Object
    Dim dispatcher As Object

    document = ThisComponent.CurrentController.Frame
    dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
    dispatcher.executeDispatch(document, ".uno:SelectData", "", 0, Array())
End Sub

Штатный метод по команде меню - Edit/Select/Select Data Area (Ctrl+*) - по-видимому, вызывает тот же "uno:SelectData" и работает следующим образом.
Кстати, у меня в Linux эта штука Ctrl+* не работает. Кто подскажет, почему?

При выборе одного или нескольких столбцов мышью "активной" становится первая ячейка видимой области листа (то есть совсем не в первой строке самого листа) и в том столбце, который был выделен последним. Курсор идёт как бы следом за указателем мыши в первой видимой строке. И вот от этой самой активной ячейки (на скриншоте - в черной рамке) Calc вычисляет текущую область и выделяет её, то есть расширяет в стороны от активной ячейки.

Чтобы реализовать подобное, нужно приблизиться к концепции "активной ячейки", которая здесь, как я это понимаю, не реализована или представлена в неявном виде (в отличие от Excel "ActiveCell").

Процедура ниже (GetCurrentRegion) приведена для примера, и она возвращает нам CurrentRegion, если была выбрана одна ячейка (возможно, что и несколько, но только не весь столбец). Если выбран один или несколько столбцов, то возвращается весь исходный диапазон. Это не то, что нам нужно. Однако метод "uno:SelectData" работает правильно, и он, как было сказано, связан с командой меню, описанной выше.
Код:
Function GetCurrentRegion(oRange As Object)
    Dim oCursor As Object

    oCursor = oRange.Spreadsheet.createCursorByRange(oRange)
    ' Расширяем курсор на содержащую ячейки область,
    ' в которую курсор в настоящее время указывает.
    ' "Region" - это диапазон ячеек, ограниченный пустыми ячейками.
   oCursor.collapseToCurrentRegion()
   GetCurrentRegion = oCursor  '.getCellRangeByName(oCursor.AbsoluteName)
End Function
Пусть не смущает термин "collapse" (означает "сжиматься, сокращаться"): речь идёт именно о расширении. Оставим эти "неясности" с выбором терминологии на совести разработчиков (ссылка).

Чтобы реализовать одноимённую с методом UNO процедуру SelectData, нужно получить ссылку на активную ячейку.
Псевдокод
Код:
Sub SelectData
    oActiveCell = GetActiveCell(oSelection)
    oRange = GetCurrentRegion(oActiveCell)
    ThisComponent.CurrentController.select(oRange)
End Sub

Решение этой "задачи" сопряжено с разбором структуры ThisComponent.CurrentController.ViewData
Кто может предложить реализацию процедуры GetActiveCell, возвращающую ссылку на активную ячейку (в рассматриваемом случае - выбираемую Calc'ом самостоятельно в видимой области листа).


UPD1:
Вот эта процедура решает поставленную задачу, но мне не всё здесь понятно. Начнём с того, что я не могу найти подробное описание структуры ViewData.
Кто может прокомментировать решение или предложить своё? И насколько я прав по поводу активной ячейки в Calc'е?
Код:
Sub Test_getActiveCell
    Dim oCell As Object

    oCell =  getActiveCell(ThisComponent.CurrentController)
    MsgBox "Active Cell: " & oCell.AbsoluteName
End Sub

Function getActiveCell(oView)
Dim as1(), lSheet&,lCol&,lRow$, sDum as String,bErr as Boolean
    as1()  = Split(oView.ViewData, ";")
    lSheet = CLng(as1(1))
    sDum = as1(lSheet +3)
    as1() = Split(sDum, "/")
    on error goto errSlash
        lCol = CLng(as1(0))
        lRow = CLng(as1(1))
    on error goto 0
    getActiveCell = oView.Model.getSheets.getByIndex(lSheet).getcellByPosition(lCol,lRow)
    Exit Function

errSlash:
    if NOT(bErr) then
        bErr = True
        as1() = Split(sDum, "+")
        resume
    endif
End Function

И в каком случае bErr будет равно True ?

UPD2:
Загружено 2 скриншота (состояние до вызова "Select Data Area" (выделен весь столбец, первая видимая строка - 40) и после выделения).


* Снимок экрана от 2021-03-13 09-10-09.png (4.45 Кб, 320x231 - просмотрено 5 раз.)

* Снимок экрана от 2021-03-13 09-10-31.png (4.39 Кб, 347x221 - просмотрено 5 раз.)
« Последнее редактирование: 13 Март 2021, 16:33 от eeigor » Записан

Ubuntu 18.04 LTS • LO 7.1.1.2 Community
economist
Форумчанин
***
Offline Offline

Сообщений: 1 461


« Ответ #1: 13 Март 2021, 11:04 »

Кстати, у меня в Linux эта штука Ctrl+* не работает. Кто подскажет, почему?

Работает в Ubuntu 20.04, 20.10, Raspbian OS. Ищите утилиту DE и удаляйте в ней глобальные хоткеи, которыми кишит каждый пингвиновый дистр.
Записан

Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...
eeigor
Форумчанин
***
Online Online

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



« Ответ #2: 13 Март 2021, 12:19 »

ThisComponent.CurrentController.ViewData = "10026;308351;100;0;300192;21972;309924;0;1"
Скриншот 1 со свойствами (возможно, это не то, что нужно).

Код от Питоньяка, который частенько выдает ошибку (скриншоты 2 и 3). Свойства разные. Пока не ясно...
Разобрался: код Питьньяка (ниже) работает для Writer и скриншот 2 с его свойствами, для Calc набор свойств существенно шире (скриншот 4) и код Питьньяка выдает ошибку.
Но, похоже, нас интересует исходная строка: "10026;308351;100;0;300192;21972;309924;0;1"

Код:
Sub GetViewData
    Dim vViewData 'View data object
    Dim i%  'Index variable
    Dim j%  'Index variable
    Dim s$  'General string
    Dim vtemp  'View data for one object

    vViewData = ThisComponent.getViewData()
    REM For each view of the data
    For i = 0 To vViewData.getCount() - 1
        vtemp = vViewData.getByIndex(i)
        For j = 0 To UBound(vtemp)
            s = s & vtemp(j).Name & " = " & CStr(vtemp(j).Value) & CHR$(10)
        Next
        MsgBox s, 0, "View Data"
    Next
End Sub
Скриншот 2 под коду от Питоньяка.


* Снимок экрана от 2021-03-13 12-18-39.png (104.63 Кб, 888x688 - просмотрено 6 раз.)

* Снимок экрана от 2021-03-13 12-21-04.png (28.88 Кб, 321x398 - просмотрено 7 раз.)

* Снимок экрана от 2021-03-13 12-32-57.png (36.95 Кб, 703x214 - просмотрено 6 раз.)

* Снимок экрана от 2021-03-13 12-38-23.png (239.31 Кб, 1000x859 - просмотрено 7 раз.)
« Последнее редактирование: 13 Март 2021, 12:48 от eeigor » Записан

Ubuntu 18.04 LTS • LO 7.1.1.2 Community
eeigor
Форумчанин
***
Online Online

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



« Ответ #3: 13 Март 2021, 12:58 »

.ViewData = "10026;308351;100;0;300192;21972;309924;0;1"
Где это найти?
Но в функции, которую я прошу пояснить (решение в стартовом сообщении), мы работаем с такой строкой:
100/60/0;0;tw:1832;1/39/0/0/0/0/2/0/0/0/39
где 0 - это индекс листа;
1 - это индекс столбца текущей ячейки выбранного листа;
39 - это индекс строки текущей ячейки выбранного листа.
В этом примере документ содержит только один лист с выбранной ячейкой ($Sheet1.$B$40).

Пример с выбранной ячейкой на втором листе ($Sheet2.$C$4):
100/60/0;1;tw:1832;1/47/0/0/0/0/2/0/0/0/39;2/3/0/0/0/0/2/0/0/0/0

Что означают другие значения, неизвестно...
Просьба пояснить работающее решение, ибо мой вопрос связан с отсутствием human readable документации.

as1() = Split(sDum, "/"): on error goto errSlash
Когда может произойти ошибка?
И что может означать "+" в строке с параметрами? Ответ: означает "сделано криво".
as1() = Split(sDum, "+")

UPD:
В общем, в чём-то разобрался сам, в чём-то помогли "соседи"...
Кому интересно, обратите внимание на разделитель параметров второго листа:
100/60/0;1;tw:1832;1/39/0/0/0/0/2/0/0/0/39;0+8192+0+0+0+0+2+0+0+0+8173
« Последнее редактирование: 13 Март 2021, 15:17 от eeigor » Записан

Ubuntu 18.04 LTS • LO 7.1.1.2 Community
sokol92
Форумчанин
***
Offline Offline

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


WWW
« Ответ #4: 14 Март 2021, 18:05 »

Добрый день! Структура строки ViewData контроллера документа Calc описана здесь (строки 3158-3164). В чаcтности указано:

when rows bigger than 8192, "+" instead of "/"
Записан

Владимир.
eeigor
Форумчанин
***
Online Online

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



« Ответ #5: 14 Март 2021, 18:13 »

Спасибо. Теперь, в принципе, всё ясно. И с плюсом разобрались. Но и я уже склонен был считать это не багом, а специфической особенностью, которой 15 больше лет. Это как-то связано исторически с увеличением количества строк на листе. Теперь это неважно. Процедура, которую я привел выше, отрабатывает эту "деталь" и используется очень давно.

Приведу строки, на которые вы сослались, для удобства другим (nTab - зд. индекс листа, "tab" значит "ярлычок"):
Код:
3158     // nZoom (until 364v) or nZoom/nPageZoom/bPageMode (from 364w)
3159     // nTab
3160     // Tab control width
3161     // per sheet:
3162     // CursorX/CursorY/HSplitMode/VSplitMode/HSplitPos/VSplitPos/SplitActive/
3163     // PosX[left]/PosX[right]/PosY[top]/PosY[bottom]

3164     // when rows bigger than 8192, "+" instead of "/"

Нас, соответственно, интересовали параметры: nTab активного листа и координаты активной (в фокусе) ячейки: CursorX, CursorY

Примечание. Я уже высказывался о необходимости "сбора" полезного кода. Вот эта функция (getActiveCell) - первый кандидат, а содержание этого поста - необходимый комментарий к ней.
« Последнее редактирование: 14 Март 2021, 18:36 от eeigor » Записан

Ubuntu 18.04 LTS • LO 7.1.1.2 Community
sokol92
Форумчанин
***
Offline Offline

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


WWW
« Ответ #6: 14 Март 2021, 20:46 »

Вот эта функция (getActiveCell) - первый кандидат
У указанной функции достаточно бедный интерфейс. Следующая функция выдает текущую (активную) ячейку любого листа из любого загруженного документа Calc. Без указания параметров она работает так же, как указанная выше.

Код:
Option Explicit
Option Compatible
' Возвращает активную (текущую ячейкy) документа (или листа).
' Параметры:
' oDoc  документ Calc. Если параметр опущен, то выбирается ThisComponent.
' sheet лист документа. Может быть объектом (Spreadsheet), числом (номер листа) или строкой (имя листа).
'       Если не задан, или равен пустой строке, то выбирается активный (текущий) лист документа.
'
' В случае ошибки возвращает Nothing.
Function Doc_ActiveCell(Optional ByVal oDoc As Variant, Optional ByVal sheet As Variant) As Object
  Dim arr, arr2, nSheet As Long, s As String, oSheet As Object
  On Local Error GoTo ErrLabel
  If IsMissing(oDoc) Then oDoc=ThisComponent
  arr=Split(oDoc.CurrentController.ViewData, ";")
 
  nSheet=-1
  If IsMissing(sheet) Then
    nSheet=arr(1)
  ElseIf IsObject(sheet) Then
    oSheet=sheet
    nSheet=oSheet.RangeAddress.Sheet
  ElseIf VarType(sheet)=V_STRING Then
    If sheet="" Then 
      nSheet=arr(1)
    Else
      nSheet=oDoc.Sheets.getByName(sheet).RangeAddress.Sheet
    End If
  ElseIf Vartype(sheet)=V_EMPTY Or Vartype(sheet)=V_NULL Then
     nSheet=arr(1)
  Else  ' числовой тип   
    nSheet=sheet
  End If
 
  If nsheet>=0 Then
    s=arr(3+nsheet)           
    arr2=Split(s, IIf(Instr(1, s, "+")>0, "+", "/"))
    Doc_ActiveCell=oDoc.Sheets(nSheet).getCellByPosition(CLng(arr2(0)), CLng(arr2(1)))
  End If 
ErrLabel:
End Function
« Последнее редактирование: 14 Март 2021, 21:28 от sokol92 » Записан

Владимир.
Страниц: 1   Вверх
  Печать  
 
Перейти в:  

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