Макрос на работу с ячейкой excel

Всё о работе с ячейками в Excel-VBA: обращение, перебор, удаление, вставка, скрытие, смена имени.

Содержание:

Table of Contents:

  • Что такое ячейка Excel?
  • Способы обращения к ячейкам
    • Выбор и активация
    • Получение и изменение значений ячеек
      • Ячейки открытой книги
      • Ячейки закрытой книги 
    • Перебор ячеек
    • Перебор в произвольном диапазоне
  • Свойства и методы ячеек
    • Имя ячейки
    • Адрес ячейки
    • Размеры ячейки
  • Запуск макроса активацией ячейки

2 нюанса:

  1. Я почти везде стараюсь использовать ThisWorkbook (а не, например, ActiveWorkbook) для обращения к текущей книге, в которой написан этот код (считаю это наиболее безопасным для новичков способом обращения к книгам, чтобы случайно не внести изменения в другие книги). Для экспериментов можете вставлять этот код в модули, коды книги, либо листа, и он будет работать только в пределах этой книги. 
  2. Я использую английский эксель и у меня по стандарту листы называются Sheet1, Sheet2 и т.д. Если вы работаете в русском экселе, то замените Thisworkbook.Sheets(«Sheet1») на Thisworkbook.Sheets(«Лист1»). Если этого не сделать, то вы получите ошибку в связи с тем, что пытаетесь обратиться к несуществующему объекту. Можно также заменить на Thisworkbook.Sheets(1), но это менее безопасно.

Что такое ячейка Excel?

В большинстве мест пишут: «элемент, образованный пересечением столбца и строки». Это определение полезно для людей, которые не знакомы с понятием «таблица». Для того, чтобы понять чем на самом деле является ячейка Excel, необходимо заглянуть в объектную модель Excel. При этом определения объектов «ряд», «столбец» и «ячейка» будут отличаться в зависимости от того, как мы работаем с файлом.

Объекты в Excel-VBA. Пока мы работаем в Excel без углубления в VBA определение ячейки как «пересечения» строк и столбцов нам вполне хватает, но если мы решаем как-то автоматизировать процесс в VBA, то о нём лучше забыть и просто воспринимать лист как «мешок» ячеек, с каждой из которых VBA позволяет работать как минимум тремя способами:

  1. по цифровым координатам (ряд, столбец),
  2. по адресам формата А1, B2 и т.д. (сценарий целесообразности данного способа обращения в VBA мне сложно представить)
  3. по уникальному имени (во втором и третьем вариантах мы будем иметь дело не совсем с ячейкой, а с объектом VBA range, который может состоять из одной или нескольких ячеек). Функции и методы объектов Cells и Range отличаются. Новичкам я бы порекомендовал работать с ячейками VBA только с помощью Cells и по их цифровым координатам и использовать Range только по необходимости.

Все три способа обращения описаны далее

Как это хранится на диске и как с этим работать вне Excel? С точки зрения хранения и обработки вне Excel и VBA. Сделать это можно, например, сменив расширение файла с .xls(x) на .zip и открыв этот архив.

Пример содержимого файла Excel:

Далее xl -> worksheets и мы видим файл листа

Содержимое файла:

 То же, но более наглядно:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac xr xr2 xr3" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:xr2="http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" xmlns:xr3="http://schemas.microsoft.com/office/spreadsheetml/2016/revision3" xr:uid="{00000000-0001-0000-0000-000000000000}">
	<dimension ref="B2:F6"/>
	<sheetViews>
		<sheetView tabSelected="1" workbookViewId="0">
			<selection activeCell="D12" sqref="D12"/>
		</sheetView>
	</sheetViews>
	<sheetFormatPr defaultRowHeight="14.4" x14ac:dyDescent="0.3"/>
	<sheetData>
		<row r="2" spans="2:6" x14ac:dyDescent="0.3">
			<c r="B2" t="s">
				<v>0</v>
			</c>
		</row>
		<row r="3" spans="2:6" x14ac:dyDescent="0.3">
			<c r="C3" t="s">
				<v>1</v>
			</c>
		</row>
		<row r="4" spans="2:6" x14ac:dyDescent="0.3">
			<c r="D4" t="s">
				<v>2</v>
			</c>
		</row>
		<row r="5" spans="2:6" x14ac:dyDescent="0.3">
			<c r="E5" t="s">
				<v>0</v></c>
		</row>
		<row r="6" spans="2:6" x14ac:dyDescent="0.3">
			<c r="F6" t="s"><v>3</v>
		</c></row>
	</sheetData>
	<pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/>
</worksheet>

Как мы видим, в структуре объектной модели нет никаких «пересечений». Строго говоря рабочая книга — это архив структурированных данных в формате XML. При этом в каждую «строку» входит «столбец», и в нём в свою очередь прописан номер значения данного столбца, по которому оно подтягивается из другого XML файла при открытии книги для экономии места за счёт отсутствия повторяющихся значений. Почему это важно. Если мы захотим написать какой-то обработчик таких файлов, который будет напрямую редактировать данные в этих XML, то ориентироваться надо на такую модель и структуру данных. И правильное определение будет примерно таким: ячейка — это объект внутри столбца, который в свою очередь находится внутри строки в файле xml, в котором хранятся данные о содержимом листа.

Способы обращения к ячейкам

Выбор и активация

Почти во всех случаях можно и стоит избегать использования методов Select и Activate. На это есть две причины:

  1. Это лишь имитация действий пользователя, которая замедляет выполнение программы. Работать с объектами книги можно напрямую без использования методов Select и Activate.
  2. Это усложняет код и может приводить к неожиданным последствиям. Каждый раз перед использованием Select необходимо помнить, какие ещё объекты были выбраны до этого и не забывать при необходимости снимать выбор. Либо, например, в случае использования метода Select в самом начале программы может быть выбрано два листа вместо одного потому что пользователь запустил программу, выбрав другой лист.

Можно выбирать и активировать книги, листы, ячейки, фигуры, диаграммы, срезы, таблицы и т.д.

Отменить выбор  ячеек можно методом Unselect:

Selection.Unselect

Отличие выбора от активации — активировать можно только один объект из раннее выбранных. Выбрать можно несколько объектов.

Если вы записали и редактируете код макроса, то лучше всего заменить Select и Activate на конструкцию With … End With. Например, предположим, что мы записали вот такой макрос:

Sub Macro1()
' Macro1 Macro
    Range("F4:F10,H6:H10").Select 'выбрали два несмежных диапазона зажав ctrl
    Range("H6").Activate          'показывает только то, что я начал выбирать второй диапазон с этой ячейки (она осталась белой). Это действие ни на что не влияет
    With Selection.Interior       
        .Pattern = xlSolid
        .PatternColorIndex = xlAutomatic
        .Color = 65535            'залили желтым цветом, нажав на кнопку заливки на верхней панели
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
End Sub

Почему макрос записался таким неэффективным образом? Потому что в каждый момент времени (в каждой строке) программа не знает, что вы будете делать дальше. Поэтому в записи выбор ячеек и действия с ними — это два отдельных действия. Этот код лучше всего оптимизировать (особенно если вы хотите скопировать его внутрь какого-нибудь цикла, который должен будет исполняться много раз и перебирать много объектов). Например, так:

Sub Macro11()
'
' Macro1 Macro
    Range("F4:F10,H6:H10").Select '1. смотрим, что за объект выбран (что идёт до .Select)
    Range("H6").Activate
    With Selection.Interior       '2. понимаем, что у выбранного объекта есть свойство interior, с которым далее идёт работа
        .Pattern = xlSolid
        .PatternColorIndex = xlAutomatic
        .Color = 65535
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
End Sub



Sub Optimized_Macro()
    With Range("F4:F10,H6:H10").Interior '3. переносим объект напрямую в конструкцию With вместо Selection
' ////// Здесь я для надёжности прописал бы ещё Thisworkbook.Sheet("ИмяЛиста") перед Range,
' ////// чтобы минимизировать риск любых случайных изменений других листов и книг
' ////// With Thisworkbook.Sheet("ИмяЛиста").Range("F4:F10,H6:H10").Interior
        .Pattern = xlSolid               '4. полностью копируем всё, что было записано рекордером внутрь блока with
        .PatternColorIndex = xlAutomatic
        .Color = 55555                   '5. здесь я поменял цвет на зеленый, чтобы было видно, работает ли код при поочерёдном запуске двух макросов
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
End Sub

Пример сценария, когда использование Select и Activate оправдано:

Допустим, мы хотим, чтобы во время исполнения программы мы одновременно изменяли несколько листов одним действием и пользователь видел какой-то определённый лист. Это можно сделать примерно так:

Sub Select_Activate_is_OK()
Thisworkbook.Worksheets(Array("Sheet1", "Sheet3")).Select 'Выбираем несколько листов по именам
Thisworkbook.Worksheets("Sheet3").Activate 'Показываем пользователю третий лист
'Далее все действия с выбранными ячейками через Select будут одновременно вносить изменения в оба выбранных листа

'Допустим, что тут мы решили покрасить те же два диапазона:
Range("F4:F10,H6:H10").Select
    Range("H6").Activate
    With Selection.Interior       
        .Pattern = xlSolid
        .PatternColorIndex = xlAutomatic
        .Color = 65535
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With

End Sub

Единственной причиной использовать этот код по моему мнению может быть желание зачем-то показать пользователю определённую страницу книги в какой-то момент исполнения программы. С точки зрения обработки объектов, опять же, эти действия лишние.

Получение и изменение значений ячеек

Значение ячеек можно получать/изменять с помощью свойства value. 

'Если нужно прочитать / записать значение ячейки, то используется свойство Value
a = ThisWorkbook.Sheets("Sheet1").Cells (1,1).Value 'записать значение ячейки А1 листа "Sheet1" в переменную "a"
ThisWorkbook.Sheets("Sheet1").Cells (1,1).Value = 1  'задать значение ячейки А1 (первый ряд, первый столбец) листа "Sheet1"

'Если нужно прочитать текст как есть (с форматированием), то можно использовать свойство .text:
ThisWorkbook.Sheets("Sheet1").Cells (1,1).Text = "1" 
a = ThisWorkbook.Sheets("Sheet1").Cells (1,1).Text

'Когда проявится разница:
'Например, если мы считываем дату в формате "31 декабря 2021 г.", хранящуюся как дата
a = ThisWorkbook.Sheets("Sheet1").Cells (1,1).Value 'эапишет как "31.12.2021"
a = ThisWorkbook.Sheets("Sheet1").Cells (1,1).Text  'запишет как "31 декабря 2021 г."

Ячейки открытой книги

К ячейкам можно обращаться:

