[Решено] Программное изменение регистра

Автор bsi, 29 января 2017, 12:06

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

bsi

Привет форумчане. Прошу досказать как переделать код из VBA для LO, если конечно у вас есть свободное время.
Sub Proper_Case()
  'Первые буквы в верхний регистр
  For Each x In Range("A1:A5")
     x.Value = Application.Proper(x.Value)
  Next
End Sub
и Sub Uppercase()
  'Все в верхний регистр
  For Each x In Range("B1:B5")
     x.Value = UCase(x.Value)
  Next
End Sub
.
Всем спасибо.

JohnSUN

Ну, в этом бэйсике нужно будет написать немного больше:

Sub ChangeCase(Optional typeCase As String, Optional sRange As String, Optional sheetName As String)
' Изменить регистр в указанном диапазоне
' typeCase - название применяемой функции Calc: "LOWER","UPPER","PROPER"
' (Если очень уж захочется, то можно и "TRIM" или "CLEAN" или любую другую функцию,
' в которой используется только один параметр).  По умолчанию применяется функция "Первые буквы - Заглавные"
' sRange - адрес диапазона для обработки. Если не указан - все ячейки на листе
' sheetName - имя листа для обработки. Если не указано - текущий, активный лист
Dim oFuncAcc As Variant
Dim oSheet As Variant
Dim oRange As Variant
Dim oDataArr As Variant
Dim oData As Variant
Dim i As Long, j As Long
On Error Resume Next ' Ошибки в параметрах могут вызвать ошибки времени выполнения
If IsMissing(typeCase) Then typeCase = "Proper"

If IsMissing(sheetName) Then ' Если имя листа не указано, использовать текущий лист
    oSheet = ThisComponent.getCurrentController().getActiveSheet()
Else ' В противном случае попытаться получить лист по имени
oSheet = ThisComponent.getSheets().getByName(sheetName)
EndIf
' Если листа с указанным именем нет или макрос запущен вообще не из Calc - нечего здесь больше делать
If IsEmpty(oSheet) Or IsNull(oSheet) Then Exit Sub

' Пытаемся получить указанный диапазон ячеек:
If IsMissing(sRange) Then ' Диапазон ячеек указан? Нет.
    oRange = oSheet.createCursor()
    oRange.gotoEndOfUsedArea(True)
    Else ' Какая-то строка есть, попытаемся получить указанные ячейки
    oRange = oSheet.getCellRangeByName(sRange)
    EndIf
If IsEmpty(oRange) Or IsNull(oRange) Then Exit Sub
' Данные из всех этих ячеек считываем во временный массив: 
  oDataArr = oRange.getDataArray()
' Вот так в OOo/AOO/LiO обращаются к встроенным функциям:
oFuncAcc = CreateUNOService("com.sun.star.sheet.FunctionAccess")

' Перебираем все ячейки:
For i = LBound(oDataArr) To UBound(oDataArr) ' Все данные по строкам
oData = oDataArr(i) ' Одна строка
For j = LBound(oData) To UBound(oData) ' По каждой ячейке строки
' If Trim(oData(j)) <> "" Then ' Вызов
oData(j) = oFuncAcc.callFunction(typeCase, Array(oData(j)))
' В случае ошибки при обработке любой из ячеек - исходные данные менять не станем
If Err <> 0 Then Exit Sub
Next j
oDataArr(i) = oData ' Возвращаем обработанную строку обратно в общий массив
Next i
    oRange.setDataArray(oDataArr) ' Записываем обработанные значения на то же самое место
End Sub


И теперь - твои две процедуры будут выглядеть так
Sub Proper_Case()
   'Первые буквы в верхний регистр
    ChangeCase("Proper", "A1:A5")
End Sub

Sub Uppercase()
   'Все в верхний регистр
   ChangeCase("UPPER", "B1:B5")
End Sub
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

bsi

Спасибо вам, как всегда быстрый ответ. Надо разобраться что к чему, а то я только-только начинаю врубаться в LO.

bsi

Прошу пояснить что я делаю не так. Поместил Ваш код в модуль. На событие листа "Содержимое изменено" ставлю макрос ChangeCase, выдает ошибку " Неверное значение свойства". Файл во вложении. LO 5.2.3.3.

JohnSUN

