Заблокировать работу с документом на время работы макроса

Автор ForumOOo (бот), 30 ноября 2016, 20:33

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

Alex16

#30
Цитата: mikekaganski от  6 декабря 2016, 12:52и вызвать calculate() для них
Т.е. метод calculate вызвать у объекта Range? Например shtReport.getCellRangeByName(Addrs).Calculate
где Addrs - ячейки с формулами?


ЗЫЖ Ошибка времени выполнения BASIC.
Свойство или метод не найдены: Calculate

JohnSUN

И кстати об экспериментах... А точно пересчет блокируется именно из-за Begin/EndUpdateRep? Так, может, отказаться от него, как от не оправдавшего доверия?
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

Alex16

Цитата: JohnSUN от  6 декабря 2016, 13:40А точно пересчет блокируется именно из-за Begin/EndUpdateRep? Так, может, отказаться от него, как от не оправдавшего доверия?
Я догадываюсь, что у вас тут есть другие решения, например как ты предлагал со стилями, но я пока хочу ограничится кодом. А без Begin/EndUpdateRep пока сильно тормозит.

JohnSUN

Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

JohnSUN

Если честно, то когда мы разбирали прошлый пример "тормознутости", я заподозрил неладное.
Насколько я понял, речь шла об итоговом листе с данными всех-всех пользователей. То есть, каждый из них, пользуясь большой и красивой формой ввода, подсчитывает сколько было выполнено "контактов с потребителем услуг" - по каждому типу (колонки) и по каждой услуге (строки). Теперь (или тогда?) ты бодаешься с листом, где эти данные собраны без лишних украшательств, просто по десятку колонок для данных каждого из юзеров и через обычный SUM итоговый подсчет по всем.
"Меня терзают смутные сомнения..."
А не растянуть ли всю эту беду по вертикали в "плоскую" таблицу с колонками
№ пользователя - Строка - Колонка - Количество
Не страшно, что она получится длинной, листать её не придётся, это только сырые данные для программы.
А вот собственно аккуратную табличку с итогами может сделать и Сводная таблица....
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

rami

Цитата: Alex16 от  6 декабря 2016, 13:43Я догадываюсь, что у вас тут есть другие решения, например как ты предлагал со стилями, но я пока хочу ограничится кодом.
Давно хотел спросить: обязательно вставлять в ячейки(диапазоны) формулы? или посчитать всё и вставить массив значений?

JohnSUN

Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

Alex16

Цитата: JohnSUN от  6 декабря 2016, 13:52Гм... А кто тормозит на этот раз?
Sub SelectListBox
Dim I as Integer, sViewData As String', oController as Object
'BeginUpdateRep
I = GetCtrl("SpisSotrud").SelectedItems(0)
if I < 0 then
 MsgBox "Ошибка! Не выбран отчет"
 EndUpdateRep
 Exit Sub
End If
LoadRep(I)
'EndUpdateRep
End Sub

Sub LoadData(ColInd%)
Dim N%, oCellRangeRep as Object, oCellRangeData as Object
StrColumnsArr = Split(StrColumns, ",")
For N = LBound(StrColumnsArr) to UBound(StrColumnsArr)
 Addrs = StrColumnsArr(N) & StartColRow + 1 & ":" & StrColumnsArr(N) & EndColRow + 1
 oCellRangeData = shtData.getCellRangeByPosition(ColInd + N, 0,  ColInd + N,  EndColRow - StartColRow)
 oCellRangeRep  = shtReport.getCellRangeByName(Addrs)
 oCellRangeRep.setDataArray(oCellRangeData.getDataArray())
Next N
End Sub

Sub LoadRep(N as Integer)
if N = LastUserID then Exit Sub
if LastUserID = 0 then ColoredRep(False)
LastUserID = N
if N = 0 then
 LoadData((GetCtrl("SpisSotrud").ItemCount - 1) * ColumnCount)
 ColoredRep(True)
 GetCtrl("btnClear").Label = "Очистить всё"
 Exit Sub
End If  
LoadData((N - 1) * ColumnCount)
GetCtrl("btnClear").Label = "Очистить!"
End Sub

Sub ColoredRep(CommonRep as Boolean)
Dim N%, Range as String, CellProtection
StrColumnsArr = Split(StrColumns, ",")
For N = LBound(StrColumnsArr) to UBound(StrColumnsArr)
 Range = StrColumnsArr(N) & StartColRow + 1 & ":" & StrColumnsArr(N) & EndColRow + 1
 CellProtection = shtReport.getCellRangeByName(Range).CellProtection
 if CommonRep then
shtReport.getCellRangeByName(Range).CellBackColor = 14540253
CellProtection.IsLocked = True
 else
   shtReport.getCellRangeByName(Range).CellBackColor = 15202046
   CellProtection.IsLocked = False
 endif
 shtReport.getCellRangeByName(Range).CellProtection = CellProtection
Next N
End Sub


Вот как-то так у меня сейчас. Понимаю, что особо разбираться тут никто не будет, но тормоза идут как в ColoredRep так и в LoadData
Но если с Begin/EndUpdateRep, то вроде сносно, а с пересчетом решил так:
BeginUpdateRep остался без изменений
Sub BeginUpdateRep
ThisReport.isUndoEnabled=False
if shtReport.isProtected() Then shtReport.UnProtect(Pass)
ThisReport.LockControllers()
ThisReport.AddActionLock()
End Sub