'В книге, в которой хранится макрос (на каком-то из листов, либо в отдельном модуле или форме)
ThisWorkbook.Sheets("Sheet1").Cells(1,1).Value        'По номерам строки и столбца
ThisWorkbook.Sheets("Sheet1").Cells(1,"A").Value      'По номерам строки и букве столбца
ThisWorkbook.Sheets("Sheet1").Range("A1").Value       'По адресу - вариант 1
ThisWorkbook.Sheets("Sheet1").[A1].Value              'По адресу - вариант 2
ThisWorkbook.Sheets("Sheet1").Range("CellName").Value 'По имени ячейки (для этого ей предварительно нужно его присвоить)

'Те же действия, но с использованием полного названия рабочей книги (книга должна быть открыта)
Workbooks("workbook.xlsm").Sheets("Sheet1").Cells(1,1).Value 'По номерам строки и столбца
Workbooks("workbook.xlsm").Sheets("Sheet1").Cells(1,"A").Value                'По номерам строки и букве столбца
Workbooks("workbook.xlsm").Sheets("Sheet1").Range("A1").Value                 'По адресу - вариант 1
Workbooks("workbook.xlsm").Sheets("Sheet1").[A1].Value                        'По адресу - вариант 2
Workbooks("workbook.xlsm").Sheets("Sheet1").Range("CellName").Value           'По имени ячейки (для этого ей предварительно нужно его присвоить)

Ячейки закрытой книги

Если нужно достать или изменить данные в другой закрытой книге, то необходимо прописать открытие и закрытие книги. Непосредственно работать с закрытой книгой не получится, потому что данные в ней хранятся отдельно от структуры и при открытии Excel каждый раз производит расстановку значений по соответствующим «слотам» в структуре. Подробнее о том, как хранятся данные в xlsx см выше.

Workbooks.Open Filename:="С:closed_workbook.xlsx"    'открыть книгу (она становится активной)
a = ActiveWorkbook.Sheets("Sheet1").Cells(1,1).Value  'достать значение ячейки 1,1
ActiveWorkbook.Close False                            'закрыть книгу (False => без сохранения)

Скачать пример, в котором можно посмотреть, как доставать и как записывать значения в закрытую книгу. 

Код из файла:

Option Explicit
Sub get_value_from_closed_wb() 'достать значение из закрытой книги
Dim a, wb_path, wsh As String
wb_path = ThisWorkbook.Sheets("Sheet1").Cells(2, 3).Value 'get path to workbook from sheet1
wsh = ThisWorkbook.Sheets("Sheet1").Cells(3, 3).Value
Workbooks.Open Filename:=wb_path
a = ActiveWorkbook.Sheets(wsh).Cells(3, 3).Value
ActiveWorkbook.Close False
ThisWorkbook.Sheets("Sheet1").Cells(4, 3).Value = a
End Sub

Sub record_value_to_closed_wb() 'записать значение в закрытую книгу
Dim wb_path, b, wsh As String
wsh = ThisWorkbook.Sheets("Sheet1").Cells(3, 3).Value
wb_path = ThisWorkbook.Sheets("Sheet1").Cells(2, 3).Value 'get path to workbook from sheet1
b = ThisWorkbook.Sheets("Sheet1").Cells(5, 3).Value 'get value to record in the target workbook
Workbooks.Open Filename:=wb_path
ActiveWorkbook.Sheets(wsh).Cells(4, 4).Value = b 'add new value to cell D4 of the target workbook
ActiveWorkbook.Close True
End Sub

Перебор ячеек

Перебор в произвольном диапазоне

Скачать файл со всеми примерами

Пройтись по всем ячейкам в нужном диапазоне можно разными способами. Основные:

  1. Цикл For Each. Пример:
    Sub iterate_over_cells()
    
    For Each c In ThisWorkbook.Sheets("Sheet1").Range("B2:D4").Cells
    MsgBox (c)
    Next c
    
    End Sub​

    Этот цикл выведет в виде сообщений значения ячеек в диапазоне B2:D4 по порядку по строкам слева направо и по столбцам — сверху вниз. Данный способ можно использовать для действий, в который вам не важны номера ячеек (закрашивание, изменение форматирования, пересчёт чего-то и т.д.).

  2. Ту же задачу можно решить с помощью двух вложенных циклов — внешний будет перебирать ряды, а вложенный — ячейки в рядах. Этот способ я использую чаще всего, потому что он позволяет получить больше контроля над исполнением: на каждой итерации цикла нам доступны координаты ячеек. Для перебора всех ячеек на листе этим методом потребуется найти последнюю заполненную ячейку. Пример кода:
    Sub iterate_over_cells()
    
    Dim cl, rw As Integer
    Dim x As Variant
    
    'перебор области 3x3
    For rw = 1 To 3 ' цикл для перебора рядов 1-3
    
        For cl = 1 To 3 'цикл для перебора столбцов 1-3
            x = ThisWorkbook.Sheets("Sheet1").Cells(rw + 1, cl + 1).Value
            MsgBox (x)
        Next cl
    Next rw
    
    
    
    'перебор всех ячеек на листе. Последняя ячейка определена с помощью UsedRange
    'LastRow = ActiveSheet.UsedRange.Row + ActiveSheet.UsedRange.Rows.Count - 1
    'LastCol = ActiveSheet.UsedRange.Column + ActiveSheet.UsedRange.Columns.Count - 1
    'For rw = 1 To LastRow 'цикл перебора всех рядов
    '    For cl = 1 To LastCol 'цикл для перебора всех столбцов
    '        Действия 
    '    Next cl
    'Next rw
    
    
    End Sub​
  3. Если нужно перебрать все ячейки в выделенном диапазоне на активном листе, то код будет выглядеть так:
    Sub iterate_cell_by_cell_over_selection()
        Dim ActSheet As Worksheet
        Dim SelRange As Range
        Dim cell As Range
        
     
        Set ActSheet = ActiveSheet
        Set SelRange = Selection
        
        'if we want to do it in every cell of the selected range
        For Each cell In Selection
        MsgBox (cell.Value)
        
        Next cell
    
    End Sub​

    Данный метод подходит для интерактивных макросов, которые выполняют действия над выбранными пользователем областями.

  4. Перебор ячеек в ряду
    Sub iterate_cells_in_row()
        Dim i, RowNum, StartCell As Long
        
        RowNum = 3 'какой ряд
        StartCell = 0 ' номер начальной ячейки (минус 1, т.к. в цикле мы прибавляем i)
        
        For i = 1 To 10 ' 10 ячеек в выбранном ряду
        ThisWorkbook.Sheets("Sheet1").Cells(RowNum, i + StartCell).Value = i '(i + StartCell) добавляет 1 к номеру столбца при каждом повторении
        Next i
    
    End Sub
  5. Перебор ячеек в столбце
    Sub iterate_cells_in_column()
        Dim i, ColNum, StartCell As Long
        
        ColNum = 3 'какой столбец
        StartCell = 0 ' номер начальной ячейки (минус 1, т.к. в цикле мы прибавляем i)
        
        For i = 1 To 10 ' 10 ячеек
        ThisWorkbook.Sheets("Sheet1").Cells(i + StartCell, ColNum).Value = i ' (i + StartCell) добавляет 1 к номеру ряда при каждом повторении
        Next i
    
    End Sub​

Свойства и методы ячеек

Имя ячейки

Присвоить новое имя можно так:

Thisworkbook.Sheets(1).Cells(1,1).name = "Новое_Имя"

Для того, чтобы сменить имя ячейки нужно сначала удалить существующее имя, а затем присвоить новое. Удалить имя можно так:

ActiveWorkbook.Names("Старое_Имя").Delete

Пример кода для переименования ячеек:

Sub rename_cell()

old_name = "Cell_Old_Name"
new_name = "Cell_New_Name"

ActiveWorkbook.Names(old_name).Delete
ThisWorkbook.Sheets(1).Cells(2, 1).Name = new_name
End Sub

Sub rename_cell_reverse()

old_name = "Cell_New_Name"
new_name = "Cell_Old_Name"

ActiveWorkbook.Names(old_name).Delete
ThisWorkbook.Sheets(1).Cells(2, 1).Name = new_name
End Sub

Адрес ячейки

Sub get_cell_address() ' вывести адрес ячейки в формате буква столбца, номер ряда
  '$A$1 style
  txt_address = ThisWorkbook.Sheets(1).Cells(3, 2).Address
  MsgBox (txt_address)
End Sub

Sub get_cell_address_R1C1()' получить адрес столбца в формате номер ряда, номер столбца
  'R1C1 style
  txt_address = ThisWorkbook.Sheets(1).Cells(3, 2).Address(ReferenceStyle:=xlR1C1)
  MsgBox (txt_address)
End Sub

  'пример функции, которая принимает 2 аргумента: название именованного диапазона и тип желаемого адреса 
  '(1- тип $A$1 2- R1C1 - номер ряда, столбца)
Function get_cell_address_by_name(str As String, address_type As Integer)
  '$A$1 style
  Select Case address_type
    Case 1
      txt_address = Range(str).Address
    Case 2
      txt_address = Range(str).Address(ReferenceStyle:=xlR1C1)
    Case Else
      txt_address = "Wrong address type selected. 1,2 available"
    End Select
  get_cell_address_by_name = txt_address
End Function

'перед запуском нужно убедиться, что в книге есть диапазон с названием, 
'адрес которого мы хотим получить, иначе будет ошибка
Sub test_function() 'запустите эту программу, чтобы увидеть, как работает функция
  x = get_cell_address_by_name("MyValue", 2)
  MsgBox (x)
End Sub

Размеры ячейки

Ширина и длина ячейки в VBA меняется, например, так:

Sub change_size()
Dim x, y As Integer
Dim w, h As Double

'получить координаты целевой ячейки
x = ThisWorkbook.Sheets("Sheet1").Cells(2, 2).Value
y = ThisWorkbook.Sheets("Sheet1").Cells(3, 2).Value

'получить желаемую ширину и высоту ячейки
w = ThisWorkbook.Sheets("Sheet1").Cells(6, 2).Value
h = ThisWorkbook.Sheets("Sheet1").Cells(7, 2).Value

'сменить высоту и ширину ячейки с координатами x,y
ThisWorkbook.Sheets("Sheet1").Cells(x, y).RowHeight = h
ThisWorkbook.Sheets("Sheet1").Cells(x, y).ColumnWidth = w


End Sub

Прочитать значения ширины и высоты ячеек можно двумя способами (однако результаты будут в разных единицах измерения). Если написать просто Cells(x,y).Width или Cells(x,y).Height, то будет получен результат в pt (привязка к размеру шрифта). 

Sub get_size()
Dim x, y As Integer
'получить координаты ячейки, с которой мы будем работать
x = ThisWorkbook.Sheets("Sheet1").Cells(2, 2).Value
y = ThisWorkbook.Sheets("Sheet1").Cells(3, 2).Value

