Сразу оговорюсь - макросы не мои. Я только чуточку доработал их для большей универсальности. Итак: [vba]
Code
Option Explicit Option Base 1 Sub ReduceSize() Dim lAntR As Long Dim iAntK As Integer Dim aR() As Single Dim aK() As Single Dim n As Integer Dim sFil1 As String Dim sFil2 As String Dim sKat As String Dim sArk As String Dim sh As Worksheet Dim nWb As Workbook Dim i As Integer i = 1 sFil1 = ActiveWorkbook.Name sKat = ActiveWorkbook.Path Set nWb = Workbooks.Add sFil2 = ActiveWorkbook.Name Workbooks(sFil2).SaveAs sKat & "\" & "(2)" & sFil1 sFil2 = ActiveWorkbook.Name For Each sh In ThisWorkbook.Sheets sh.Activate sArk = ActiveSheet.Name lAntR = Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row iAntK = Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
ReDim aR(lAntR) ReDim aK(iAntK) For n = 1 To lAntR aR(n) = Rows(n).RowHeight Next n For n = 1 To iAntK aK(n) = Columns(n).ColumnWidth Next n Application.CutCopyMode = False Range(Cells(1, 1), Cells(lAntR, iAntK)).Copy With nWb If .Sheets.Count < i Then .Sheets.Add after:=.Sheets(.Sheets.Count) End If .Sheets(i).Name = sArk .Sheets(i).Paste Application.CutCopyMode = False For n = 1 To lAntR .Sheets(i).Rows(n).RowHeight = aR(n) Next n For n = 1 To iAntK .Sheets(i).Columns(n).ColumnWidth = aK(n) Next n End With i = i + 1 Next Application.DisplayAlerts = False Call ExportAllStdModules(Workbooks(sFil2)) Workbooks(sFil2).Save Workbooks(sFil1).Close savechanges:=True Application.DisplayAlerts = True End Sub
[/vba]
[vba]
Code
Private Sub ExportAllStdModules(wb As Workbook) Dim iTempPath As String, iModuleName As String Dim iVBComponent With Application .ScreenUpdating = False iTempPath = .DefaultFilePath & .PathSeparator With wb.VBProject.VBComponents For Each iVBComponent In ThisWorkbook.VBProject.VBComponents If iVBComponent.Type = 1 Then iModuleName$ = iTempPath$ & iVBComponent.Name iVBComponent.Export Filename:=iModuleName$ .Import Filename:=iModuleName$ Kill PathName:=iModuleName$ End If Next End With .ScreenUpdating = True End With End Sub
[/vba]
P.S. Думаю, излишним будет напоминать о резервном копировании данных (хотя макрос данные исходной книги никак не затрагивает).
Сразу оговорюсь - макросы не мои. Я только чуточку доработал их для большей универсальности. Итак: [vba]
Code
Option Explicit Option Base 1 Sub ReduceSize() Dim lAntR As Long Dim iAntK As Integer Dim aR() As Single Dim aK() As Single Dim n As Integer Dim sFil1 As String Dim sFil2 As String Dim sKat As String Dim sArk As String Dim sh As Worksheet Dim nWb As Workbook Dim i As Integer i = 1 sFil1 = ActiveWorkbook.Name sKat = ActiveWorkbook.Path Set nWb = Workbooks.Add sFil2 = ActiveWorkbook.Name Workbooks(sFil2).SaveAs sKat & "\" & "(2)" & sFil1 sFil2 = ActiveWorkbook.Name For Each sh In ThisWorkbook.Sheets sh.Activate sArk = ActiveSheet.Name lAntR = Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row iAntK = Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
ReDim aR(lAntR) ReDim aK(iAntK) For n = 1 To lAntR aR(n) = Rows(n).RowHeight Next n For n = 1 To iAntK aK(n) = Columns(n).ColumnWidth Next n Application.CutCopyMode = False Range(Cells(1, 1), Cells(lAntR, iAntK)).Copy With nWb If .Sheets.Count < i Then .Sheets.Add after:=.Sheets(.Sheets.Count) End If .Sheets(i).Name = sArk .Sheets(i).Paste Application.CutCopyMode = False For n = 1 To lAntR .Sheets(i).Rows(n).RowHeight = aR(n) Next n For n = 1 To iAntK .Sheets(i).Columns(n).ColumnWidth = aK(n) Next n End With i = i + 1 Next Application.DisplayAlerts = False Call ExportAllStdModules(Workbooks(sFil2)) Workbooks(sFil2).Save Workbooks(sFil1).Close savechanges:=True Application.DisplayAlerts = True End Sub
[/vba]
[vba]
Code
Private Sub ExportAllStdModules(wb As Workbook) Dim iTempPath As String, iModuleName As String Dim iVBComponent With Application .ScreenUpdating = False iTempPath = .DefaultFilePath & .PathSeparator With wb.VBProject.VBComponents For Each iVBComponent In ThisWorkbook.VBProject.VBComponents If iVBComponent.Type = 1 Then iModuleName$ = iTempPath$ & iVBComponent.Name iVBComponent.Export Filename:=iModuleName$ .Import Filename:=iModuleName$ Kill PathName:=iModuleName$ End If Next End With .ScreenUpdating = True End With End Sub
[/vba]
P.S. Думаю, излишним будет напоминать о резервном копировании данных (хотя макрос данные исходной книги никак не затрагивает).KuklP
Ну с НДС и мы чего-то стoим! kuklp60@gmail.com WM Z206653985942, R334086032478, U238399322728
Код классный! Можно рекомендовать к широкому использованию. Попробовал на работе с распухшим за несколько лет общим файлом с сотней страниц. Весил 40 метров. Открывался по сети "со скрипом". Теперь весит 12 метров и по сравнению со старым прямо летает.
Зная нелюбовь Сергея (KuklP) к оформительской работе, давно собирался "причесать" классный код, предложенный им: более понятно (на мой взгляд) переобозвать переменные, добавить комментарии с целью повышения его читабельности не слишком искушенными пользователями. А тут заболел (грипп, зараза!), сижу дома. Подполировал код Сергея. Надеюсь, он не против? И так: 1. В стандартный модуль разбухшей книги помещаем код:[vba]
Code
Option Explicit Option Base 1
Sub ReduceSize() ' фитнесс для разбухших файлов '--------------------------------------------------------------------------------------- ' Procedure : ReduceSize ' Author : KuklP + Alex_ST ("полировка" и комментарии) ' URL : http://www.excelworld.ru/forum/3-57-1 ' Date : 10.09.2010 + 01.02.2011 ' Purpose : фитнесс для разбухших файлов '---------------------------------------------------------------------------------------
Dim LastRow&, LastColumn% Dim arrRowsHeight!(), arrColumnsWidth!() Dim oldWbName$, newWbName$ Dim WbPath$, iShtName$ Dim iSht As Worksheet Dim newWb As Workbook Dim i%, n% WbPath = ActiveWorkbook.Path ' запомним путь к книге oldWbName = ActiveWorkbook.Name ' запомним имя старой книги Set newWb = Workbooks.Add ' создадим новую книгу (она сразу станет ActiveWorkbook) ActiveWorkbook.SaveAs WbPath & "\" & "(NEW) " & oldWbName 'сохраним новую книгу рядом со старой с префиксом к имени "(NEW) " newWbName = ActiveWorkbook.Name ' запомним имя новой книги i = 1 ' начинаем с первой страницы новой книги For Each iSht In ThisWorkbook.Sheets ' цикл по всем листам старой(ThisWorkbook) книги iSht.Activate iShtName = ActiveSheet.Name LastRow = Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row ' последняя строка на листе, содержащая хоть какие-нибудь значения LastColumn = Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column ' последний столбец на листе, содержащий хоть какие-нибудь значения ReDim arrRowsHeight(LastRow) ReDim arrColumnsWidth(LastColumn) For n = 1 To LastRow ' запомним высоты строк в массив arrRowsHeight(n) = Rows(n).RowHeight Next n For n = 1 To LastColumn ' запомним ширины столбцов в массив arrColumnsWidth(n) = Columns(n).ColumnWidth Next n Application.CutCopyMode = False Range(Cells(1, 1), Cells(LastRow, LastColumn)).Copy ' копируем только диапазон, содержащий данные With newWb If .Sheets.Count < i Then .Sheets.Add after:=.Sheets(.Sheets.Count) .Sheets(i).Name = iShtName .Sheets(i).Paste ' копируем на страницы новой книги диапазон, содержащий данные Application.CutCopyMode = False For n = 1 To LastRow ' восстановим высоты строк .Sheets(i).Rows(n).RowHeight = arrRowsHeight(n) Next n For n = 1 To LastColumn ' восстановим ширины столбцов .Sheets(i).Columns(n).ColumnWidth = arrColumnsWidth(n) Next n End With i = i + 1 ' продолжим на следующей странице новой книги Next Application.DisplayAlerts = False Call ExportAllStdModules(Workbooks(newWbName)) ' скопировать все компоненты VBA в новую книгу Workbooks(newWbName).Save ' сохраним новую книгу Workbooks(oldWbName).Close SaveChanges:=False ' закроем старую книгу без сохранения изменений Application.DisplayAlerts = True End Sub
Private Sub ExportAllStdModules(wb As Workbook) ' скопировать все компоненты VBA в новую книгу Dim iTempPath$, iModuleName$ Dim iVBComponent With Application .ScreenUpdating = False iTempPath = .DefaultFilePath & .PathSeparator With wb.VBProject.VBComponents For Each iVBComponent In ThisWorkbook.VBProject.VBComponents If iVBComponent.Type = 1 Then iModuleName$ = iTempPath$ & iVBComponent.Name iVBComponent.Export Filename:=iModuleName$ .Import Filename:=iModuleName$ Kill PathName:=iModuleName$ End If Next End With .ScreenUpdating = True End With End Sub
[/vba]
2. Выполняем макрос ReduceSize 3. После выполнения работы макроса рядом с распухшим файлом будет создан такой же по содержанию, но "похудевший" новый файл с префиксом (NEW).
Код классный! Можно рекомендовать к широкому использованию. Попробовал на работе с распухшим за несколько лет общим файлом с сотней страниц. Весил 40 метров. Открывался по сети "со скрипом". Теперь весит 12 метров и по сравнению со старым прямо летает.
Зная нелюбовь Сергея (KuklP) к оформительской работе, давно собирался "причесать" классный код, предложенный им: более понятно (на мой взгляд) переобозвать переменные, добавить комментарии с целью повышения его читабельности не слишком искушенными пользователями. А тут заболел (грипп, зараза!), сижу дома. Подполировал код Сергея. Надеюсь, он не против? И так: 1. В стандартный модуль разбухшей книги помещаем код:[vba]
Code
Option Explicit Option Base 1
Sub ReduceSize() ' фитнесс для разбухших файлов '--------------------------------------------------------------------------------------- ' Procedure : ReduceSize ' Author : KuklP + Alex_ST ("полировка" и комментарии) ' URL : http://www.excelworld.ru/forum/3-57-1 ' Date : 10.09.2010 + 01.02.2011 ' Purpose : фитнесс для разбухших файлов '---------------------------------------------------------------------------------------
Dim LastRow&, LastColumn% Dim arrRowsHeight!(), arrColumnsWidth!() Dim oldWbName$, newWbName$ Dim WbPath$, iShtName$ Dim iSht As Worksheet Dim newWb As Workbook Dim i%, n% WbPath = ActiveWorkbook.Path ' запомним путь к книге oldWbName = ActiveWorkbook.Name ' запомним имя старой книги Set newWb = Workbooks.Add ' создадим новую книгу (она сразу станет ActiveWorkbook) ActiveWorkbook.SaveAs WbPath & "\" & "(NEW) " & oldWbName 'сохраним новую книгу рядом со старой с префиксом к имени "(NEW) " newWbName = ActiveWorkbook.Name ' запомним имя новой книги i = 1 ' начинаем с первой страницы новой книги For Each iSht In ThisWorkbook.Sheets ' цикл по всем листам старой(ThisWorkbook) книги iSht.Activate iShtName = ActiveSheet.Name LastRow = Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row ' последняя строка на листе, содержащая хоть какие-нибудь значения LastColumn = Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column ' последний столбец на листе, содержащий хоть какие-нибудь значения ReDim arrRowsHeight(LastRow) ReDim arrColumnsWidth(LastColumn) For n = 1 To LastRow ' запомним высоты строк в массив arrRowsHeight(n) = Rows(n).RowHeight Next n For n = 1 To LastColumn ' запомним ширины столбцов в массив arrColumnsWidth(n) = Columns(n).ColumnWidth Next n Application.CutCopyMode = False Range(Cells(1, 1), Cells(LastRow, LastColumn)).Copy ' копируем только диапазон, содержащий данные With newWb If .Sheets.Count < i Then .Sheets.Add after:=.Sheets(.Sheets.Count) .Sheets(i).Name = iShtName .Sheets(i).Paste ' копируем на страницы новой книги диапазон, содержащий данные Application.CutCopyMode = False For n = 1 To LastRow ' восстановим высоты строк .Sheets(i).Rows(n).RowHeight = arrRowsHeight(n) Next n For n = 1 To LastColumn ' восстановим ширины столбцов .Sheets(i).Columns(n).ColumnWidth = arrColumnsWidth(n) Next n End With i = i + 1 ' продолжим на следующей странице новой книги Next Application.DisplayAlerts = False Call ExportAllStdModules(Workbooks(newWbName)) ' скопировать все компоненты VBA в новую книгу Workbooks(newWbName).Save ' сохраним новую книгу Workbooks(oldWbName).Close SaveChanges:=False ' закроем старую книгу без сохранения изменений Application.DisplayAlerts = True End Sub
Private Sub ExportAllStdModules(wb As Workbook) ' скопировать все компоненты VBA в новую книгу Dim iTempPath$, iModuleName$ Dim iVBComponent With Application .ScreenUpdating = False iTempPath = .DefaultFilePath & .PathSeparator With wb.VBProject.VBComponents For Each iVBComponent In ThisWorkbook.VBProject.VBComponents If iVBComponent.Type = 1 Then iModuleName$ = iTempPath$ & iVBComponent.Name iVBComponent.Export Filename:=iModuleName$ .Import Filename:=iModuleName$ Kill PathName:=iModuleName$ End If Next End With .ScreenUpdating = True End With End Sub
[/vba]
2. Выполняем макрос ReduceSize 3. После выполнения работы макроса рядом с распухшим файлом будет создан такой же по содержанию, но "похудевший" новый файл с префиксом (NEW).Alex_ST
Привет, Леш. С чего бы я был против? Для того и выкладывал, чтоб все пользовались. И вообще, я не раз и на разных форумах выказывал свою нелюбовь к скрытию, запароливанию и т.д. То, что создано, должно работать и приносить пользу. И чем большую, тем лучше:-) Выздоравливай, давай!
Quote (Alex_ST)
Надеюсь, он не против?
Привет, Леш. С чего бы я был против? Для того и выкладывал, чтоб все пользовались. И вообще, я не раз и на разных форумах выказывал свою нелюбовь к скрытию, запароливанию и т.д. То, что создано, должно работать и приносить пользу. И чем большую, тем лучше:-) Выздоравливай, давай!KuklP
Ну с НДС и мы чего-то стoим! kuklp60@gmail.com WM Z206653985942, R334086032478, U238399322728
Сообщение отредактировал KuklP - Вторник, 01.02.2011, 19:32
Привет, Серёга! Рад, что ты ответил. Всё-таки мнение автора - главное. Хотя я в общем-то в твоём "одобрямсе" и не сомневался. Но всё-таки... Всё. Больше в теме на флудим. Обсуждение здесь - это правильно. А общение - флуд.
Привет, Серёга! Рад, что ты ответил. Всё-таки мнение автора - главное. Хотя я в общем-то в твоём "одобрямсе" и не сомневался. Но всё-таки... Всё. Больше в теме на флудим. Обсуждение здесь - это правильно. А общение - флуд.Alex_ST
С уважением, Алексей MS Excel 2003 - the best!!!
Сообщение отредактировал Alex_ST - Вторник, 01.02.2011, 19:38
Я тоже наткнулся я на эти грабли, когда пытался чужой многостраничный файл "похудеть", но тогда просто закомментировал так: [vba]
Код
If .Sheets.Count < i Then .Sheets.Add ' after:=.Sheets.Count
[/vba], т.к. было нужно срочно и был "завал" на работе. Решил разобраться потом и забыл...
А вот на днях на другие "грабли" напоролся: проблема с элементами OLEObject на листе - не переносятся, гады. Правда, это было ближе к концу рабочего дня, а перегружать Ёксель я не пробовал (опять "завал")... И тоже отложил "разбор полётов". Может, перед выполнением макроса режим конструктора включить? Надо подуамть...
Я тоже наткнулся я на эти грабли, когда пытался чужой многостраничный файл "похудеть", но тогда просто закомментировал так: [vba]
Код
If .Sheets.Count < i Then .Sheets.Add ' after:=.Sheets.Count
[/vba], т.к. было нужно срочно и был "завал" на работе. Решил разобраться потом и забыл...
А вот на днях на другие "грабли" напоролся: проблема с элементами OLEObject на листе - не переносятся, гады. Правда, это было ближе к концу рабочего дня, а перегружать Ёксель я не пробовал (опять "завал")... И тоже отложил "разбор полётов". Может, перед выполнением макроса режим конструктора включить? Надо подуамть...Alex_ST
С уважением, Алексей MS Excel 2003 - the best!!!
Сообщение отредактировал Alex_ST - Пятница, 18.02.2011, 15:43
А еще он не перенесет макросы из модулей листов. Можно разрешить, но перенесет как классы. А OLEObject в новом файле сохранившие ссылки на старый файл тебе нужны? Отож. А если еще и куча форм в файле, грабли обеспечены. Я уже неоднократно утверждал, что универсальные макросы всех времен и народов - это не мое:-) Я больше на злобу дня...
А еще он не перенесет макросы из модулей листов. Можно разрешить, но перенесет как классы. А OLEObject в новом файле сохранившие ссылки на старый файл тебе нужны? Отож. А если еще и куча форм в файле, грабли обеспечены. Я уже неоднократно утверждал, что универсальные макросы всех времен и народов - это не мое:-) Я больше на злобу дня...KuklP
Ну с НДС и мы чего-то стoим! kuklp60@gmail.com WM Z206653985942, R334086032478, U238399322728
Я это тоже заметил, но разбираться было некогда - ручками перенёс вместе с OLEObject-ами листа. Для меня это вообще наикрутейший облом, т.к. я как раз люблю писАть так, чтобы было как можно меньше связей между листами. При таком стиле программирования можно лист без проблем копировать в другую книгу и всё будет работать, как, например, в моём "удобном автофильтре" ... Конечно, это ведёт к избыточности кода, зато удобно.
Quote (KuklP)
А еще он не перенесет макросы из модулей листов
Я это тоже заметил, но разбираться было некогда - ручками перенёс вместе с OLEObject-ами листа. Для меня это вообще наикрутейший облом, т.к. я как раз люблю писАть так, чтобы было как можно меньше связей между листами. При таком стиле программирования можно лист без проблем копировать в другую книгу и всё будет работать, как, например, в моём "удобном автофильтре" ... Конечно, это ведёт к избыточности кода, зато удобно.Alex_ST
С уважением, Алексей MS Excel 2003 - the best!!!
Сообщение отредактировал Alex_ST - Суббота, 19.02.2011, 21:44
Сергей, а почему собственно в Private Sub ExportAllStdModules ты ограничился только копированием стандартных модулей? Если я правильно понял, то твой код [vba]
Код
If iVBComponent.Type = 1 Then
[/vba] это то же самое, что [vba]
Код
If iVBComponent.Type = vbext_ct_StdModule Then
[/vba] А почему нельзя копировать точно также и модули классов (Type = vbext_ct_ClassModule = 2), модули форм (Type = vbext_ct_MSForm = 3)?
К стати, а вот здесь написано: vbext_ct_Document (100): One of the Sheet modules or the ThisWorkbook module что-то я не понял, модули листов разве не модули класса?
Сергей, а почему собственно в Private Sub ExportAllStdModules ты ограничился только копированием стандартных модулей? Если я правильно понял, то твой код [vba]
Код
If iVBComponent.Type = 1 Then
[/vba] это то же самое, что [vba]
Код
If iVBComponent.Type = vbext_ct_StdModule Then
[/vba] А почему нельзя копировать точно также и модули классов (Type = vbext_ct_ClassModule = 2), модули форм (Type = vbext_ct_MSForm = 3)?
К стати, а вот здесь написано: vbext_ct_Document (100): One of the Sheet modules or the ThisWorkbook module что-то я не понял, модули листов разве не модули класса?Alex_ST
См. ответ от Дата: Пятница, 18.02.2011, 23:59. Закомментируй так и посмотри, что выйдет: [vba]
Код
For Each iVBComponent In ThisWorkbook.VBProject.VBComponents 'If iVBComponent.Type = 1 Then iModuleName$ = iTempPath$ & iVBComponent.Name iVBComponent.Export Filename:=iModuleName$ .Import Filename:=iModuleName$ Kill PathName:=iModuleName$ 'End If Next
[/vba]
См. ответ от Дата: Пятница, 18.02.2011, 23:59. Закомментируй так и посмотри, что выйдет: [vba]
Код
For Each iVBComponent In ThisWorkbook.VBProject.VBComponents 'If iVBComponent.Type = 1 Then iModuleName$ = iTempPath$ & iVBComponent.Name iVBComponent.Export Filename:=iModuleName$ .Import Filename:=iModuleName$ Kill PathName:=iModuleName$ 'End If Next
Sub ReduceSize() Dim lAntR As Long Dim iAntK As Integer Dim aR() As Single Dim aK() As Single Dim n As Integer Dim sFil1 As String Dim sFil2 As String Dim sKat As String Dim sArk As String Dim sh As Worksheet Dim nWb As Workbook Dim i As Integer i = 1 sFil1 = ActiveWorkbook.Name sKat = ActiveWorkbook.Path Set nWb = Workbooks.Add sFil2 = ActiveWorkbook.Name Workbooks(sFil2).SaveAs sKat & "\" & "(2)" & sFil1 sFil2 = ActiveWorkbook.Name For Each sh In ThisWorkbook.Sheets sh.Activate sArk = ActiveSheet.Name lAntR = Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row iAntK = Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
ReDim aR(lAntR) ReDim aK(iAntK) For n = 1 To lAntR aR(n) = Rows(n).RowHeight Next n For n = 1 To iAntK aK(n) = Columns(n).ColumnWidth Next n Application.CutCopyMode = False Range(sh.Cells(1, 1), sh.Cells(lAntR, iAntK)).Copy With nWb If .Sheets.Count < i Then .Sheets.Add after:=.Sheets(.Sheets.Count) End If .Sheets(i).Name = sArk .Sheets(i).Paste '([a1]) Application.CutCopyMode = False For n = 1 To lAntR .Sheets(i).Rows(n).RowHeight = aR(n) Next n For n = 1 To iAntK .Sheets(i).Columns(n).ColumnWidth = aK(n) Next n End With i = i + 1 Next Application.DisplayAlerts = False Call ExportAllStdModules(Workbooks(sFil2)) Workbooks(sFil2).Save Workbooks(sFil1).Close savechanges:=True Application.DisplayAlerts = True End Sub Private Sub ExportAllStdModules(wb As Workbook) Dim iTempPath As String, iModuleName As String Dim iVBComponent As Object Dim a As Boolean With Application .ScreenUpdating = False iTempPath = .DefaultFilePath & .PathSeparator With wb.VBProject.VBComponents For Each iVBComponent In ThisWorkbook.VBProject.VBComponents iModuleName$ = iTempPath$ & iVBComponent.Name a = CopyModule(iVBComponent.Name, _ ThisWorkbook.VBProject, _ wb.VBProject, True) Next End With .ScreenUpdating = True End With End Sub
Function CopyModule(ModuleName As String, _ FromVBProject, _ ToVBProject, _ OverwriteExisting As Boolean) As Boolean Dim VBComp As Object 'As VBIDE.VBComponent Dim FName$, CompName$, S$ Dim SlashPos&, ExtPos& Dim TempVBComp 'As VBIDE.VBComponent Dim vbext_pp_locked As Boolean On Error Resume Next Set VBComp = FromVBProject.VBComponents(ModuleName) If Err.Number <> 0 Then CopyModule = False Exit Function End If FName = Environ("Temp") & "\" & ModuleName & ".bas" If OverwriteExisting = True Then If Dir(FName, vbNormal + vbHidden + vbSystem) <> vbNullString Then Err.Clear Kill FName If Err.Number <> 0 Then CopyModule = False Exit Function End If End If With ToVBProject.VBComponents .Remove .Item(ModuleName) End With Else Err.Clear Set VBComp = ToVBProject.VBComponents(ModuleName) If Err.Number <> 0 Then If Err.Number = 9 Then ' module doesn't exist. ignore error. Else ' other error. get out with return value of False CopyModule = False Exit Function End If End If End If FromVBProject.VBComponents(ModuleName).Export Filename:=FName SlashPos = InStrRev(FName, "\") ExtPos = InStrRev(FName, ".") CompName = Mid(FName, SlashPos + 1, ExtPos - SlashPos - 1) Set VBComp = Nothing Set VBComp = ToVBProject.VBComponents(CompName) If VBComp Is Nothing Then ToVBProject.VBComponents.Import Filename:=FName Else Set TempVBComp = ToVBProject.VBComponents.Import(FName) ' TempVBComp is source module With VBComp.CodeModule .DeleteLines 1, .CountOfLines S = TempVBComp.CodeModule.Lines(1, TempVBComp.CodeModule.CountOfLines) .InsertLines 1, S End With On Error GoTo 0 ToVBProject.VBComponents.Remove TempVBComp End If Kill FName CopyModule = True End Function
[/vba]
Вымучил, так работает: [vba]
Код
Sub ReduceSize() Dim lAntR As Long Dim iAntK As Integer Dim aR() As Single Dim aK() As Single Dim n As Integer Dim sFil1 As String Dim sFil2 As String Dim sKat As String Dim sArk As String Dim sh As Worksheet Dim nWb As Workbook Dim i As Integer i = 1 sFil1 = ActiveWorkbook.Name sKat = ActiveWorkbook.Path Set nWb = Workbooks.Add sFil2 = ActiveWorkbook.Name Workbooks(sFil2).SaveAs sKat & "\" & "(2)" & sFil1 sFil2 = ActiveWorkbook.Name For Each sh In ThisWorkbook.Sheets sh.Activate sArk = ActiveSheet.Name lAntR = Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row iAntK = Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
ReDim aR(lAntR) ReDim aK(iAntK) For n = 1 To lAntR aR(n) = Rows(n).RowHeight Next n For n = 1 To iAntK aK(n) = Columns(n).ColumnWidth Next n Application.CutCopyMode = False Range(sh.Cells(1, 1), sh.Cells(lAntR, iAntK)).Copy With nWb If .Sheets.Count < i Then .Sheets.Add after:=.Sheets(.Sheets.Count) End If .Sheets(i).Name = sArk .Sheets(i).Paste '([a1]) Application.CutCopyMode = False For n = 1 To lAntR .Sheets(i).Rows(n).RowHeight = aR(n) Next n For n = 1 To iAntK .Sheets(i).Columns(n).ColumnWidth = aK(n) Next n End With i = i + 1 Next Application.DisplayAlerts = False Call ExportAllStdModules(Workbooks(sFil2)) Workbooks(sFil2).Save Workbooks(sFil1).Close savechanges:=True Application.DisplayAlerts = True End Sub Private Sub ExportAllStdModules(wb As Workbook) Dim iTempPath As String, iModuleName As String Dim iVBComponent As Object Dim a As Boolean With Application .ScreenUpdating = False iTempPath = .DefaultFilePath & .PathSeparator With wb.VBProject.VBComponents For Each iVBComponent In ThisWorkbook.VBProject.VBComponents iModuleName$ = iTempPath$ & iVBComponent.Name a = CopyModule(iVBComponent.Name, _ ThisWorkbook.VBProject, _ wb.VBProject, True) Next End With .ScreenUpdating = True End With End Sub
Function CopyModule(ModuleName As String, _ FromVBProject, _ ToVBProject, _ OverwriteExisting As Boolean) As Boolean Dim VBComp As Object 'As VBIDE.VBComponent Dim FName$, CompName$, S$ Dim SlashPos&, ExtPos& Dim TempVBComp 'As VBIDE.VBComponent Dim vbext_pp_locked As Boolean On Error Resume Next Set VBComp = FromVBProject.VBComponents(ModuleName) If Err.Number <> 0 Then CopyModule = False Exit Function End If FName = Environ("Temp") & "\" & ModuleName & ".bas" If OverwriteExisting = True Then If Dir(FName, vbNormal + vbHidden + vbSystem) <> vbNullString Then Err.Clear Kill FName If Err.Number <> 0 Then CopyModule = False Exit Function End If End If With ToVBProject.VBComponents .Remove .Item(ModuleName) End With Else Err.Clear Set VBComp = ToVBProject.VBComponents(ModuleName) If Err.Number <> 0 Then If Err.Number = 9 Then ' module doesn't exist. ignore error. Else ' other error. get out with return value of False CopyModule = False Exit Function End If End If End If FromVBProject.VBComponents(ModuleName).Export Filename:=FName SlashPos = InStrRev(FName, "\") ExtPos = InStrRev(FName, ".") CompName = Mid(FName, SlashPos + 1, ExtPos - SlashPos - 1) Set VBComp = Nothing Set VBComp = ToVBProject.VBComponents(CompName) If VBComp Is Nothing Then ToVBProject.VBComponents.Import Filename:=FName Else Set TempVBComp = ToVBProject.VBComponents.Import(FName) ' TempVBComp is source module With VBComp.CodeModule .DeleteLines 1, .CountOfLines S = TempVBComp.CodeModule.Lines(1, TempVBComp.CodeModule.CountOfLines) .InsertLines 1, S End With On Error GoTo 0 ToVBProject.VBComponents.Remove TempVBComp End If Kill FName CopyModule = True End Function
А может для модулей листов не импорт делать (ты вроде говоришь, что тогда из модулей листов модули класса получаются?), а тупо по одной в цикле текстом переписывать строки начиная с 1 до CodeModule.CountOfLines? Хотя тогда даже если мы ОЛЕ-объекты листа и сможем скопировать на новый лист, они, наверное, окажутся связанными со старым модулем листа...
А может для модулей листов не импорт делать (ты вроде говоришь, что тогда из модулей листов модули класса получаются?), а тупо по одной в цикле текстом переписывать строки начиная с 1 до CodeModule.CountOfLines? Хотя тогда даже если мы ОЛЕ-объекты листа и сможем скопировать на новый лист, они, наверное, окажутся связанными со старым модулем листа...Alex_ST
Серёга, я твой код как всегда малость "полирнул" для ясности и сделал так, чтобы его можно было разместить в Personal.xls Честно признаюсь: в работе с VBProject и VBComponents я плаваю по поверхности, поэтому там почти ничего не менял. (текст превысил допустимую длину, поэтому попробую приложить в следующем посте)
Ещё недоработку обнаружил: в давно использующихся книгах страницы удаляют/добавляют, переставляют... Поэтому ПРОГРАММНЫЕ номера страниц идут не по порядку и с пропусками. А в новой книге новые страницы создаются в цикле For Each по порядку расположения их ярлыков листов в старой, т.е. по индексу. И после создания автоматом получают очередное программное имя. Т.е. если самым левым в старой книге был лист с программным номером 9, то в новой книге копия этого листа будет иметь и индекс и программный номер 1, код на него не экспортируется, а для кода старого листа 9 в новой книге будет создан модуль класса Лист9. Я у Климова на msoffice.nm.ru посмотрел как изменять кодовые имена листов... Не могу никак присобачить к твоему коду. Хорошо бы, наверное, перед началом обработки перенумеровать программные имена (индексы) страниц в старой книге, а уж потом начинать копировать/экспортировать.
Серёга, я твой код как всегда малость "полирнул" для ясности и сделал так, чтобы его можно было разместить в Personal.xls Честно признаюсь: в работе с VBProject и VBComponents я плаваю по поверхности, поэтому там почти ничего не менял. (текст превысил допустимую длину, поэтому попробую приложить в следующем посте)
Ещё недоработку обнаружил: в давно использующихся книгах страницы удаляют/добавляют, переставляют... Поэтому ПРОГРАММНЫЕ номера страниц идут не по порядку и с пропусками. А в новой книге новые страницы создаются в цикле For Each по порядку расположения их ярлыков листов в старой, т.е. по индексу. И после создания автоматом получают очередное программное имя. Т.е. если самым левым в старой книге был лист с программным номером 9, то в новой книге копия этого листа будет иметь и индекс и программный номер 1, код на него не экспортируется, а для кода старого листа 9 в новой книге будет создан модуль класса Лист9. Я у Климова на msoffice.nm.ru посмотрел как изменять кодовые имена листов... Не могу никак присобачить к твоему коду. Хорошо бы, наверное, перед началом обработки перенумеровать программные имена (индексы) страниц в старой книге, а уж потом начинать копировать/экспортировать.
Sub ReduceSize() Dim LastRow As Long Dim LastColumn As Integer Dim arrRowHeight() As Single Dim arrColumnWidth() As Single Dim newWbk As Workbook Dim oldWbName As String Dim newWbName As String Dim WbPath As String Dim ShtName As String Dim Sht As Worksheet Dim n As Integer Dim i As Integer oldWbName = ActiveWorkbook.Name ' запомним имя старой книги WbPath = ActiveWorkbook.Path ' запомним путь к старой книге Set newWbk = Workbooks.Add ' создадим новую книгу (она сразу станет ActiveWorkbook) ActiveWorkbook.SaveAs WbPath & "\" & "(NEW) " & oldWbName 'сохраним новую книгу рядом со старой с префиксом к имени "(NEW) " newWbName = ActiveWorkbook.Name ' запомним имя новой книги i = 1 ' начинаем с первой страницы новой книги For Each Sht In Workbooks(oldWbName).Sheets ' цикл по всем листам старой книги Sht.Activate With ActiveSheet ShtName = .Name LastRow = .Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row ' последняя строка на листе, содержащая хоть какие-нибудь значения LastColumn = .Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column ' последний столбец на листе, содержащий хоть какие-нибудь значения ReDim arrRowHeight(LastRow) ReDim arrColumnWidth(LastColumn) For n = 1 To LastRow ' запомним высоты строк в массив arrRowHeight(n) = .Rows(n).RowHeight Next n For n = 1 To LastColumn ' запомним ширины столбцов в массив arrColumnWidth(n) = .Columns(n).ColumnWidth Next n Application.CutCopyMode = False Range(.Cells(1, 1), .Cells(LastRow, LastColumn)).Copy ' копируем только диапазон, содержащий данные End With With Workbooks(newWbName) If .Sheets.Count < i Then .Sheets.Add after:=.Sheets(.Sheets.Count) .Sheets(i).Name = ShtName .Sheets(i).Paste ' копируем на страницу новой книги диапазон, содержащий данные Application.CutCopyMode = False For n = 1 To LastRow ' восстановим высоты строк .Sheets(i).Rows(n).RowHeight = arrRowHeight(n) Next n For n = 1 To LastColumn ' восстановим ширины столбцов .Sheets(i).Columns(n).ColumnWidth = arrColumnWidth(n) Next n End With i = i + 1 ' продолжим на следующей странице новой книги Next Application.DisplayAlerts = False Call ExportAllStdModules(newWbk, Workbooks(oldWbName)) ' скопировать все компоненты VBA в новую книгу Workbooks(newWbName).Save Workbooks(oldWbName).Close savechanges:=True Application.DisplayAlerts = True End Sub
[/vba]
продолжение следует
[vba]
Код
Option Explicit Option Base 1
Sub ReduceSize() Dim LastRow As Long Dim LastColumn As Integer Dim arrRowHeight() As Single Dim arrColumnWidth() As Single Dim newWbk As Workbook Dim oldWbName As String Dim newWbName As String Dim WbPath As String Dim ShtName As String Dim Sht As Worksheet Dim n As Integer Dim i As Integer oldWbName = ActiveWorkbook.Name ' запомним имя старой книги WbPath = ActiveWorkbook.Path ' запомним путь к старой книге Set newWbk = Workbooks.Add ' создадим новую книгу (она сразу станет ActiveWorkbook) ActiveWorkbook.SaveAs WbPath & "\" & "(NEW) " & oldWbName 'сохраним новую книгу рядом со старой с префиксом к имени "(NEW) " newWbName = ActiveWorkbook.Name ' запомним имя новой книги i = 1 ' начинаем с первой страницы новой книги For Each Sht In Workbooks(oldWbName).Sheets ' цикл по всем листам старой книги Sht.Activate With ActiveSheet ShtName = .Name LastRow = .Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row ' последняя строка на листе, содержащая хоть какие-нибудь значения LastColumn = .Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column ' последний столбец на листе, содержащий хоть какие-нибудь значения ReDim arrRowHeight(LastRow) ReDim arrColumnWidth(LastColumn) For n = 1 To LastRow ' запомним высоты строк в массив arrRowHeight(n) = .Rows(n).RowHeight Next n For n = 1 To LastColumn ' запомним ширины столбцов в массив arrColumnWidth(n) = .Columns(n).ColumnWidth Next n Application.CutCopyMode = False Range(.Cells(1, 1), .Cells(LastRow, LastColumn)).Copy ' копируем только диапазон, содержащий данные End With With Workbooks(newWbName) If .Sheets.Count < i Then .Sheets.Add after:=.Sheets(.Sheets.Count) .Sheets(i).Name = ShtName .Sheets(i).Paste ' копируем на страницу новой книги диапазон, содержащий данные Application.CutCopyMode = False For n = 1 To LastRow ' восстановим высоты строк .Sheets(i).Rows(n).RowHeight = arrRowHeight(n) Next n For n = 1 To LastColumn ' восстановим ширины столбцов .Sheets(i).Columns(n).ColumnWidth = arrColumnWidth(n) Next n End With i = i + 1 ' продолжим на следующей странице новой книги Next Application.DisplayAlerts = False Call ExportAllStdModules(newWbk, Workbooks(oldWbName)) ' скопировать все компоненты VBA в новую книгу Workbooks(newWbName).Save Workbooks(oldWbName).Close savechanges:=True Application.DisplayAlerts = True End Sub
Private Sub ExportAllStdModules(newWbk As Workbook, oldWbk As Workbook) ' скопировать все компоненты VBA в новую книгу Dim iTempPath As String, iModuleName As String Dim iVBComponent As Object Dim a As Boolean With Application .ScreenUpdating = False iTempPath = .DefaultFilePath & .PathSeparator With newWbk.VBProject.VBComponents For Each iVBComponent In oldWbk.VBProject.VBComponents iModuleName$ = iTempPath$ & iVBComponent.Name a = CopyModule(iVBComponent.Name, _ oldWbk.VBProject, _ newWbk.VBProject, True) Next End With .ScreenUpdating = True End With End Sub
Function CopyModule(ModuleName As String, _ FromVBProject, _ ToVBProject, _ OverwriteExisting As Boolean) As Boolean Dim VBComp As Object 'As VBIDE.VBComponent Dim FName$, CompName$, S$ Dim SlashPos&, ExtPos& Dim TempVBComp 'As VBIDE.VBComponent Dim vbext_pp_locked As Boolean On Error Resume Next Set VBComp = FromVBProject.VBComponents(ModuleName) If Err.Number <> 0 Then CopyModule = False Exit Function End If FName = Environ("Temp") & "\" & ModuleName & ".bas" If OverwriteExisting = True Then If Dir(FName, vbNormal + vbHidden + vbSystem) <> vbNullString Then Err.Clear Kill FName If Err.Number <> 0 Then CopyModule = False Exit Function End If End If With ToVBProject.VBComponents .Remove .Item(ModuleName) End With Else Err.Clear Set VBComp = ToVBProject.VBComponents(ModuleName) If Err.Number <> 0 Then If Err.Number = 9 Then ' module doesn't exist. ignore error. Else ' other error. get out with return value of False CopyModule = False Exit Function End If End If End If FromVBProject.VBComponents(ModuleName).Export FileName:=FName SlashPos = InStrRev(FName, "\") ExtPos = InStrRev(FName, ".") CompName = Mid(FName, SlashPos + 1, ExtPos - SlashPos - 1) Set VBComp = Nothing Set VBComp = ToVBProject.VBComponents(CompName) If VBComp Is Nothing Then ToVBProject.VBComponents.Import FileName:=FName Else Set TempVBComp = ToVBProject.VBComponents.Import(FName) ' TempVBComp is source module With VBComp.CodeModule .DeleteLines 1, .CountOfLines S = TempVBComp.CodeModule.Lines(1, TempVBComp.CodeModule.CountOfLines) .InsertLines 1, S End With On Error GoTo 0 ToVBProject.VBComponents.Remove TempVBComp End If Kill FName CopyModule = True End Function
[/vba]
продолжение: [vba]
Код
Private Sub ExportAllStdModules(newWbk As Workbook, oldWbk As Workbook) ' скопировать все компоненты VBA в новую книгу Dim iTempPath As String, iModuleName As String Dim iVBComponent As Object Dim a As Boolean With Application .ScreenUpdating = False iTempPath = .DefaultFilePath & .PathSeparator With newWbk.VBProject.VBComponents For Each iVBComponent In oldWbk.VBProject.VBComponents iModuleName$ = iTempPath$ & iVBComponent.Name a = CopyModule(iVBComponent.Name, _ oldWbk.VBProject, _ newWbk.VBProject, True) Next End With .ScreenUpdating = True End With End Sub
Function CopyModule(ModuleName As String, _ FromVBProject, _ ToVBProject, _ OverwriteExisting As Boolean) As Boolean Dim VBComp As Object 'As VBIDE.VBComponent Dim FName$, CompName$, S$ Dim SlashPos&, ExtPos& Dim TempVBComp 'As VBIDE.VBComponent Dim vbext_pp_locked As Boolean On Error Resume Next Set VBComp = FromVBProject.VBComponents(ModuleName) If Err.Number <> 0 Then CopyModule = False Exit Function End If FName = Environ("Temp") & "\" & ModuleName & ".bas" If OverwriteExisting = True Then If Dir(FName, vbNormal + vbHidden + vbSystem) <> vbNullString Then Err.Clear Kill FName If Err.Number <> 0 Then CopyModule = False Exit Function End If End If With ToVBProject.VBComponents .Remove .Item(ModuleName) End With Else Err.Clear Set VBComp = ToVBProject.VBComponents(ModuleName) If Err.Number <> 0 Then If Err.Number = 9 Then ' module doesn't exist. ignore error. Else ' other error. get out with return value of False CopyModule = False Exit Function End If End If End If FromVBProject.VBComponents(ModuleName).Export FileName:=FName SlashPos = InStrRev(FName, "\") ExtPos = InStrRev(FName, ".") CompName = Mid(FName, SlashPos + 1, ExtPos - SlashPos - 1) Set VBComp = Nothing Set VBComp = ToVBProject.VBComponents(CompName) If VBComp Is Nothing Then ToVBProject.VBComponents.Import FileName:=FName Else Set TempVBComp = ToVBProject.VBComponents.Import(FName) ' TempVBComp is source module With VBComp.CodeModule .DeleteLines 1, .CountOfLines S = TempVBComp.CodeModule.Lines(1, TempVBComp.CodeModule.CountOfLines) .InsertLines 1, S End With On Error GoTo 0 ToVBProject.VBComponents.Remove TempVBComp End If Kill FName CopyModule = True End Function
Public Sub www() Dim Sh As Object, iCodeName$ For Each Sh In Sheets iCodeName = Sh.CodeName Application.VBE.ActiveVBProject.VBComponents(iCodeName).Name = Sh.Name Next End Sub
[/vba]
[vba]
Код
Public Sub www() Dim Sh As Object, iCodeName$ For Each Sh In Sheets iCodeName = Sh.CodeName Application.VBE.ActiveVBProject.VBComponents(iCodeName).Name = Sh.Name Next End Sub