Calc: StatusBar

Автор eeigor, 20 июня 2020, 20:58

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

eeigor

Знатоки, подскажите, как отобразить/скрыть строку состояния в Calc программно.

Sub DisplayStatusBar(state As Boolean)
Dim document As Object
Dim dispatcher As Object

document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

Dim args1(0) As New com.sun.star.beans.PropertyValue
args1(0).Name = "StatusBarVisible"
args1(0).Value = state

dispatcher.executeDispatch(document, ".uno:StatusBarVisible", "", 0, args1())
End Sub


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

В Excel есть два свойства:
Application.DisplayStatusBar [Boolean]
Application.StatusBar [Variant]
Ubuntu 18.04 LTS • LibreOffice 7.3.5.2 Community

sokol92

#1
Описано здесь.

Пример использования:

' Сопоставляет время вызова "родной" функции Basic и функции, вызванной через FunctionAccess
Sub TestFunctionAccessSpeed
 Dim n as Long  ' число вызовов функции  
 Dim i as Long  ' счетчик вызовов
 Dim oIndicator ' индикатор  статуса
 Dim oFA        ' FunctionAccess
 Dim j as Long, s as String, t as Long, d as Double, fm as String, title as String

 n=500000
 fm="#,##0"
 oFA = createUnoService( "com.sun.star.sheet.FunctionAccess" )
 oIndicator=ThisComponent.getCurrentController().frame.createStatusIndicator()  ' создаем индикатор статуса
 
 oIndicator.start("Сравнение скорости вызова функций", n)    ' стартуем индикатор статуса
 s="Число вызовов функций: " & format(n, fm)
 
 For j=1 To 2
   title=IIf(j=1, "Вызов Basic SIN", "Вызов FunctionAccess SIN")
   oIndicator.setText(title)
   oIndicator.setValue(0)
   t=GetSystemTicks()
   For i=1 to n
     If i mod 50000=0 Then
       oIndicator.setvalue(i)
     End If    
     If j=1 Then
       d=sin(i)
     Else
       d=oFA.callFunction("SIN", Array(CDbl(i)))  
     End If  
   Next i  
   s=s & Chr(10) & title & ". Время: " & Format(GetSystemTicks-t, fm)
 Next j  
 
 oIndicator.end()   ' закрываем индикатор статуса
 Msgbox s
End Sub

Владимир.

sokol92

Дополнил свой ответ.
Владимир.

eeigor

#3
Ubuntu Linux 18.04 LTS LibreOffice Calc 6.4.4.2.

sokol92, очень интересное решение. Правда, я спрашивал про StatusBar, но хотел использовать эту панель именно с этой целью: вывести импровизированную строку состояния из символов псевдографики. Но вы угадали мою конечную цель: построить ProgressBar.
Задал значения переменных: n = 5000; m = 500.

Как удалить индикатор?
Скриншот с неудалённым индикатором.

Другой вопрос, чуть не по теме.
Как обновить экран? В Excel для этих целей использовал оператор DoEvents в цикле. А так, ScreenUpdating [Boolean].
Здесь что-то подобное ScreenUpdating False|True:
ThisComponent.lockControllers
ThisComponent.unlockControllers
Ubuntu 18.04 LTS • LibreOffice 7.3.5.2 Community

sokol92

"Индикатор" и есть аналог StatusBar, но с расширенными возможностями. Он состоит из двух частей, которыми можно управлять независимо: текста и "прогрессбара".

Если макрос завершается аварийно, то индикатор остается (я не знаю пока, как с этим воевать). При нормальном завершении индикатор удаляется после того, как будет выполнен метод end  и обнулен счетчик ссылок на индикатор (как и другие объекты).

С обновлением экрана, надеюсь, помогут более опытные коллеги.
Владимир.

eeigor

#5
Я, в своё время работал с Microsoft Access, и там сделано подобным образом.
https://docs.microsoft.com/en-us/office/vba/access/concepts/miscellaneous/use-the-status-bar-progress-meter
acSysCmdRemoveMeter  Remove progress meter

Но всё равно это находка. Спасибо

В отношении метода end() в описании сказано: The instance must be gone by using ref count or disposing. (Экземпляр должен быть удален с помощью...).
Почему "должен быть"? Кто это должен сделать и как?
Цитата: sokol92 от 21 июня 2020, 20:45При нормальном завершении индикатор удаляется после того, как будет выполнен метод end
Сомневаюсь, однако...

UPD
Ну, вот, и ответ. Вы использовали все методы, кроме одного:
oIndicator.reset()
Он и доделает остальное.
reset()  Clear progress value and description
Ubuntu 18.04 LTS • LibreOffice 7.3.5.2 Community

rami

Цитата: sokol92 от 21 июня 2020, 20:45Если макрос завершается аварийно, то индикатор остается (я не знаю пока, как с этим воевать).
Просто нужно выполнить код:
Sub Main
ThisComponent.CurrentController.StatusIndicator.end()
End Sub



Цитата: eeigor от 21 июня 2020, 20:54Ну, вот, и ответ. Вы использовали все методы, кроме одного:
Код:
oIndicator.reset()
Он и доделает остальное.
reset()  Clear progress value and description
reset() только сбрасывает значения, но не завершает.