'получить длину и ширину выбранной ячейки в тех же единицах измерения, в которых мы их задавали
ThisWorkbook.Sheets("Sheet1").Cells(2, 6).Value = ThisWorkbook.Sheets("Sheet1").Cells(x, y).ColumnWidth
ThisWorkbook.Sheets("Sheet1").Cells(3, 6).Value = ThisWorkbook.Sheets("Sheet1").Cells(x, y).RowHeight

'получить длину и ширину с помощью свойств ячейки (только для чтения) в поинтах (pt)
ThisWorkbook.Sheets("Sheet1").Cells(7, 9).Value = ThisWorkbook.Sheets("Sheet1").Cells(x, y).Width
ThisWorkbook.Sheets("Sheet1").Cells(8, 9).Value = ThisWorkbook.Sheets("Sheet1").Cells(x, y).Height

End Sub

Скачать файл с примерами изменения и чтения размера ячеек

Запуск макроса активацией ячейки

Для запуска кода VBA при активации ячейки необходимо вставить в код листа нечто подобное:

3 важных момента, чтобы это работало:

1. Этот код должен быть вставлен в код листа (здесь контролируется диапазон D4)

2-3. Программа, ответственная за запуск кода при выборе ячейки, должна называться Worksheet_SelectionChange и должна принимать значение переменной Target, относящейся к триггеру SelectionChange. Другие доступные триггеры можно посмотреть в правом верхнем углу (2).

Скачать файл с базовым примером (как на картинке)

Скачать файл с расширенным примером (код ниже)

Option Explicit

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

        ' имеем в виду, что триггер SelectionChange будет запускать эту Sub после каждого клика мышью (после каждого клика будет проверяться:
          '1. количество выделенных ячеек и 
          '2. не пересекается ли выбранный диапазон с заданным в этой программе диапазоном.
        ' поэтому в эту программу не стоит без необходимости писать никаких других тяжелых операций

    If Selection.Count = 1 Then 'запускаем программу только если выбрано не более 1 ячейки


    'вариант модификации - брать адрес ячейки из другой ячейки:
    'Dim CellName as String
    'CellName = Activesheet.Cells(1,1).value 'брать текстовое имя контролируемой ячейки из A1 (должно быть в формате Буква столбца + номер строки)
    'If Not Intersect(Range(CellName), Target) Is Nothing Then
    'для работы этой модификации следующую строку надо закомментировать/удалить



        If Not Intersect(Range("D4"), Target) Is Nothing Then 
        'если заданный (D4) и выбранный диапазон пересекаются 
        '(пересечение диапазонов НЕ равно Nothing)

        'можно прописать диапазон из нескольких ячеек:
        'If Not Intersect(Range("D4:E10"), Target) Is Nothing Then
        'можно прописать несколько диапазонов:
        'If Not Intersect(Range("D4:E10"), Target) Is Nothing or Not Intersect(Range("A4:A10"), Target) Is Nothing Then

            Call program 'выполняем программу
        End If
    End If
End Sub

Sub program()

MsgBox ("Program Is running") 'здесь пишем код того, что произойдёт при выборе нужной ячейки


End Sub

Обращение к ячейке на листе Excel из кода VBA по адресу, индексу и имени. Чтение информации из ячейки. Очистка значения ячейки. Метод ClearContents объекта Range.

Обращение к ячейке по адресу

Допустим, у нас есть два открытых файла: «Книга1» и «Книга2», причем, файл «Книга1» активен и в нем находится исполняемый код VBA.

В общем случае при обращении к ячейке неактивной рабочей книги «Книга2» из кода файла «Книга1» прописывается полный путь:

Workbooks(«Книга2.xlsm»).Sheets(«Лист2»).Range(«C5»)

Workbooks(«Книга2.xlsm»).Sheets(«Лист2»).Cells(5, 3)

Workbooks(«Книга2.xlsm»).Sheets(«Лист2»).Cells(5, «C»)

Workbooks(«Книга2.xlsm»).Sheets(«Лист2»).[C5]

Удобнее обращаться к ячейке через свойство рабочего листа Cells(номер строки, номер столбца), так как вместо номеров строк и столбцов можно использовать переменные. Обратите внимание, что при обращении к любой рабочей книге, она должна быть открыта, иначе произойдет ошибка. Закрытую книгу перед обращением к ней необходимо открыть.

Теперь предположим, что у нас в активной книге «Книга1» активны «Лист1» и ячейка на нем «A1». Тогда обращение к ячейке «A1» можно записать следующим образом:

ActiveCell

Range(«A1»)

Cells(1, 1)

Cells(1, «A»)

[A1]

Точно также можно обращаться и к другим ячейкам активного рабочего листа, кроме обращения ActiveCell, так как активной может быть только одна ячейка, в нашем примере – это ячейка «A1».

Если мы обращаемся к ячейке на неактивном листе активной рабочей книги, тогда необходимо указать этот лист:

‘по основному имени листа

Лист2.Cells(2, 7)

‘по имени ярлыка

Sheets(«Имя ярлыка»).Cells(3, 8)

Имя ярлыка может совпадать с основным именем листа. Увидеть эти имена можно в окне редактора VBA в проводнике проекта. Без скобок отображается основное имя листа, в скобках – имя ярлыка.

Обращение к ячейке по индексу

К ячейке на рабочем листе можно обращаться по ее индексу (порядковому номеру), который считается по расположению ячейки на листе слева-направо и сверху-вниз.

Например, индекс ячеек в первой строке равен номеру столбца. Индекс ячеек во второй строке равен количеству ячеек в первой строке (которое равно общему количеству столбцов на листе, зависящему от версии Excel) плюс номер столбца. Индекс ячеек в третьей строке равен количеству ячеек в двух первых строках плюс номер столбца. И так далее.

Для примера, Cells(4) та же ячейка, что и Cells(1, 4). Используется такое обозначение редко, тем более, что у разных версий Excel может быть разным количество столбцов и строк на рабочем листе.

По индексу можно обращаться к ячейке не только на всем рабочем листе, но и в отдельном диапазоне. Нумерация ячеек осуществляется в пределах заданного диапазона по тому же правилу: слева-направо и сверху-вниз. Вот индексы ячеек диапазона Range(«A1:C3»):

Индексы ячеек в диапазоне Range("A1:C3")

Обращение к ячейке Range("A1:C3").Cells(5) соответствует выражению Range("B2").

Обращение к ячейке по имени

Если ячейке на рабочем листе Excel присвоено имя (Формулы –> Присвоить имя), то обращаться к ней можно по присвоенному имени.

Допустим одной из ячеек присвоено имя – «Итого», тогда обратиться к ней можно – Range("Итого").

Запись информации в ячейку

Содержание ячейки определяется ее свойством «Value», которое в VBA Excel является свойством по умолчанию и его можно явно не указывать. Записывается информация в ячейку при помощи оператора присваивания «=»:

Cells(2, 4).Value = 15

Cells(2, 4) = 15

Range(«A1») = «Этот текст записываем в ячейку»

ActiveCell = 28 + 10*36

Вместе с числами и текстом можно использовать переменные. Примеры здесь и ниже приведены для активного листа. Для неактивных листов дополнительно необходимо указывать имя листа, как в разделе «Обращение к ячейке».

Чтение информации из ячейки

Считать информацию из ячейки в переменную можно также при помощи оператора присваивания «=»:

Sub Test()

Dim a1 As Integer, a2 As Integer, a3 As Integer

Range(«A3») = 6

Cells(2, 5) = 15

a1 = Range(«A3»)

a2 = Cells(2, 5)

a3 = a1 * a2

MsgBox a3

End Sub

Точно также можно обмениваться информацией между ячейками:

Cells(2, 2) = Range(«A4»)

Очистка значения ячейки

Очищается ячейка от значения с помощью метода ClearContents. Кроме того, можно присвоить ячейке значение нуля. пустой строки или Empty:

Cells(10, 2).ClearContents

Range(«D23») = 0

ActiveCell = «»

Cells(5, «D») = Empty

Содержание

  1. Как записать макрос в Excel? Пошаговая инструкция.
  2. Что такое макрос?
  3. Отображение вкладки «Разработчик» в ленте меню
  4. Запись макроса в Excel
  5. Что записывает макрос?
  6. Абсолютная и относительная запись макроса
  7. Что нельзя сделать с помощью макрорекодера?
  8. Расширение файлов Excel, которые содержат макросы

Как записать макрос в Excel? Пошаговая инструкция.

Что такое макрос?

Для начала немного о терминологии.

Макрос — это код, написанный на встроенном в Excel языке VBA (Visual Basic for Application). Макросы могут создаваться как вручную, так и записываться автоматически с помощью так называемого макрорекодера.

Макрорекодер — это инструмент в Excel, который пошагово записывает все что вы выполняете в Excel и преобразует это в код на языке VBA. Макрорекодер создает очень подробный код (как мы увидим позже), который вы сможете при необходимости отредактировать в дальнейшем.

Записанный макрос можно будет запускать неограниченное количество раз и Excel повторит все записанные шаги. Это означает, что даже если вы ничего не знаете о VBA, вы можете автоматизировать некоторые задачи, просто записав свои шаги и затем повторно использовать их позже.

Теперь давайте погрузимся и посмотрим, как записать макрос в Excel.

Отображение вкладки «Разработчик» в ленте меню

Перед тем как записывать макрос, нужно добавить на ленту меню Excel вкладку «Разработчик». Для этого выполните следующие шаги:

  1. Щелкните правой кнопкой мыши по любой из существующих вкладок на ленте и нажмите «Настроить ленту». Он откроет диалоговое окно «Параметры Excel».
  2. В диалоговом окне «Параметры Excel» у вас будут параметры «Настроить ленту». Справа на панели «Основные вкладки» установите флажок «Разработчик».
  3. Нажмите «ОК».

В результате на ленте меню появится вкладка «Разработчик»

Запись макроса в Excel

Теперь давайте запишем очень простой макрос, который выбирает ячейку и вводит в нее текст, например «Excel».

Вот шаги для записи такого макроса:

  1. Перейдите на вкладку «Разработчик».
  2. В группе «Код» нажмите кнопку «Запись макроса». Откроется одноименное диалоговое окно.
  3. В диалоговом окне «Запись макроса» введите имя для своего макроса, например «ВводТекста». Есть несколько условий именования, которые необходимо соблюдать при назначении макроса. Например, вы не можете использовать пробелы между ними. Обычно я предпочитаю сохранять имена макросов как одно слово, с разными частями с заглавным первым алфавитом. Вы также можете использовать подчеркивание для разделения двух слов — например, «Ввод_текста».
  4. Если вы хотите, то можете задать сочетание клавиш. В этом случае мы будем использовать ярлык Ctrl + Shift + N. Помните, что сочетание, которое вы указываете, будет отменять любые существующие горячие клавиши в вашей книге. Например, если вы назначили сочетание Ctrl + S, вы не сможете использовать это для сохранения рабочей книги (вместо этого, каждый раз, когда вы его используете, он выполняет макрос).
  5. В поле «Сохранить в» убедитесь, что выбрана опция «Эта книга». Этот шаг гарантирует, что макрос является частью рабочей книги. Он будет там, когда вы сохраните его и снова откроете, или даже если вы поделитесь файлом с кем-то.
  6. Введите описание при необходимости. Обычно я этого не делаю, но если у вас много макросов, лучше указать, чтобы в будущем не забыть что делает макрос.
  7. Нажмите «ОК». Как только вы нажмете OK, Excel начнет записывать ваши действия. Вы можете увидеть кнопку «Остановить запись» на вкладке «Разработчик», которая указывает, что выполняется запить макроса.
  8. Выберите ячейку A2.
  9. Введите текст «Excel» (или вы можете использовать свое имя).
  10. Нажмите клавишу Enter. Вы попадете на ячейку A3.
  11. Нажмите кнопку «Остановить запись» на вкладке «Разработчик».

