Страницы: 1
RSS
Перенос текста на следующую строку при заполнении столбца по ширине, оптимизация макроса
 
Доброго утра, уважаемые форумчане!  У меня есть тема (вот тут) - по названию практически такая же (для тех, кто ищет). Там всё глухо и, если я буду там писать просто так, то, по сути, это UP и это плохо...
Здесь же прошу вашей помощи по оптимизации самого подходящего (для моих задач) макроса - WrapDownWithLeftColomn: он сцепляет выделенный диапазон (который нужно разнести по строкам) со столбцом слева, переносит целевой и расцепляет обратно - в итоге построчная связь не разрушается и остальные поля можно подтянуть через ВПР по СТОЛБЦУ СЛЕВА (с цифрами). Долго, нудно, но работает...
В примере 20 позиций (секунд 30 обрабатывает), в оригинале около 300 (и это далеко не предел) - excel виснет безбожно((((

P.S.: замечено, что время работы меняется НЕ прямо пропорционально объёму, а чуть ли не в геометрической прогрессии, то есть увеличение объёма в 4 раза увеличивает время работы макроса почти в 16!!! раз
Код
'Перенос текста в выделенном диапазоне на СТРОКИ НИЖЕ при заполнении столбца по ширине
'Принцип: содержимое ячейки, которое переносится "визуально" при изменении ширины столбца, макрос переносит на самом деле в нижние ячейки
'Особенность: сцепляет переносимое с содержимым солбца слева, после переноса расцепляет обратно для соблюдения связи
'Переменная "myEC" - вспомогательный столбец (будет очищен после выполнения макроса)
'=======================================================================================================
Sub WrapDownWithLeftColomn()

   Dim c As Range, myRa As Range
   Dim s As String
   Dim Arr As Variant
   Dim i As Integer
   Dim d As Variant


        Application.ScreenUpdating = False
        Application.Calculation = xlCalculationManual
        Application.EnableEvents = False
        ActiveSheet.DisplayPageBreaks = False
        Application.DisplayStatusBar = False
        Application.DisplayAlerts = False

    
   Set myRa = Selection
   myC = myRa.Column
   myE = myRa.Row - 1
   myR = myRa.Row
   myEC = 10 '№ вспомогательного столбца
   Columns(myEC).EntireColumn.Clear
   For Each r In myRa.Rows
       myE = myE + 1
       d = Cells(r.Row, myC).ColumnWidth * 1.05 'ширина первоначальной ячейки (несколько увеличена)
       Arr = Split(Cells(r.Row, myC), " ")
       s = ""
       Cells(myE, myEC - 1) = Cells(r.Row, myC - 1)
       For i = 0 To UBound(Arr)
          s = s & Arr(i) & " "
           
          Cells(myE, myEC) = s
     
          Cells(myE, myEC).EntireColumn.AutoFit
     
          If Cells(myE, myEC).ColumnWidth > d Then
             Cells(myE, myEC).ColumnWidth = d
             Cells(myE, myEC).Value = left(s, Len(s) - (Len(Arr(i)) + 1))  'без последнего слова
             i = i - 1 'т.к. слово выкинули
              
             '---- переход в другую ячейку ----
             myE = myE + 1
             s = ""
          End If
       Next i
        
   Next
   myRa.Delete Shift:=xlUp
   Range(Cells(myR, myC - 1), Cells(myE, myC - 1)).Delete Shift:=xlUp
   Range(Cells(myR, myEC - 1), Cells(myE, myEC)).Copy
   Cells(myR, myC - 1).Insert Shift:=xlDown
   Range(Cells(myR, myEC - 1), Cells(myE, myEC)).Clear

   
        Application.ScreenUpdating = True
    
        Application.EnableEvents = True
    
        Application.DisplayStatusBar = True
        Application.DisplayAlerts = True
   
End Sub

'=========================================================================================================

Sub WrapDown()

   Dim c As Range, myRa As Range
   Dim s As String
   Dim Arr As Variant
   Dim i As Integer
   Dim d As Variant
   
        Application.ScreenUpdating = False
        Application.Calculation = xlCalculationManual
        Application.EnableEvents = False
        ActiveSheet.DisplayPageBreaks = False
        Application.DisplayStatusBar = False
        Application.DisplayAlerts = False
    
   Set myRa = Selection
   myC = myRa.Column
   myE = myRa.Row - 1
   myR = myRa.Row
   myEC = myC + 5 '№ вспомогательного столбца
   Columns(myEC).EntireColumn.Clear
   For Each r In myRa.Rows
       myE = myE + 1
       d = Cells(r.Row, myC).ColumnWidth * 1.05 'ширина первоначальной ячейки (несколько увеличена)
       Arr = Split(Cells(r.Row, myC), " ")
       s = ""
       For i = 0 To UBound(Arr)
          s = s & Arr(i) & " "
           
          Cells(myE, myEC) = s
     
          Cells(myE, myEC).EntireColumn.AutoFit
     
          If Cells(myE, myEC).ColumnWidth > d Then
             Cells(myE, myEC).ColumnWidth = d
             Cells(myE, myEC).Value = left(s, Len(s) - (Len(Arr(i)) + 1))  'без последнего слова
             i = i - 1 'т.к. слово выкинули
              
             '---- переход в другую ячейку ----
             myE = myE + 1
             s = ""
          End If
       Next i
   Next
   myRa.Delete Shift:=xlUp
   Range(Cells(myR, myEC), Cells(myE, myEC)).Copy
   Cells(myR, myC).Insert Shift:=xlDown
   Columns(myEC).EntireColumn.Clear

   
        Application.ScreenUpdating = True
    
        Application.EnableEvents = True
    
        Application.DisplayStatusBar = True
        Application.DisplayAlerts = True
   
End Sub
Изменено: Jack_Famous - 04.05.2016 10:43:03
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack_Famous написал:
прошу вашей помощи по оптимизации самого подходящего (для моих задач) макроса: он сцепляет выделенный диапазон (который нужно разнести по строкам) со столбцом слева, переносит целевой и расцепляет обратно - в итоге построчная связь не разрушается и остальные поля можно подтянуть через ВПР
Добрый день, вот это - не понятно ▲ :(
По вложенному макросу - думаю, что можно ускорить рззбиение на несколько ячеек при допущении, что:
1. Все ячейки в Selection - одного формата (а именно: шрифт, номер шрифта).
2. Все символы внутри содержимого (т.е. - текста) каждой ячейки, входящей в Selection, также имеют один шрифт и размер.
В Вашем примере - ячейка, которая используется для автоподгонки ширины столбца, имеет размер (т.е. номер) шрифта, отличный от размера, используемого в ячейках, для которых всё затевается (т.е. у Вас это - Selection). Наверно это ээээ. ошибка? :)
Пока - всё. Откорректирую макрос - выложу.
Всё сложное - не нужно. Всё нужное - просто /М. Т. Калашников/
 
Михаил Лебедев, доброго утра!)))
По непонятному: изменил и дополнил файл-пример ;)
По макросу: делал не я , поэтому может быть всё, что угодно))))
По, непосредственно, переносу: за запуск переноситься в 1 столбце будет всегда содержимое одного размера, шрифта и т.д. Обычно это Times New Roman - 8, но хотелось бы понять, где изменить, в случае чего (может на InputBox назначить...)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Новый файл - не смотрел.
Исходил из того, что для одной и той же автоширины столбца нужно одно и то же кол-во символов в ячейке, если шрифт и его размер - совпадают.
Изменено: Михаил Лебедев - 04.05.2016 13:36:31
Всё сложное - не нужно. Всё нужное - просто /М. Т. Калашников/
 