eeigor

Цитата: sokol92 от 21 июня 2020, 20:45Он состоит из двух частей, которыми можно управлять независимо: текста и "прогрессбара"
На этом форуме, вроде, этой информации нет. Я не нашёл. Есть реализацию через форму (https://forumooo.ru/index.php/topic,3774.0.html). А это очень полезный инструмент.
Ubuntu 18.04 LTS • LibreOffice 7.3.5.2 Community

eeigor

#8
Цитата: rami от 21 июня 2020, 21:19reset() только сбрасывает значения, но не завершает
Да нет же.
Вот так:
 oIndicator.end()    ' закрываем индикатор статуса
oIndicator.reset()  ' clear all

После этого в строке состояния появляется системное сообщение: Лист 1 из 1
Что и требовалось.
Ubuntu 18.04 LTS • LibreOffice 7.3.5.2 Community

rami

Я взял макрос из Ответ #1, закомментировал строку кода oIndicator.end()   ' закрываем индикатор статуса, статус индикатор остался незавершённый, затем выполнил предложенный мною макрос и статус индикатор убрался полностью из строки состояния.

eeigor

#10
Оформлять в виде отдельной процедуры не обязательно, можно прямо здесь:
  oIndicator = ThisComponent.getCurrentController().frame.createStatusIndicator()
' oIndicator.end()  ' закрываем индикатор статуса
 ThisComponent.CurrentController.StatusIndicator.end()


Работает так же, как и с oIndicator.reset()
Вообще, не очевидная модель объектов:
ThisComponent.CurrentController().frame.createStatusIndicator()
ThisComponent.CurrentController.StatusIndicator.end()

Как будто:
ThisComponent.CurrentController().frame.createStatusIndicator() Is Not ThisComponent.CurrentController.StatusIndicator

Проверил с помощью Xray: в обоих случаях это объект com.sun.star.task.XStatusIndicator
А работает по-разному.

Вот так нормально и понятно (не люблю я эти геттеры и сеттеры):
' oIndicator = ThisComponent.getCurrentController().frame.createStatusIndicator()  ' создаем индикатор статуса
 oIndicator = ThisComponent.CurrentController().StatusIndicator()


Работает. Зачем нужно было обращение к frame ?
Ubuntu 18.04 LTS • LibreOffice 7.3.5.2 Community

sokol92

Rami, большое спасибо!
Владимир.

sokol92

В версии LO 6.4 появился Infobar, который, в частности, также можно использовать для целей, указанных в данной теме. Пример из #1 расширен:

' Сопоставляет время вызова "родной" функции Basic и функции, вызванной через FunctionAccess
Sub TestFunctionAccessSpeed
  Dim n as Long   ' число вызовов функции   
  Dim i as Long   ' счетчик вызовов
  Dim oController ' контроллер документа
  Dim oIndicator  ' индикатор  статуса
  Dim oFA         ' FunctionAccess
  Dim j as Long, s as String, t as Long, d as Double, fm as String, title as String, bRed as Boolean

  n=200000
  fm="#,##0"
  oFA = createUnoService( "com.sun.star.sheet.FunctionAccess" )
  oController=ThisComponent.getCurrentController()
 
  oIndicator=oController.StatusIndicator()  ' создаем индикатор статуса
  oController.appendInfobar("MyInfobar", "Выполняется макрос", "Дождитесь завершения работы макроса, иначе можно получить непредсказуемый результат", 3, Array(), True)
  oIndicator.start("Сравнение скорости вызова функций", n)    ' стартуем индикатор статуса
 
  s="Число вызовов функций: " & format(n, fm)
 
  bRed=True
  For j=1 To 2
    title=IIf(j=1, "Вызов Basic SIN", "Вызов FunctionAccess SIN")
    oIndicator.setText(title)
    oIndicator.setValue(0)
    t=GetSystemTicks()
    For i=1 to n
      If i mod 20000=0 Then
        oIndicator.setvalue(i)
        If bRed And j=2 And i/n>=0.7 then
          oController.updateInfobar("MyInfobar", "Макрос скоро завершится", "Дождитесь завершения работы макроса, иначе можно получить непредсказуемый результат", 2)
          bRed=False
        End If 
      End If     
      If j=1 Then
        d=sin(i)
      Else
        d=oFA.callFunction("SIN", Array(CDbl(i))) 
      End If 
    Next i 
    s=s & Chr(10) & title & ". Время: " & Format(GetSystemTicks-t, fm)
  Next J   
 
  oIndicator.end()   ' закрывам индикатор статуса
  oController.removeInfobar("MyInfobar")  ' закрываем инфобар
  Msgbox s
End Sub



Владимир.

eeigor

Хороший пример. Берём на вооружение.
Ubuntu 18.04 LTS • LibreOffice 7.3.5.2 Community

siti

Цитата: sokol92 от 24 июня 2020, 16:45В версии LO 6.4 появился Infobar, который, в частности, также можно использовать для целей, указанных в данной теме. Пример из #1 расширен:
Пример работает, но подскажите для не особо грамотных... у меня есть процедура, например main.
Как мне интегрировать в нее прогрессбар? Что тут нужно выкинуть и куда вставить свой код?