Поздравляем! Вы только что записали свой первый макрос в Excel. Хотя макрос не делает ничего полезного, но он поможет нам понять как работает макрорекордер в Excel.

Теперь давайте рассмотрим код который записал макрорекодер. Выполните следующие действия, чтобы открыть редактор кода:

  1. Удалите текст в ячейке A2. Это нужно, чтобы проверить будет ли макрос вставлять текст в ячейку A2 или нет.
  2. Выберите любую ячейку — кроме A2. Это нужно проверить, выбирает ли макрос ячейку A2 или нет.
  3. Перейдите на вкладку «Разработчик».
  4. В группе «Код» нажмите кнопку «Макросы».
  5. В диалоговом окне «Макрос» щелкните макрос «ВводТекста».
  6. Нажмите кнопку «Выполнить».

Вы увидите, что как только вы нажмете кнопку «Выполнить», текст «Excel» будет вставлен в ячейку A2 и выбрана ячейка A3. Это происходит за миллисекунды. Но на самом деле макрос последовательно выполнил записанные действия.

Примечание. Вы также можете запустить макрос с помощью сочетания клавиш Ctrl + Shift + N (удерживайте клавиши Ctrl и Shift, а затем нажмите клавишу N). Это тот же самый ярлык, который мы назначили макросу при его записи.

Что записывает макрос?

Теперь перейдем к редактору кода и посмотрим что у нас получилось.

Вот шаги по открытию редактора VB в Excel:

  1. Перейдите на вкладку «Разработчик».
  2. В группе «Код» нажмите кнопку «Visual Basic».

Вы также можете использовать комбинацию клавиш Alt + F11 и перейти в редактор кода VBA.

Рассмотрим сам редактор кода. Далее коротко опишем интерфейс редактора.

  • Панель меню: содержит команды, которые можно использовать во время работы с редактором VB.
  • Панель инструментов — похожа на панель быстрого доступа в Excel. Вы можете добавить к ней дополнительные инструменты, которыми часто пользуетесь.
  • Окно проектов (Project Explorer) — здесь Excel перечисляет все книги и все объекты в каждой книге. Например, если у нас есть книга с 3 рабочими листами, она появится в Project Explorer. Здесь есть несколько дополнительных объектов, таких как модули, пользовательские формы и модули классов.
  • Окно кода — собственно сам код VBA размещается в этом окне. Для каждого объекта, указанного в проводнике проекта, есть окно кода, например, рабочие листы, книги, модули и т. д. В этом уроке мы увидим, что записанный макрос находится в окне кода модуля.
  • Окно свойств — вы можете увидеть свойства каждого объекта в этом окне. Я часто использую это окно для обозначения объектов или изменения их свойств.
  • Immediate Window (окно предпросмотра) — На начальном этапе оно вам не пригодится. Оно полезно, когда вы хотите протестировать шаги или во время отладки. Он по умолчанию не отображается, и вы можете его отобразить, щелкнув вкладку «View» и выбрав опцию «Immediate Window».

Когда мы записали макрос «ВводТекста», в редакторе VB произошли следующие вещи:

  • Был добавлен новый модуль.
  • Макрос был записан с именем, которое мы указали — «ВводТекста»
  • В окне кода добавлена новая процедура.

Поэтому, если вы дважды щелкните по модулю (в нашем случае модуль 1), появится окно кода, как показано ниже.

Вот код, который записан макрорекодером:

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

Теперь давайте пробежим по каждой строке кода и опишем что и зачем.

Код начинается с Sub, за которым следует имя макроса и пустые круглые скобки. Sub — сокращение для подпрограммы. Каждая подпрограмма (также называемая процедурой) в VBA начинается с Sub и заканчивается End Sub.

  • Range(«A2»).Select — эта строка выбирает ячейку A2.
  • ActiveCell.FormulaR1C1 = «Excel» — эта строка вводит текст «Excel» в активной ячейке. Поскольку мы выбрали ячейку A2 в качестве первого шага, она становится нашей активной ячейкой.
  • Range(«A3»).Select — выбор ячейки A3. Это происходит, когда мы нажимаем клавишу Enter после ввода текста, результатом которого является выбор ячейки A3.

Надеюсь, что у вас есть некоторое базовое понимание того, как записывать макрос в Excel.

Обращаем внимание, что код, записанный через макрорекордер, как правило, не является эффективным и оптимизированным кодом. Макрорекордер часто добавляет дополнительные ненужные действия. Но это не значит, что не нужно пользоваться макрорекодером. Для тех, кто только изучает VBA , макрорекордер может быть отличным способом проанализировать и понять как все работает в VBA.

Абсолютная и относительная запись макроса

Вы уже знаете про абсолютные и относительные ссылки в Excel? Если вы используете абсолютную ссылку для записи макроса, код VBA всегда будет ссылаться на те же ячейки, которые вы использовали. Например, если вы выберете ячейку A2 и введете текст «Excel», то каждый раз — независимо от того, где вы находитесь на листе и независимо от того, какая ячейка выбрана, ваш код будет вводить текст «Excel» в ячейку A2.

Если вы используете параметр относительной ссылки для записи макроса, VBA не будет привязываться к конкретному адресу ячейки. В этом случае программа будет «двигаться» относительно активной ячейки. Например, предположим, что вы уже выбрали ячейку A1, и вы начинаете запись макроса в режиме относительной ссылки. Теперь вы выбираете ячейку A2, вводите текст Excel и нажмите клавишу Enter. Теперь, если вы запустите этот макрос, он не вернется в ячейку A2, вместо этого он будет перемещаться относительно активной ячейки. Например, если выбрана ячейка B3, она переместится на B4, запишет текст «Excel» и затем перейдет к ячейке K5.

Теперь давайте запишем макрос в режиме относительных ссылок:

  1. Выберите ячейку A1.
  2. Перейдите на вкладку «Разработчик».
  3. В группе «Код» нажмите кнопку «Относительные ссылки». Он будет подсвечиваться, указывая, что он включен.
  4. Нажмите кнопку «Запись макроса».
  5. В диалоговом окне «Запись макроса» введите имя для своего макроса. Например, имя «ОтносительныеСсылки».
  6. В опции «Сохранить в» выберите «Эта книга».
  7. Нажмите «ОК».
  8. Выберите ячейку A2.
  9. Введите текст «Excel» (или другой как вам нравится).
  10. Нажмите клавишу Enter. Курсор переместиться в ячейку A3.
  11. Нажмите кнопку «Остановить запись» на вкладке «Разработчик».

Макрос в режиме относительных ссылок будет сохранен.

Теперь сделайте следующее.

  1. Выберите любую ячейку (кроме A1).
  2. Перейдите на вкладку «Разработчик».
  3. В группе «Код» нажмите кнопку «Макросы».
  4. В диалоговом окне «Макрос» кликните на сохраненный макрос «ОтносительныеСсылки».
  5. Нажмите кнопку «Выполнить».

Как вы заметите, макрос записал текст «Excel» не в ячейки A2. Это произошло, потому что вы записали макрос в режиме относительной ссылки. Таким образом, курсор перемещается относительно активной ячейки. Например, если вы сделаете это, когда выбрана ячейка B3, она войдет в текст Excel — ячейка B4 и в конечном итоге выберет ячейку B5.

Вот код, который записал макрорекодер:

Обратите внимание, что в коде нет ссылок на ячейки B3 или B4. Макрос использует Activecell для ссылки на текущую ячейку и смещение относительно этой ячейки.

Не обращайте внимание на часть кода Range(«A1»). Это один из тех случаев, когда макрорекодер добавляет ненужный код, который не имеет никакой цели и может быть удален. Без него код будет работать отлично.

Что нельзя сделать с помощью макрорекодера?

Макро-рекордер отлично подходит для вас в Excel и записывает ваши точные шаги, но может вам не подойти, когда вам нужно сделать что-то большее.

  • Вы не можете выполнить код без выбора объекта. Например, если вы хотите, чтобы макрос перешел на следующий рабочий лист и выделил все заполненные ячейки в столбце A, не выходя из текущей рабочей таблицы, макрорекодер не сможет этого сделать. В таких случаях вам нужно вручную редактировать код.
  • Вы не можете создать пользовательскую функцию с помощью макрорекордера. С помощью VBA вы можете создавать пользовательские функции, которые можно использовать на рабочем листе в качестве обычных функций.
  • Вы не можете создавать циклы с помощью макрорекордера. Но можете записать одно действие, а цикл добавить вручную в редакторе кода.
  • Вы не можете анализировать условия: вы можете проверить условия в коде с помощью макрорекордера. Если вы пишете код VBA вручную, вы можете использовать операторы IF Then Else для анализа условия и запуска кода, если true (или другой код, если false).

Расширение файлов Excel, которые содержат макросы

Когда вы записываете макрос или вручную записываете код VBA в Excel, вам необходимо сохранить файл с расширением файла с поддержкой макросов (.xlsm).

До Excel 2007 был достаточен один формат файла — .xls. Но с 2007 года .xlsx был представлен как стандартное расширение файла. Файлы, сохраненные как .xlsx, не могут содержать в себе макрос. Поэтому, если у вас есть файл с расширением .xlsx, и вы записываете / записываете макрос и сохраняете его, он будет предупреждать вас о сохранении его в формате с поддержкой макросов и покажет вам следующее диалоговое окно:

Если вы выберете «Нет», Excel сохранить файл в формате с поддержкой макросов. Но если вы нажмете «Да», Excel автоматически удалит весь код из вашей книги и сохранит файл как книгу в формате .xlsx. Поэтому, если в вашей книге есть макрос, вам нужно сохранить его в формате .xlsm, чтобы сохранить этот макрос.

Источник

Экономисты в повседневной работе сталкиваются с рутинной работой: с определенной периодичностью им приходится выполнять одну и ту же последовательность действий для получения определенного отчета, например. Частично автоматизировать такую работу можно с помощью макросов. Причем для написания несложных команд достаточно знать только азы программирования.

Как записать самый простой макрос?