Цитата
Jack_Famous написал: но хотелось бы понять, где изменить...о
Привязал размер и название шрифта к первой ячейке выделенного блока.
Мой пример - "сырой", не сделана проверка на кол-во столбцов выделенных, не учтен случай, когда ячейка - пустая, когда первое же слово - длинней, чем необходима ширина столбца и, скорее всего, еще что-нибудь...
Всё сложное - не нужно. Всё нужное - просто /М. Т. Калашников/
 
Михаил Лебедев, он работает быстрее, чем стандартный WrapDown (который без сцепки) - спасибо большое)))) к сожалению, при его использовании абсолютно теряется  связь между строками (даже с левым столбцом) и, да, он не проверяет нижние ячейки на заполненность и копирует прямо в них - но для задач, где это не нужно, подходит отлично ;) :idea:

P.S.: а это действительно так проблематично - чтобы макрос сдвигал/вставлял строки целиком?... Я понимаю, что Excel как-бы не для переносов, но всё-же)))
Изменено: Jack_Famous - 04.05.2016 14:03:55
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Можно добавлять сквозные строки, но работать будет помедленнее...
Всё сложное - не нужно. Всё нужное - просто /М. Т. Калашников/
 
Михаил Лебедев, доброе утро! Вот это шедевр!)))) Очень быстро всё разносит и строки вставляет, как надо)))) :D 8) :idea: проблема решена!
Спасибо Вам огромное!!!
А код закомментировали так, что очень удобно пошагово изучать его)))) Примечательно, что в старой теме вы были первый, кто отозвался ;)