У макросов, которые должны обрабатывать события, обычно есть один обязательный параметр - его принято обозначать oEvent As Variant. Через него офис передает в макрос сведения о самом событии. Для события листа "Содержимое изменено" в этом oEvent будет изменившийся диапазон ячеек.
А у ChangeCase три строковых параметра, и ни один из них не подходит под ожидаемый тип Variant.

Просто в твоем первом примере были жестко заданы диапазоны обрабатываемых ячеек - "A1:A5", "B1:B5". Это предполагало, что макрос должен вызываться для всего диапазона, то ли кнопкой, то ли горячей клавишей, то ли через Макрос-Выполнить - вот я и предложил вариант "вообще", который обрабатывал бы заранее известный диапазон ячеек.
Если же ты хочешь обрабатывать ячейки по событию, когда заранее неизвестно для какой из ячеек (или диапазона ячеек) макрос был вызван, то код будет выглядеть немного иначе.
' Обработать событие листа "Содержимое изменено"
Sub onChange(oEvent As Variant)
Dim oFuncAcc As Variant
Dim i&, j&
oFuncAcc = CreateUNOService("com.sun.star.sheet.FunctionAccess")
If oEvent.ImplementationName = "ScCellObj" Then ' Событие вызвано для одной ячейки
' Адрес этой ячейки oEvent.CellAddress. В какой колонке находится изменившаяся ячейка?
Select Case oEvent.CellAddress.Column
Case 0 ' Колонка A - значение меняем с помощью функции Proper
oEvent.setString(oFuncAcc.callFunction("Proper", Array(oEvent.getString())))
Case 1 ' Колонка B - значение меняем с помощью функции Upper
oEvent.setString(oFuncAcc.callFunction("Upper", Array(oEvent.getString())))
' ... здесь могут быть другие Case для других колонок
Case Else
' Что-то сделать для ячеек из всех остальных колонок. Мы ничего делать не будем
    End Select
Else ' Не одна-единственная ячейка? Значит, целый диапазон. Обработаем каждую ячейку диапазона отдельно
For i = 0 To oEvent.getColumns().getCount()-1
For j = 0 To oEvent.getRows().getCount()-1
onChange(oEvent.getCellByPosition(i, j)) ' То есть вызываем ту же самую обработку события,
' но не для всего диапазона, а для каждой из его ячеек
' Эту часть можно было бы улучшить, если предварительно выбрать из oEvent ячейки,
' которые действительно нужно обрабатывать, чтобы не вызывать процедуру вхолостую
Next j
Next i
EndIf
End Sub
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

bsi

Мир не без добрых людей !  :beer: Огромное спасибо. Все работает.

bsi

#6
Еще раз спасибо за участие в моей проблеме, но и этот вариант надо править. Необходимо чтобы макрос срабатывал на событие листа, но в определенном диапазоне ячеек. В конкретном случае в В6:В27 и F6:F27. Файл во вложении.

rami

Цитата: bsi от 30 января 2017, 08:38Необходимо чтобы макрос срабатывал на событие листа, но в определенном диапазоне ячеек. В конкретном случае в В6:В27 и F6:F27.
JohnSUN дал вам развёрнутый ответ для разных вариантов, но под конкретные условия лучше отсечь не используемые варианты. Как вам такой вариант:
Sub onChange(oEvent As Variant)
Dim oFuncAcc As Variant
oFuncAcc=CreateUNOService("com.sun.star.sheet.FunctionAccess")
If oEvent.ImplementationName = "ScCellObj" Then ' Событие вызвано для одной ячейки
'если номер строки ячейки меньше 5 или больше 26 выходим из процедуры
If oEvent.CellAddress.Row<5 Or oEvent.CellAddress.Row>26 Then Exit Sub
' Адрес этой ячейки oEvent.CellAddress. В какой колонке находится изменившаяся ячейка?
Select Case oEvent.CellAddress.Column
Case 1 ' Колонка B - значение меняем с помощью функции Upper
oEvent.setString(oFuncAcc.callFunction("Upper", Array(oEvent.getString())))
Case 5 ' Колонка F - значение меняем с помощью функции Proper
oEvent.setString(oFuncAcc.callFunction("Proper", Array(oEvent.getString())))
' ... здесь могут быть другие Case для других колонок
   End Select
EndIf
End Sub

bsi

ЦитироватьКак вам такой вариант:
.
Отлично !  :D