Для начала запишем самый легкий макрос — зададим в ячейке А1 формат вида 12 345:

  •  Открываем новую книгу, в ячейке А1 набираем шестизначное число 123456. Сейчас оно выдается без разделителей разрядов. Запишем макрос, который ставит эти разделители.
  •  Заходим на панели инструментов в закладку Вид*, находим кнопку Макросы, жмем Запись макроса. В появившемся окне задаем имя макроса и книгу, в которой хотим этот макрос сохранить.

Важно

Запустить макросы можно только из открытых книг, поэтому если вы планируете использовать записанные вами макросы довольно часто, стоит использовать специальную книгу макросов, которая автоматически открывается вместе с запуском сеанса Excel.

Если вы все-таки хотите хранить макросы в отдельном файле, эту книгу нужно сохранить, выбрав тип файла Книга Excel с поддержкой макросов. В противном случае после закрытия книги макросы будут стерты.

  •  Выбираем Сохранить в… —  Личная книга макросов и нажимаем Ок (рис. 1).

Рис. 1. Запись макроса в личную книгу макросов

  •  Записываем в макрос действия, которые хотим выполнить: вызываем контекстное меню Формат ячеек (можно воспользоваться комбинацией клавиш Сtrl+1) и задаем нужный нам формат числа: на закладке Число идем в блок (все форматы) и выбираем там формат вида # ##0.

К сведению

Этот формат можно задать и в блоке Числовой, но чуть позже вам станет ясно, почему мы воспользовались блоком Все форматы.

  •  На закладке Вид — Макросы выбираем пункт Остановить запись.

Второй, более быстрый способ остановить запись макроса — нажать на появившийся в левом нижнем углу синий квадратик (рис. 2.).

Мы рекомендуем

Всегда обращайте внимание на этот квадратик: если он появился на панели, значит, сейчас идет запись всех ваших действий в макрос. Не забывайте вовремя останавливать запись макроса, чтобы потом его не пришлось переделывать.

Проверяем, что макрос записан и работоспособен:

  •  в ячейку А2 вбиваем любое шестизначное число;
  •  запускаем макрос одним из двух способов: на закладке Вид — Макросы выбираем пункт Макросы или нажимаем комбинацию клавиш Alt+F8, находим в списке наш макрос и нажимаем кнопку Выполнить.

Рис. 2. Форматирование числа и остановка записи макроса

Итак, вы записали свой первый макрос! Примите поздравления. Теперь давайте познакомимся с личной книгой макросов и синтаксисом написания команд для макроса.

Личная книга макросов

По умолчанию Excel не отображает личную книгу макросов. Чтобы убедиться, что она открыта, выбираем на вкладке Вид кнопку Отобразить — в появившемся окне должна быть книга под именем PERSONAL.

Мы убедились, что книга открыта, но отображать ее не будем, чтобы потом по ошибке не закрыть ее. По сути, в этой книге нас интересует так называемый Исходный текст — блок, в котором записываются макросы. Чтобы увидеть это окно, нажмите клавиши Alt+F11 или кликните правой кнопкой мыши на ярлыке любого листа Excel и выберите в контекстном меню Исходный текст. Откроется окно VBA-кодирования в Excel (рис. 3). Оно состоит из двух блоков:

1. В левой части экрана окно Project – VBAProject — это проводник, в котором отображаются все открытые в данный момент книги Excel (даже если вы их не видите, как, например, книгу Personal). Работа с этим блоком аналогична работе в обычном проводнике — двойной клик по наименованию книги раскрывает ее содержимое. Нас интересует блок Modules — Module1. Кликаем левой кнопкой мыши дважды по этому объекту.

2. В правой части экрана откроется блок записи и редактирования макросов. Здесь уже автоматически записался Макрос1. Рассмотрим на его примере основную канву макроса.

Рис. 3. Окно VBA-кодирования в Excel

Синтаксис макроса

Макросы — это команды, написанные на языке VBA (Visual Basic for Applications). И синтаксис кода макроса не отличается от записи кода в Visual Basic.

Любой макрос имеет следующий вид:

Sub Имя_Макроса_Без_Пробелов()

‘ комментарии к макросу — они нужны для вас, VBA не воспринимает такие строки как команды

команды, написанные на языке VBA

End Sub

3 обязательных блока макроса:

1. Начало макроса. Всегда начинается с команды Sub. Далее идет имя макроса — оно может быть на русском языке, но не должно содержать пробелы и специальные символы.

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

2. Блок команд. В нашем примере он состоит из одной строки: Selection.NumberFormat = «#,##0»

Каждая команда должна начинаться с новой строки. Если текст команды очень длинный и не помещается на экране, его можно разбить на несколько строк, заканчивая строку символом нижнего подчеркивания _ (далее в примере мы это увидим).

3. Конец макроса. Всегда обозначается как End Sub.

Есть и один необязательный блок — это комментарии, которые вы можете оставлять в любом месте внутри кода макроса, поставив перед началом комментариев знак апострофа ‘. Например, вы можете описать, что именно делает тот или иной макрос.

Обратите внимание!

Если вы хотите разместить комментарии в несколько строк, каждую новую строку надо начинать с апострофа.

Теперь запишем более сложный макрос и научимся понимать текст его кода.

Например, информационная система выдает отчет «Бюджет на месяц» без выделения групповых значений цветом или шрифтом.

Нам необходимо:

  •  выделить групповые строки полужирным шрифтом;
  •  отформатировать на печать — расположить отчет по центру листа, задать масштаб 75 %, вывести в колонтитулы название отчета (рис. 4).

Рис. 4. Изменения после написания макроса

Запишем алгоритм форматирования отчета в макрос.

Нажимаем кнопку записи макроса и выполняем следующие действия:

  •  Даем макросу имя Форматирование_БДР, в блоке описания записываем, что будет делать этот макрос (например, Выделяет жирным курсивом итоги, форматирует на печать). Жмем Ок.
  •  Выделяем столбцы А:С, ставим автофильтр — на закладке Данные находим кнопку Фильтр.
  •  По столбцу КОД задаем условие не содержит точку: Текстовые фильтры — Не содержит и в поле текста ставим символ точки без пробелов (рис. 5).

Рис. 5. Использование автофильтра по столбцу «КОД»

  •  Выделяем отфильтрованный диапазон и задаем ему полужирный шрифт.
  •  Снимаем автофильтр (повторное нажатие на закладке Данные кнопки Фильтр).
  •  Заходим в меню форматирования на печать (Кнопка Файл/Office — Печать — Предварительный просмотр — Параметры страницы) и задаем там три параметра:

1) на вкладке Страница задаем масштаб 75 %;

2) на вкладке Поля отмечаем пункт Горизонтально в блоке Центрировать на странице;

3) на вкладке Колонтитулы создаем верхний колонтитул с текстом Бюджет на январь.

  •  Выходим из параметров страницы.
  •  Заканчиваем запись макроса.
  •  Нажимаем Alt+F11 и смотрим, что получилось (см. рис. 4).

Код этого макроса уже гораздо длиннее и непонятнее, но легко читаем для знающих английский язык и азы программирования в VBA.

Правила написания команд в VBA

Любая команда макроса состоит из двух блоков, разделенных точкой:

Объект.Действие с объектом или свойство объекта

Объектами в Excel являются, например:

  •  книга: WorkBook, ActiveWorkbook;
  •  лист, листы: WorkSheet, ActiveSheet, Sheets;
  •  ячейка: Cells(1,1) — в скобках указываются номера строки (Row) и столбца (Column) ячейки на листе;
  •  диапазон ячеек (может быть и одна ячейка): Range(«А1:С5»), Range(«А1»);
  •  строки (Rows);
  •  столбцы (Columns);
  •  выделение (Selection) — выделенный в данный момент диапазон (это может быть как несколько смежных ячеек, так и смежные строки или столбцы).

Примеры действий с объектами:

  •  ActiveWorkbook.Save — сохранить рабочую книгу (та, которая была активна в момент вызова пользователем макроса);
  •  Sheets(«Лист3»).Name = «Отчет» — переименовать «Лист3» в «Отчет»;
  •  Sheets(«Отчет»).Activate — перейти на лист с названием «Отчет»;
  •  Range(«А1»).Copy — скопировать в буфер обмена данные из ячейки А1;
  •  Rows(«13:13»).Delete Shift:=xlUp — удалить строку 13 со сдвигом вверх.

Примеры свойств объектов:

  •  ActiveCell.FormulaR1C1 = «БДР» — в выделенной (активной) ячейке записан текст «БДР»;
  •  ActiveCell.Row < 65 — номер ряда активной ячейки меньше 65.

Помнить все названия объектов, команд и свойств для написания несложных макросов не обязательно. Вы всегда можете сначала записать ваши стандартные действия с отчетами в Excel, а потом отформатировать код макроса, убрав из него лишние действия или заменив некоторые заданные параметры (например, длину диапазона) на переменные (которые в дальнейшем макрос будет запрашивать у пользователя или рассчитывать самостоятельно).

Но об этом мы расскажем далее, а сейчас обратимся к коду нашего первого макроса, состоящего из одной строки:

Selection.NumberFormat = «#,##0»

Суть его в следующем: к объекту Выделенный диапазон (у нас одна ячейка, но это может быть и весь столбец/строка или диапазон смежных ячеек) применяется свойство Числовой формат вида # ##0 (если помните, именно этот формат мы выбрали в списке).

Код макроса Форматирование_БДР и расшифровка строк кода представлены в таблице.

 

Строка кода

Расшифровка

Sub Форматирование_БДР()

Начало макроса, имя макроса

Пустая строка комментариев (ставится автоматически при записи макроса)

‘ Форматирование_БДР Макрос

Автоматически добавленный комментарий при записи макроса — может быть удален без потери работоспособности макроса

‘ Выделяем жирным курсивом итоги, форматируем на печать

Автоматически добавленный комментарий при записи макроса из поля Описание

Пустая строка — не влияет на суть исполнения макроса, но их полезно добавлять для разделения блоков команд внутри кода

   Columns(«A:C»).Select

Выделить (Select) объект Столбцы (Columns) А:С

    Selection.AutoFilter

Применить автофильтр (AutoFilter) для выделенного диапазона (Selection)

    ActiveSheet.Range(«$A$1:$C$34″).AutoFilter Field:=1, Criteria1:=»<>*.*», _

Задать критерий отбора «не содержит точку»

        Operator:=xlAnd

Продолжение команды из предыдущей строки.

Обратите внимание: предыдущая строка закончилась символом нижнего подчеркивания _, значит, текст команды не уместился на одну строку и окончание команды перенесено на следующую

    Range(«A1:C34»).Select

Выделить (Select) объект Диапазон (Range) А1:С34.

Обратите внимание: какой бы длины ни был ваш следующий отчет, для которого вы будете применять этот макрос, выделится всегда только диапазон до 34 строки!

Как сделать этот диапазон любой длины — обсудим немного позже

    Selection.Font.Bold = True