P.S.: разместил в старой теме ссылку на эту, для тех, кто ищет, так как найдено общее глобальное решение...
Код
'Перенос текста по строкам в выделенном диапазоне (один столбец)
'
'Исходник кода «Wrap», использованного при создании данного макроса (автор: «Саня»): http://www.excelworld.ru/forum/10-13118-1?laBq83
'Тема, в которой НАЧАЛСЯ поиск решения: http://www.planetaexcel.ru/forum/index.php?PAGE_NAME=read&FID=1&TID=71429&TITLE_SEO=71429-perenos-teksta-na-yacheyku-vniz-pri-zapolnenii-stroki-po-shirine
'Тема, в которой решение было НАЙДЕНО: http://www.planetaexcel.ru/forum/index.php?PAGE_NAME=message&FID=1&TID=77447&TITLE_SEO=77447-perenos-teksta-na-sleduyushchuyu-stroku-pri-zapolnenii-stolbtsa-po-shi&MID=648862&result=edit#message648862
'Автор финальной версии: Михаил Лебедев
'Немного "подбил под себя": Jack Famous
'===================================================================================================================================================================================================================================================

Sub TextWrapping()

 Dim myRa As Range, r As Range
    Dim s As String, s1 As String
    Dim myFontName As String, myFontSize As String
    Dim arr
    Dim arrCountRowInCells()
    Dim arr1()
    Dim myCol
    Dim i As Integer, j As Integer, k As Integer, l As Integer, CountRowInCells As Integer
    Dim d
    
    
    myCol = InputBox("Введите номер по счёту свободного столбца для вычислений СПРАВА от активного")
    If myCol = "" Then End

   
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Application.EnableEvents = False
    ActiveSheet.DisplayPageBreaks = False
    Application.DisplayStatusBar = False
    Application.DisplayAlerts = False

    
    Set myRa = Selection                ' !!! должен быть только ОДИН !!! столбец, в котором текст

    d = myRa.ColumnWidth * 0.95         ' ширина первоначальной ячейки (несколько уменьшена)
    ReDim arrCountRowInCells(myRa.Rows.Count) ' размер массива для хранения кол-ва строк для каждой ячейки из myRa
    With myRa.Cells(1)                  ' работаем с текстом первой ячейки из Selection
        myFontSize = .Font.Size         ' запоминаем размер шрифта первой ячейки из Selection
        myFontName = .Font.Name         ' запоминаем имя шрифта первой ячейки из Selection
        arr = Split(.Value, " ")        ' забираем в массив текст  из первой ячейки выделения
        With .Offset(, myCol)           ' работаем с ячейками, в "myCol"
            .EntireColumn.Clear         ' Очищаем "myCol" от MyRa (это вместо: Columns(10).EntireColumn.Clear)
            s = ""
            .Font.Size = myFontSize     ' устанавливаем размер шрифта, как в первой ячейке выделения
            .Font.Name = myFontName     ' устанавливаем имя шрифта, как в первой ячейке выделения

            ' Дальше - исходим из того, что после подбора нужной ширины столбца
            ' нужно подобрать нужное количество символов для этой ширины, чтобы
            ' каждый раз не заморачиваться с подбором ширины столбца
            ' НАЧАЛИ =========================================================================================================================================
            For i = 0 To UBound(arr)
              s = s & arr(i) & " "
              .Value = s
              .EntireColumn.AutoFit                 ' делаем автоподбор ширины
              If .ColumnWidth > d Then              ' если подобрали ширину больше, чем надо, то...
                 Do Until .ColumnWidth < d          ' ... до тех пор, пока ширина будет больше,
                    j = j + 1
                    .Value = left(s, Len(s) - j)    '... начинаем в цикле уменьшать на 1 символ ...
                    .EntireColumn.AutoFit           ' и делать автоподбор ширины столбца снова
                 Loop
                 j = Len(.Value)    ' запоминаем, сколько символов максимум должно быть в строке
                 s = ""
            Exit For
              End If
            Next
            ' ЗАКОНЧИЛИ ========================================================================================================================================
            .Clear ' очищаем временную ячейку
        End With
    End With
    k = 0
    For Each r In myRa ' бежим по всем выделенным ячейкам, разбиваем на слова из условия, что длина не должна превышать максимальную для данной ширины столбца
        arr = Split(r.Value, " ")
        For i = 0 To UBound(arr) - 1
            s = s & arr(i) & " "
            s1 = s & arr(i + 1) & " "
            If (Len(s1) - 1) > j Then
                ReDim Preserve arr1(k + 1)
                arr1(k) = RTrim(s)
                k = k + 1
                CountRowInCells = CountRowInCells + 1
                s = ""
                s1 = ""
            End If
            If i = (UBound(arr) - 1) Then
                arr1(k) = RTrim(s1)
                k = k + 1
                CountRowInCells = CountRowInCells + 1
                s = ""
                s1 = ""
            End If
        Next
        arrCountRowInCells(l) = CountRowInCells
        l = l + 1
        CountRowInCells = 0
    Next