А EndUpdateRep
Sub EndUpdateRep
Dim I%
ThisReport.RemoveActionLock()
ThisReport.UnlockControllers()
with ThisReport.GetCurrentController
 .RestoreViewData(.GetViewData())
end with
shtReport.Protect(Pass)
I = GetCtrl("SpisSotrud").SelectedItems(0)
ThisReport.CalculateAll
GetCtrl("SpisSotrud").InsertItemText(0,"<(Общий)>")
GetCtrl("SpisSotrud").SelectedItems = Array(I)
ThisReport.isUndoEnabled=True
End Sub

Alex16

Цитата: rami от  6 декабря 2016, 14:09Давно хотел спросить: обязательно вставлять в ячейки(диапазоны) формулы? или посчитать всё и вставить массив значений?
Изначально тоже так думал, но этож надо каждый раз пересчитывать эти значения. Операторы в течении конца рабочего времени, а то и всего раб. дня вносят изменения каждый в свой отчет.

Alex16

Цитата: JohnSUN от  6 декабря 2016, 14:03Если честно,
Если честно, у меня уже башка скоро взорвется, ели ели вроде осилил пока этот отчет. А тут снова все переделывать - как то не утешает перспектива :(
Огромнейшее в любом случае СПАСИБО за помощь и желание помогать. Но пока остановлюсь на достигнутом. Завтра отдам на бета тестирование, а там война план покажет.

JohnSUN

А! Если они результат еще не видели, то на всякий случай вставь внутри циклов Wait(100).
Тогда по результатам тестирования единственным замечанием будет "Сильно тормозит". Ты отвечаешь "Понятно, исправим" и сокращаешь паузу на треть...
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

Alex16

Цитата: JohnSUN от  6 декабря 2016, 14:26А! Если они результат еще не видели, то на всякий случай вставь внутри циклов Wait(100).
Тогда по результатам тестирования единственным замечанием будет "Сильно тормозит". Ты отвечаешь "Понятно, исправим" и сокращаешь паузу на треть...
;D :beer:

mikekaganski

Цитата: Alex16 от  6 декабря 2016, 14:41
Не все формулы обновляются. Причем по F9 тоже самое, но если выделить ячейку с "кривым результатом" формулы и нажать F9 то ячейка пересчитывается как надо.

Код, выполняющий calculate(), здесь: http://opengrok.libreoffice.org/xref/core/sc/source/ui/docshell/docsh4.cxx#1206 (метод ScDocShell::DoRecalc для calculate, метод ScDocShell::DoHardRecalc для calculateAll).

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

Можно пойти разными путями. Во-первых, можно попробовать перед изменением формул ячеек устанавливать текст этих ячеек в "" - может быть, это сделает их "изменёнными". Можно создать курсор, пробежать по нужным ячейкам и в каждой позиции вызвать calculate для отчёта. А можно настроить среду разработки и попробовать с помощью отладки понять, почему же ячейки сами не "пачкаются" в процессе выполнения скрипта и какая из операций блокирования этому виной, может быть, это баг? ;)
С уважением,
Михаил Каганский

Alex16

Цитата: mikekaganski от  6 декабря 2016, 15:25почему же ячейки сами не "пачкаются" в процессе выполнения скрипта и какая из операций блокирования этому виной, может быть, это баг?
Может и баг. Я сделал тестовый файл, но в нем этот баг не проявился. Но и в тестовом файле ячейки с данными по другому заполняются.
Возможно это связано с oCellRangeRep.setDataArray(oCellRangeData.getDataArray()) - там где "баг" проявился, а вoт код тестового

Sub BeginUpdateRep
ThisComponent.isUndoEnabled=False
if ThisComponent.Sheets(0).isProtected() Then ThisComponent.Sheets(0).unprotect(1)
ThisComponent.lockControllers()
ThisComponent.AddActionLock()

End Sub

Sub EndUpdateRep
ThisComponent.RemoveActionLock()
ThisComponent.UnlockControllers()
ThisComponent.Sheets(0).protect(1)
ThisComponent.isUndoEnabled=True
End Sub

Sub Main
BeginUpdateRep
LoadData
EndUpdateRep
End Sub

Sub LoadData
For N = 0 to 2
  X = INT(RND * 100) + 10
  Y = INT(RND * 100) + 10
  Z = INT(RND * 100) + 10
  ThisComponent.Sheets(0).GetCellByPosition(1, 5 + N).Value = X
  ThisComponent.Sheets(0).GetCellByPosition(2, 5 + N).Value = Y
  ThisComponent.Sheets(0).GetCellByPosition(3, 5 + N).Value = Z
  ThisComponent.Sheets(0).GetCellByPosition(6, 5 + N).Value = X + Y + Z
Next N
End Sub

Alex16

Цитата: mikekaganski от  6 декабря 2016, 15:25Код, выполняющий calculate(), здесь: http://opengrok.libreoffice.org/xref/core/sc/source/ui/docshell/docsh4.cxx#1206 (метод ScDocShell::DoRecalc для calculate, метод ScDocShell::DoHardRecalc для calculateAll).
Это какой-то си наверное. Я с ним знаком немного, точнее просто си, а тут наверное какойнить ++ или еще какой... Но не в этом суть. В любом случае мне тяжело разобраться в том коде.
Цитата: mikekaganski от  6 декабря 2016, 15:25Можно создать курсор, пробежать по нужным ячейкам и в каждой позиции вызвать calculate для отчёта.
Мне кажется это добавит тормозов еще больше