Для выделенного диапазона (Объект Selection) установить свойство «полужирный шрифт» (Font.Bold = True). Если нужно отменить какое-то свойство, пишем False

    Selection.AutoFilter

Снять автофильтр (при записи макроса это было повторное нажатие кнопки Фильтр на закладке Данные)

    With ActiveSheet.PageSetup

Начало процедуры With (используется, если далее перечисляются свойства или действия с одним и тем же объектом для компактности записи кода).

Для объекта ActiveSheet (Текущий лист) применить следующие параметры свойства PageSetup (Параметры печати):

        .PrintTitleRows = «»

Печатать на каждой странице сквозные строки — пусто (то есть данное свойство не задано пользователем)

        .PrintTitleColumns = «»

Печатать на каждой странице сквозные столбцы — пусто

    End With

Окончание процедуры With

    ActiveSheet.PageSetup.PrintArea = «»

Заданная область печати — пусто (то есть пользователь не ограничил область печати, следовательно, на экран будет выведено все, что есть на листе)

    With ActiveSheet.PageSetup

Начало процедуры With

Для объекта Текущий лист применить следующие параметры печати (цветом выделены те, которые мы изменили по сравнению со стандартными):

        .LeftHeader = «»

Левый верхний колонтитул — пусто

        .CenterHeader = «Бюджет на январь»

Центральный верхний колонтитул — задан текст пользователем

        .RightHeader = «»

Правый верхний колонтитул — пусто

        .LeftFooter = «»

Левый нижний колонтитул — пусто

        .CenterFooter = «»

Центральный нижний колонтитул — пусто

        .RightFooter = «»

Правый нижний колонтитул — пусто

        .LeftMargin = Application.InchesToPoints(0.708661417322835)

Размеры левого поля

        .RightMargin = Application.InchesToPoints(0.708661417322835)

Размеры правого поля

        .TopMargin = Application.InchesToPoints(0.748031496062992)

Размеры верхнего поля

        .BottomMargin = Application.InchesToPoints(0.748031496062992)

Размеры нижнего поля

        .HeaderMargin = Application.InchesToPoints(0.31496062992126)

Размеры верхнего колонтитула

        .FooterMargin = Application.InchesToPoints(0.31496062992126)

Размеры нижнего колонтитула

        .PrintHeadings = False

Не печатать заголовки строк и столбцов (False — пользователь не отметил этот пункт)

        .PrintGridlines = False

Не печатать сетку

        .PrintComments = xlPrintNoComments

Не печатать примечания

        .PrintQuality = 600

Качество печати — 600 точек на дюйм

        .CenterHorizontally = True

Центрировать на странице горизонтально (True — пользователь отметил этот пункт)

        .CenterVertically = False

Не центрировать по вертикали

        .Orientation = xlPortrait

Ориентация страницы — книжная

        .Draft = False

Пользователь не отметил пункт Черновая в блоке Печать

        .PaperSize = xlPaperA4

Размер бумаги А4

        .FirstPageNumber = xlAutomatic

Номер первой страницы — автоматически

        .Order = xlDownThenOver

Последовательность вывода страниц: вниз, потом вправо (пункт в блоке Печать)

        .BlackAndWhite = False

Пользователь не отметил пункт Черно-белая в блоке Печать

        .Zoom = 75

Масштаб 75 %

        .PrintErrors = xlPrintErrorsDisplayed

Пункт в блоке ПечатьОшибки ячеекКак на экране

        .OddAndEvenPagesHeaderFooter = False

Пользователь не задавал разные колонтитулы для четных и нечетных страниц (флажок в блоке Колонтитулы)

        .DifferentFirstPageHeaderFooter = False

Пользователь не задавал отдельный колонтитул для первой страницы (флажок в блоке Колонтитулы)

        .ScaleWithDocHeaderFooter = True

Флажок в блоке Колонтитулы – Изменять вместе с масштабом страницы отмечен пользователем

        .AlignMarginsHeaderFooter = True

Флажок в блоке Колонтитулы – Выровнять относительно полей страницы отмечен пользователем

        .EvenPage.LeftHeader.Text = «»

Текст колонтитулов для четных и первой страниц не задан

        .EvenPage.CenterHeader.Text = «»

        .EvenPage.RightHeader.Text = «»

        .EvenPage.LeftFooter.Text = «»

        .EvenPage.CenterFooter.Text = «»

        .EvenPage.RightFooter.Text = «»

        .FirstPage.LeftHeader.Text = «»

        .FirstPage.CenterHeader.Text = «»

        .FirstPage.RightHeader.Text = «»

        .FirstPage.LeftFooter.Text = «»

        .FirstPage.CenterFooter.Text = «»

        .FirstPage.RightFooter.Text = «»

    End With

Окончание процедуры With

End Sub

Окончание кода макроса

Редактирование макроса

Как видите, код макроса легко читаем и понятен. Кроме того, нам не надо нагромождать его лишними строками: так как в параметрах печати мы меняли только три пункта, остальные строки можем удалить (они будут установлены по умолчанию). Удалим ненужные строки, поставим комментарии и в итоге получим вот такой элегантный код:

Sub Форматирование_БДР()

‘ Макрос выделяет жирным курсивом итоги, форматирует отчет на печать

‘——————

‘ Выделяем столбцы и ставим фильтр по столбцу КОД

 Columns(«A:C»).Select

 Selection.AutoFilter

 ActiveSheet.Range(«$A$1:$C$34″).AutoFilter Field:=1, Criteria1:=»<>*.*», _

 Operator:=xlAnd

‘ Выделяем отфильтрованный диапазон полужирным шрифтом, снимаем фильтр

 Range(«A1:C34»).Select

 Selection.Font.Bold = True

 Selection.AutoFilter

 ‘ Форматируем на печать: верхний колонтитул, центрирование по горизонтали, масштаб 75 %

 With ActiveSheet.PageSetup

 .CenterHeader = «Бюджет на январь»

 .CenterHorizontally = True

 .Zoom = 75

 End With

End Sub

Ввод в код макроса функций и процедур

Теперь усложним код макроса, задав ему два параметра:

1. Название месяца отчета запрашиваем у пользователя.

2. Последняя строка отчета БДР (в случае если она плавающая) рассчитывается в коде макроса.

Функция InputBox

Чтобы запросить у пользователя месяц отчета, воспользуемся функцией Inputbox, которая выводит диалоговое окно, в котором пользователь может самостоятельно задать значение переменной, используемой в коде. Синтаксис функции InputBox:

Zapros = InputBox(«Текст запроса», <«Текст в шапке окна»>, <Значение по умолчанию>,…)

где Zapros — введенная вами переменная (имя придумываете вы сами), а в скобках через запятую перечисляются аргументы функции.

Обратите внимание: первый аргумент является обязательным, то есть любое диалоговое окно должно сопровождаться пояснительным текстом, чего вы ждете от пользователя. Следующие аргументы обязательными не являются и их можно не указывать. То есть если вы хотите задать значение по умолчанию, но не хотите писать текст в шапке диалогового окна, разделите первый и третий аргументы двумя запятыми, как это будет сделано в нашем примере (см. далее).

Для удобства присвойте полученное значение функции InputBox какой-нибудь введенной вами переменной, особенно если в коде макроса вы будете несколько раз использовать значение этой функции.

Важно

Имена вводимых переменных не должны совпадать с уже занятыми VBA словами под название объектов, свойств или функций!

В нашем примере присвоим результат вызова функции InputBox переменной Mes.

Например, нельзя завести свою переменную Range, Cells или Month — компилятор VBA предупредит вас, что делать этого нельзя, и не запустит макрос, пока вы не устраните ошибку (рис. 6).

Рис. 6. Пример ошибки при заведении переменной

Не забывайте любой текст в коде брать в кавычки! В противном случае компилятор VBA будет воспринимать этот текст как команды и выдавать ошибку, так как не сможет их обработать.

Итак, приступим к редактированию кода макроса. Добавим в самое начало кода макроса строки:

‘ Запрашиваем у пользователя месяц отчета

Mes = InputBox(«Введите название месяца отчета», , «Январь»)

Теперь при запуске макроса будет выводиться диалоговое окно, в котором пользователь самостоятельно сможет указать, за какой месяц этот отчет (рис. 7).

Рис. 7. Диалоговое окно для указания месяца

С помощью функции InputBox можно запросить у пользователя и длину отчета. Но мы научим Excel высчитывать ее самостоятельно. Для этого нам потребуется процедура While.

Процедура While

Используется в коде, если надо сделать одинаковые действия несколько раз подряд до тех пор, пока выполняется какое-либо условие. Синтаксис процедуры While:

Do While <условие, которое должно быть верным для выполнения процедуры>

 <список команд>

Loop

Условие может состоять из одного выражения или содержать несколько, перечисленных через оператор AND (то есть оба условия должны быть выполнены) или OR (достаточно выполнения только одного из перечисленных условий). Также условие обязательно должно содержать переменную-счетчик (это может быть номер строки или столбца ячейки, значения которой вы проверяете).

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

Если макрос ушел в цикл, прервите его с помощью комбинации клавиш Ctrl+Break и либо прекратите макрос (кнопка End), либо зайдите в код макроса и исправьте ошибку (кнопка Debug). Чтобы макрос не уходил в цикл, рекомендуется включить в блок условий «защиту от дурака». Например, добавляем в условие проверку, чтобы значение счетчика не превышало определенной, заведомо достаточной для нас величины.

Рассмотрим применение процедуры While для поиска конца отчета БДР.

Как видно на рис. 4, последняя строка отчета имеет код «500». Напишем процедуру, которая будет проверять значения в ячейках столбца «А» и остановит свои действия, когда найдет ячейку с кодом «500».

Обратите внимание!

Excel иногда воспринимает числа как текст, поэтому включим два условия проверки значения ячейки и добавим «защиту от дурака» на случай, если в форме отчета случайно затрется код последней строки.

Помним, что все текстовые значения надо брать в кавычки. Числа записываем без кавычек:

‘ Ищем последнюю строку отчета

Dim Row_End As Integer     ‘ Вводим переменную «счетчик номера строки»

Row_End = 1             ‘ Присваиваем ей номер 1

‘ Начинаем процедуру поиска последней строки отчета по коду «500»

Do While Cells(Row_End, 1).Value <> «500» And Cells(Row_End, 1).Value <> 500 And Row_End < 100

‘ До тех пор, пока код не равен 500 и номер строки меньше 100, выполняем наращивание счетчика

Row_End = Row_End +1

Loop

Таким образом, процедура While нам нужна только для наращивания счетчика — никаких дополнительных действий она не производит. Запомните этот прием — он часто нужен в кодировании.

Теперь заменим в изначальном коде макроса номер последней ячейки (34) на переменную Row_End. Число 34 было частью текста А1:С34, а теперь нам надо часть текста заменить на переменную. Делается это с помощью символа амперсанд &:

«текст» & переменная & «текст».

В нашем случае ссылка на диапазон А1:С34 будет записана так: А1:С & Row_End.

Кроме того, вспоминаем, что и название отчета Бюджет на январь у нас тоже теперь содержит параметр и будет записываться так: Бюджет на & Mes.

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

Еще раз взглянем на получившийся код макроса:

Sub Форматирование_БДР()

‘ Макрос выделяет жирным курсивом итоги, форматирует отчет на печать

‘ ——————

‘ Запрашиваем у пользователя месяц отчета

Mes = InputBox(«Введите название месяца отчета», , «Январь»)

‘ Ищем последнюю строку отчета

Dim Row_End As Integer     ‘ Вводим переменную «счетчик номера строки»

Row_End = 1             ‘ Присваиваем ей номер 1

‘ Начинаем процедуру поиска последней строки отчета по коду «500»

‘ Критичным значением для «защиты от дурака» принимаем номер строки 100

Do While Cells(Row_End, 1).Value <> «500» And Cells(Row_End, 1).Value <> 500 And Row_End < 100

‘ До тех пор, пока код не равен 500 и номер строки меньше 100, выполняем наращивание счетчика

Row_End = Row_End +1

Loop

‘ Выделяем столбцы и ставим фильтр на КОД

 Columns(«A:C»).Select

 Selection.AutoFilter

 ActiveSheet.Range(«$A$1:$C$» & Row_End).AutoFilter Field:=1, Criteria1:=»<>*.*», _

 Operator:=xlAnd

‘ Выделяем отфильтрованный диапазон полужирным шрифтом, снимаем фильтр

 Range(«A1:C» & Row_End).Select

 Selection.Font.Bold = True

 Selection.AutoFilter

‘ Форматируем на печать: верхний колонтитул, центрирование по горизонтали, масштаб 75 %

 With ActiveSheet.PageSetup

 .CenterHeader = «Бюджет на » & Mes

 .CenterHorizontally = True

 .Zoom = 75

 End With

End Sub

Теперь макрос стал более универсальным. Добавим в него еще одну «защиту от дурака».

Если нам принципиально, правильно ли макрос нашел последнюю строку отчета, после окончания процедуры While (строка Loop) можно добавить блок проверки значения Row_End и запроса у пользователя подтверждения на продолжение макроса.

Для этого изучим функцию MsgBox, процедуру IF и команду Exit Sub.

Функция MsgBox

MsgBox — еще один способ общения с пользователем: сообщения ему какой-то информации по ходу выполнения макроса или запрос у него подтверждения по дальнейшим действиям макроса путем нажатия на кнопки вида Yes, No, Ок, Cancel.

Она имеет два вида записи:

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

MsgBox «Текст сообщения», <Вид кнопок>, <«Текст в шапке окна»>,…

На экране отобразится диалоговое окно, и после нажатия пользователем кнопки Ок продолжится выполнение макроса (рис. 8).

Рис. 8. Первый вид записи функции MsgBox

Как и в случае с функцией InputBox, обязательным здесь является только первый аргумент — Текст сообщения. Остальные можно даже не указывать, сократив вид записи функции до вида:

2. Нам важно, что ответил пользователь, мы записываем его ответ в значение какой-то переменной (рис. 9). В этом случае аргументы функции заключаются в скобки, а перед функцией обязательно должна стоять переменная, в которую мы записываем, на какую кнопку нажал пользователь:

YesNo = MsgBox(«Текст сообщения», <Вид кнопок>, <«Текст в шапке окна»>,…)

Рис. 9. Второй вид записи функции MsgBox

Варианты вида кнопок:

  •  vbOKOnly — только кнопка ОК;
  •  vbOKCanсel — кнопки ОК и Cancel;
  •  vbYesNo — кнопки Yes и No;
  •  vbYesNoCancel — кнопки Yes, No и Cancel.

Соответственно в зависимости от нажатой кнопки значения функции MsgBox могут быть vbOK, vbCancel, vbYes или vbNo.

Процедура If

С помощью данной процедуры можно разбить команды кода на две ветки в зависимости от выполнения заданного условия. Синтаксис процедуры If:

If <условие, которое должно быть верным> Then

 <список команд при выполнении указанного условия>

else

 <список команд при невыполнении указанного условия>

End If

Обязательным к заполнению является только условие. Список команд в обоих блоках заполнять не обязательно. В зависимости от ваших задач вы можете заполнить оба блока или только один из них. Условие может состоять из одного выражения или содержать несколько выражений, перечисленных через оператор AND (то есть оба условия должны быть выполнены) или оператор OR (достаточно выполнения только одного из перечисленных условий).

Команда Exit Sub

Прекращает выполнение макроса. Обычно ее используют в ветках процедуры If при проверке допустимости дальнейшего исполнения макроса. Обратите внимание: ни одно действие после команды Exit Sub выполнено не будет. Поэтому если вы хотите сообщить пользователю о принудительном прекращении процедуры, команду MsgBox нужно расположить выше команды Exit Sub.

Итак, объединим новые знания в код «защиты от дурака» и запишем его после строки Loop:

‘ Проверяем, дошла ли процедура While до «критичной» строки 100

‘ и спрашиваем подтверждение о продолжении выполнения макроса

If Row_End = 100 Then      

YesNo = MsgBox(«Поиск последней строки отчета дошел до 100, продолжаем?», vbYesNo)

If YesNo = vbNo Then          ‘ Если нажата кнопка «No», то…

MsgBox «Процедура прервана пользователем»   ‘ 1. выдаем сообщение для пользователя,

Exit Sub          ‘ 2. останавливаем макрос

End If

End If

В нашем коде прошло вложение одной процедуры If в другую:

  •  сначала мы проверили, дошел ли счетчик Row_End до значения 100;
  •  если дошел, мы спрашиваем у пользователя, продолжать ли нам выполнение макроса;
  •  если пользователь ответил «нет», останавливаем макрос.

В обеих процедурах If мы опустили второй блок (else): если Row_End не достиг значения 100 или пользователь ответил «да», макрос просто покинет процедуру If и продолжит выполнять команды, написанные ниже.

Каждая процедура If должна заканчиваться командой End If. Если количество строк с командой If не будет соответствовать количеству строк с командой End If, компилятор VBA сообщит об ошибке и вам придется искать, где вы потеряли конец процедуры If.

Поэтому рекомендуется сразу писать обе строки, а потом уже наполнять процедуру командами.

Также для удобства визуального восприятия кода макроса рекомендуется каждую вложенную процедуру начинать с отступа, чтобы визуально было понятно, где заканчивается вложенная процедура и продолжается список команд процедуры верхнего уровня.

Подведем итоги

Мы с вами научились:

  •  записывать макросы через команду Вид  Макросы  Запись макроса;
  •  редактировать автоматически записанный макрос, удалять из него лишние команды;
  •  унифицировать код макроса, вводя в него переменные, которые макрос запрашивает у пользователя или рассчитывает самостоятельно,

а также изучили функции InputBox и MsgBox, процедуры While и If, команду Exit Sub.

В следующем номере рассмотрим процедуру FOR, запишем макрос суммирования результирующих статей БДР, научимся тестировать макросы и выносить кнопки вызова макроса на панель быстрого доступа.


Статья опубликована в журнале «Справочник экономиста» № 4, 2016.

Время на прочтение
7 мин

Количество просмотров 312K

Приветствую всех.

В этом посте я расскажу, что такое VBA и как с ним работать в Microsoft Excel 2007/2010 (для более старых версий изменяется лишь интерфейс — код, скорее всего, будет таким же) для автоматизации различной рутины.

VBA (Visual Basic for Applications) — это упрощенная версия Visual Basic, встроенная в множество продуктов линейки Microsoft Office. Она позволяет писать программы прямо в файле конкретного документа. Вам не требуется устанавливать различные IDE — всё, включая отладчик, уже есть в Excel.

Еще при помощи Visual Studio Tools for Office можно писать макросы на C# и также встраивать их. Спасибо, FireStorm.

Сразу скажу — писать на других языках (C++/Delphi/PHP) также возможно, но требуется научится читать, изменять и писать файлы офиса — встраивать в документы не получится. А интерфейсы Microsoft работают через COM. Чтобы вы поняли весь ужас, вот Hello World с использованием COM.

Поэтому, увы, будем учить Visual Basic.

Чуть-чуть подготовки и постановка задачи

Итак, поехали. Открываем Excel.

Для начала давайте добавим в Ribbon панель «Разработчик». В ней находятся кнопки, текстовые поля и пр. элементы для конструирования форм.

Появилась вкладка.

Теперь давайте подумаем, на каком примере мы будем изучать VBA. Недавно мне потребовалось красиво оформить прайс-лист, выглядевший, как таблица. Идём в гугл, набираем «прайс-лист» и качаем любой, который оформлен примерно так (не сочтите за рекламу, пожалуйста):

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

Результат, которого хотим добиться, выглядит примерно так:

Разумеется, если смотреть прайс только на компьютере, то можно добавить фильтры и будет гораздо удобнее искать нужный товар. Однако мы хотим научится кодить и задача вполне подходящая, не так ли?

Кодим

Для начала требуется создать кнопку, при нажатии на которую будет вызываться наша програма. Кнопки находятся в панели «Разработчик» и появляются по кнопке «Вставить». Вам нужен компонент формы «Кнопка». Нажали, поставили на любое место в листе. Далее, если не появилось окно назначения макроса, надо нажать правой кнопкой и выбрать пункт «Назначить макрос». Назовём его FormatPrice. Важно, чтобы перед именем макроса ничего не было — иначе он создастся в отдельном модуле, а не в пространстве имен книги. В этому случае вам будет недоступно быстрое обращение к выделенному листу. Нажимаем кнопку «Новый».

И вот мы в среде разработки VB. Также её можно вызвать из контекстного меню командой «Исходный текст»/«View code».

Перед вами окно с заглушкой процедуры. Можете его развернуть. Код должен выглядеть примерно так:

Sub FormatPrice()End Sub

Напишем Hello World:

Sub FormatPrice()
    MsgBox "Hello World!"
End Sub

И запустим либо щелкнув по кнопке (предварительно сняв с неё выделение), либо клавишей F5 прямо из редактора.

Тут, пожалуй, следует отвлечься на небольшой ликбез по поводу синтаксиса VB. Кто его знает — может смело пропустить этот раздел до конца. Основное отличие Visual Basic от Pascal/C/Java в том, что команды разделяются не ;, а переносом строки или двоеточием (:), если очень хочется написать несколько команд в одну строку. Чтобы понять основные правила синтаксиса, приведу абстрактный код.

Примеры синтаксиса

' Процедура. Ничего не возвращает
' Перегрузка в VBA отсутствует
Sub foo(a As String, b As String)
    ' Exit Sub ' Это значит "выйти из процедуры"
    MsgBox a + ";" + b