' Добавляем нужное кол-во строк
        For i = UBound(arrCountRowInCells) - 1 To 0 Step -1
            Range(myRa.Cells(1).Offset(i + 1), myRa.Cells(1).Offset(i + arrCountRowInCells(i) - 1)).EntireRow.Insert , CopyOrigin:=xlFormatFromLeftOrAbove
        Next
' Заносим данные в столбец myRa
        For i = 0 To UBound(arr1)
            myRa.Cells(1).Offset(i) = arr1(i)
        Next
' копируем в новый блок форматы из первой ячейки myRa
' НАЧАЛО ======================================================================================================================================================
    myRa.Cells(1).Copy
    Range(myRa.Cells(1), myRa.Cells(1).Offset(UBound(arr1))).PasteSpecial _
        Paste:=xlPasteFormats, _
        Operation:=xlNone, _
        SkipBlanks:=False, _
        Transpose:=False
' КОНЕЦ =======================================================================================================================================================
    
    
    Application.CutCopyMode = False
    
    
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Application.EnableEvents = True

    Application.DisplayStatusBar = True
    Application.DisplayAlerts = True

    
End Sub



Изменено: Jack_Famous - 05.05.2016 10:36:23
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Пожалуйста :) Заодно и сам поупражнялся, а то давно ничего не писал. Лобные мышцы стали дрябнуть :)
Всё сложное - не нужно. Всё нужное - просто /М. Т. Калашников/
 
Михаил Лебедев, если будет интересно - вот тут поднимается интересная тема о "правильности" и "грамотности" переноса в Excel, а уважаемый RAN сделал пару своих вариантов - буду рад, если вы ЕЩЁ улучшите макрос (не позволяйте мыщцам дряблеть :D ) ;) хотя и так я ОЧЕНЬ МНОГО перерыл, но ТАКОЙ универсальности не видел :D
Ещё раз огромное Вам спасибо, Михаил!!!
Изменено: Jack_Famous - 05.05.2016 12:02:07
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Добрый день.
Возникла надобность решения подобного по теме, но с некоторой поправкой. В моем случае текст так же находится в одной ячейке, но вписать его нужно не в одну ячейку, а в диапазон по ширине нескольких смежных ячеек, в поле определенное формой. В общем определить ширину диапазона для ввода текста из нескольких столбцов я смог, а вот дальше застрял. Никак не соображу что надо еще исправить в коде, мне ведь надо выделить не 1 столбец по ячейкам, а несколько. В остальном функционал кода полностью устраивает.
 
Всем добрый день.
Как говорится, спасение утопающих дело рук самих утопающих. Несколько переделал код под свои нужды, он работает, но возникло несколько вопросов. Если ячейки выделять по одной строке - всё вообще прекрасно. Если же выделять по несколько строк строк, то возникают огрехи: где-то вставляется лишняя пустая строка, а где-то строка не добавляется и перенос не производится. В приложенном примере это видно по позиции №5. Подскажите, что я сделал не так.
Изменено: cuprum - 20.02.2018 16:20:45
 
Видимо мой вопрос никого не заинтересовал.  :sceptic:  Но благодаря откликнувшимся в теме Возможно ли изменение изменение предела счетчика в цикле For Next возникшей в поисках решения по этой теме, вопрос разрешился, за что я им всем благодарен.  :)  
 
cuprum, Андрей VG мне прислал вот такой файл. Я его не смотрел…
Описание от Андрея: По этой теме. Набросал код для разбора содержимого ячейки(ек) на строки для вставки через вспомогательный объект. Для четырёх ячеек с большим текстом, суммарно раскладывающемся на 174 ячейки по ширине, отрабатывает за 0,2 секунды. Под всё остальное не затачивал. Вывод разбивки выполняется на новый лист.
Изменено: Jack Famous - 27.02.2018 16:40:23
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous, спасибо. Попытаюсь понять как это работает.  
Страницы: 1
Наверх