End Sub' Функция. Вовращает Integer
Function LengthSqr(x As Integer, y As IntegerAs Integer
    ' Exit Function
    LengthSqr = x * x + y * y
End FunctionSub FormatPrice()
    Dim s1 As String, s2 As String
    s1 = "str1"
    s2 = "str2"
    If s1 <> s2 Then
        foo "123""456" ' Скобки при вызове процедур запрещены
    End IfDim res As sTRING ' Регистр в VB не важен. Впрочем, редактор Вас поправит
    Dim i As Integer
    ' Цикл всегда состоит из нескольких строк
    For i = 1 To 10
        res = res + CStr(i) ' Конвертация чего угодно в String
        If i = 5 Then Exit For
    Next iDim x As Double
    x = Val("1.234"' Парсинг чисел
    x = x + 10
    MsgBox xOn Error Resume Next ' Обработка ошибок - игнорировать все ошибки
    x = 5 / 0
    MsgBox xOn Error GoTo Err ' При ошибке перейти к метке Err
    x = 5 / 0
    MsgBox "OK!"
    GoTo ne

Err:
    MsgBox 

"Err!"

ne:

On Error GoTo 0 ' Отключаем обработку ошибок

    ' Циклы бывает, какие захотите
    Do While True
        Exit DoLoop 'While True
    Do 'Until False
        Exit Do
    Loop Until False
    ' А вот при вызове функций, от которых хотим получить значение, скобки нужны.
    ' Val также умеет возвращать Integer
    Select Case LengthSqr(Len("abc"), Val("4"))
    Case 24
        MsgBox "0"
    Case 25
        MsgBox "1"
    Case 26
        MsgBox "2"
    End Select' Двухмерный массив.
    ' Можно также менять размеры командой ReDim (Preserve) - см. google
    Dim arr(1 to 10, 5 to 6) As Integer
    arr(1, 6) = 8Dim coll As New Collection
    Dim coll2 As Collection
    coll.Add "item""key"
    Set coll2 = coll ' Все присваивания объектов должны производится командой Set
    MsgBox coll2("key")
    Set coll2 = New Collection
    MsgBox coll2.Count
End Sub

Грабли-1. При копировании кода из IDE (в английском Excel) есь текст конвертируется в 1252 Latin-1. Поэтому, если хотите сохранить русские комментарии — надо сохранить крокозябры как Latin-1, а потом открыть в 1251.

Грабли-2. Т.к. VB позволяет использовать необъявленные переменные, я всегда в начале кода (перед всеми процедурами) ставлю строчку Option Explicit. Эта директива запрещает интерпретатору заводить переменные самостоятельно.

Грабли-3. Глобальные переменные можно объявлять только до первой функции/процедуры. Локальные — в любом месте процедуры/функции.

Еще немного дополнительных функций, которые могут пригодится: InPos, Mid, Trim, LBound, UBound. Также ответы на все вопросы по поводу работы функций/их параметров можно получить в MSDN.

Надеюсь, что этого Вам хватит, чтобы не пугаться кода и самостоятельно написать какое-нибудь домашнее задание по информатике. По ходу поста я буду ненавязчиво знакомить Вас с новыми конструкциями.

Кодим много и под Excel

В этой части мы уже начнём кодить нечто, что умеет работать с нашими листами в Excel. Для начала создадим отдельный лист с именем result (лист с данными назовём data). Теперь, наверное, нужно этот лист очистить от того, что на нём есть. Также мы «выделим» лист с данными, чтобы каждый раз не писать длинное обращение к массиву с листами.

Sub FormatPrice()
    Sheets("result").Cells.Clear
    Sheets("data").Activate
End Sub

Работа с диапазонами ячеек

Вся работа в Excel VBA производится с диапазонами ячеек. Они создаются функцией Range и возвращают объект типа Range. У него есть всё необходимое для работы с данными и/или оформлением. Кстати сказать, свойство Cells листа — это тоже Range.

Примеры работы с Range

Sheets("result").Activate
Dim r As Range
Set r = Range("A1")
r.Value = "123"
Set r = Range("A3,A5")
r.Font.Color = vbRed
r.Value = "456"
Set r = Range("A6:A7")
r.Value = "=A1+A3"

Теперь давайте поймем алгоритм работы нашего кода. Итак, у каждой строчки листа data, начиная со второй, есть некоторые данные, которые нас не интересуют (ID, название и цена) и есть две вложенные группы, к которым она принадлежит (тип и производитель). Более того, эти строки отсортированы. Пока мы забудем про пропуски перед началом новой группы — так будет проще. Я предлагаю такой алгоритм:

  1. Считали группы из очередной строки.
  2. Пробегаемся по всем группам в порядке приоритета (вначале более крупные)
    1. Если текущая группа не совпадает, вызываем процедуру AddGroup(i, name), где i — номер группы (от номера текущей до максимума), name — её имя. Несколько вызовов необходимы, чтобы создать не только наш заголовок, но и всё более мелкие.
  3. После отрисовки всех необходимых заголовков делаем еще одну строку и заполняем её данными.

Для упрощения работы рекомендую определить следующие функции-сокращения:

Function GetCol(Col As IntegerAs String
    GetCol = Chr(Asc("A") + Col)
End FunctionFunction GetCellS(Sheet As String, Col As Integer, Row As IntegerAs Range
    Set GetCellS = Sheets(Sheet).Range(GetCol(Col) + CStr(Row))
End FunctionFunction GetCell(Col As Integer, Row As IntegerAs Range
    Set GetCell = Range(GetCol(Col) + CStr(Row))
End Function

Далее определим глобальную переменную «текущая строчка»: Dim CurRow As Integer. В начале процедуры её следует сделать равной единице. Еще нам потребуется переменная-«текущая строка в data», массив с именами групп текущей предыдущей строк. Потом можно написать цикл «пока первая ячейка в строке непуста».

Глобальные переменные

Option Explicit ' про эту строчку я уже рассказывал
Dim CurRow As Integer
Const GroupsCount As Integer = 2
Const DataCount As Integer = 3

FormatPrice

Sub FormatPrice()
    Dim I As Integer ' строка в data
    CurRow = 1
    Dim Groups(1 To GroupsCount) As String
    Dim PrGroups(1 To GroupsCount) As String

    Sheets(

"data").Activate
    I = 2
    Do While True
        If GetCell(0, I).Value = "" Then Exit Do
        ' ...
        I = I + 1
    Loop
End Sub

Теперь надо заполнить массив Groups:

На месте многоточия

Dim I2 As Integer
For I2 = 1 To GroupsCount
    Groups(I2) = GetCell(I2, I)
Next I2
' ...
For I2 = 1 To GroupsCount ' VB не умеет копировать массивы
    PrGroups(I2) = Groups(I2)
Next I2
I =  I + 1

И создать заголовки:

На месте многоточия в предыдущем куске

For I2 = 1 To GroupsCount
    If Groups(I2) <> PrGroups(I2) Then
        Dim I3 As Integer
        For I3 = I2 To GroupsCount
            AddHeader I3, Groups(I3)
        Next I3
        Exit For
    End If
Next I2

Не забудем про процедуру AddHeader:

Перед FormatPrice

Sub AddHeader(Ty As Integer, Name As String)
    GetCellS("result", 1, CurRow).Value = Name
    CurRow = CurRow + 1
End Sub

Теперь надо перенести всякую информацию в result

For I2 = 0 To DataCount - 1
    GetCellS("result", I2, CurRow).Value = GetCell(I2, I)
Next I2

Подогнать столбцы по ширине и выбрать лист result для показа результата

После цикла в конце FormatPrice

Sheets("Result").Activate
Columns.AutoFit

Всё. Можно любоваться первой версией.

Некрасиво, но похоже. Давайте разбираться с форматированием. Сначала изменим процедуру AddHeader:

Sub AddHeader(Ty As Integer, Name As String)
    Sheets("result").Range("A" + CStr(CurRow) + ":C" + CStr(CurRow)).Merge
    ' Чтобы не заводить переменную и не писать каждый раз длинный вызов
    ' можно воспользоваться блоком With
    With GetCellS("result", 0, CurRow)
        .Value = Name
        .Font.Italic = True
        .Font.Name = "Cambria"
        Select Case Ty
        Case 1 ' Тип
            .Font.Bold = True
            .Font.Size = 16
        Case 2 ' Производитель
            .Font.Size = 12
        End Select
        .HorizontalAlignment = xlCenter
    End With
    CurRow = CurRow + 1
End Sub

Уже лучше:

Осталось только сделать границы. Тут уже нам требуется работать со всеми объединёнными ячейками, иначе бордюр будет только у одной:

Поэтому чуть-чуть меняем код с добавлением стиля границ:

Sub AddHeader(Ty As Integer, Name As String)
    With Sheets("result").Range("A" + CStr(CurRow) + ":C" + CStr(CurRow))
        .Merge
        .Value = Name
        .Font.Italic = True
        .Font.Name = "Cambria"
        .HorizontalAlignment = xlCenterSelect Case Ty
        Case 1 ' Тип
            .Font.Bold = True
            .Font.Size = 16
            .Borders(xlTop).Weight = xlThick
        Case 2 ' Производитель
            .Font.Size = 12
            .Borders(xlTop).Weight = xlMedium
        End Select
        .Borders(xlBottom).Weight = xlMedium ' По убыванию: xlThick, xlMedium, xlThin, xlHairline
    End With
    CurRow = CurRow + 1
End Sub

Осталось лишь добится пропусков перед началом новой группы. Это легко:

В начале FormatPrice

Dim I As Integer ' строка в  data
CurRow = 0 ' чтобы не было пропуска в самом начале
Dim Groups(1 To GroupsCount) As String

В цикле расстановки заголовков

If Groups(I2) <> PrGroups(I2) Then
    CurRow = CurRow + 1
    Dim I3 As Integer

В точности то, что и хотели.

Надеюсь, что эта статья помогла вам немного освоится с программированием для Excel на VBA. Домашнее задание — добавить заголовки «ID, Название, Цена» в результат. Подсказка: CurRow = 0 CurRow = 1.

Файл можно скачать тут (min.us) или тут (Dropbox). Не забудьте разрешить исполнение макросов. Если кто-нибудь подскажет человеческих файлохостинг, залью туда.

Спасибо за внимание.

Буду рад конструктивной критике в комментариях.

UPD: Перезалил пример на Dropbox и min.us.

UPD2: На самом деле, при вызове процедуры с одним параметром скобки можно поставить. Либо использовать конструкцию Call Foo(«bar», 1, 2, 3) — тут скобки нужны постоянно.

Понравилась статья? Поделить с друзьями:
  • Макрос на поиск решения в excel
  • Макрос на подбор параметра в excel
  • Макрос на очистку ячейки в excel
  • Макрос на открытия другой книги в excel
  • Макрос на открытие формы в excel