---
title: "Закрепление областей и автофильтры"
description: "Excelize freeze panes: SetPanes закрепляет шапку листа, autofilter excelize вешает фильтр и прячет строки. Сортировку делает пользователь в Excel."
course: "Excel в Go: чтение и генерация xlsx на excelize"
url: "https://golangmaster.ru/courses/excelize/lessons/15-zakreplenie-filtry/"
published: "2026-09-19"
updated: "2026-09-21"
minutes: 16
---

# Закрепление областей и автофильтры

*Курс «Excel в Go: чтение и генерация xlsx на excelize», урок 15 из 25. ~16 минут. Обновлено 21.09.2026. Источник: https://golangmaster.ru/courses/excelize/lessons/15-zakreplenie-filtry/*

Запрос excelize freeze panes приходит, когда выгрузка выросла: триста строк вниз — и шапка с названиями колонок уехала за экран, а получатель листает туда-обратно, вспоминая, что в колонке E. Закрепление областей держит шапку на месте при прокрутке, а AutoFilter ставит на диапазон фильтр с кнопками. В уроке разберём SetPanes с закреплением строки и колонки, выражения фильтра, скрытые строки и честное разделение труда: сортировку и фильтрацию на живом файле делает пользователь в Excel, а генератор готовит файл к этой работе.

Отчёт из прошлых уроков собран: данные записаны, шапка оформлена и объединена, итоги считаются формулами, график стоит рядом. Остался слой удобства, который отличает файл для работы от файла для просмотра: на длинной выгрузке без закрепления шапки листать тяжело, а без фильтра — выбирать нужные строки руками. Обе вещи делаются вызовами на листе и не трогают данные: закрепление описывает окна, фильтр — признаки строк. Именно поэтому их удобно ставить последним слоем генерации, когда данные уже лежат, и стили уже прикладываются к готовым диапазонам. На длинных списках эта пара меняет отношение получателя к файлу заметнее, чем любое оформление: шапка видна на каждом экране, а отбор строк занимает клик, а не двадцать минут правок. Есть и скрытая сторона, о которой стоит знать заранее: выражение фильтра excelize применяет сама, пряча неподошедшие строки в файле, и чтение своего файла станет неожиданностью, если забыть про скрытые строки. Разберём обе темы по очереди: сначала окна, потом фильтры, а в конце — честный разговор о сортировке, за которой excelize не идёт.

### SetPanes: excelize freeze panes для шапки

Закрепление настраивает метод f.SetPanes с двумя аргументами: лист и указатель на структуру Panes. Чтобы закрепить первую строку, пишут Freeze: true, YSplit: 1 — число закреплённых строк сверху, TopLeftCell: "A2" — первая ячейка прокручиваемой области, и ActivePane: "bottomLeft" — активное окно. Ячейка TopLeftCell обязана совпадать с границей закрепления: закрепили одну строку — прокручиваемая область начинается с A2, закрепили строку и колонку — с B2. Рассинхрон даёт странную прокрутку: области либо наезжают, либо прыгают, и пользователь обвинит ваш файл в поломке. Закрепить колонку слева — XSplit: 1, ActivePane: "topRight"; вместе — обе величины и ActivePane: "bottomRight". Снимается закрепление той же SetPanes с Freeze: false и нулевыми сплитами — приём для перегенерации файла, где шапка уже не нужна. Запрос excelize freeze panes на практике сводится к этой четвёрке полей, и она покрывает и шапку, и боковую колонку с наименованиями.

### Шапка и первая колонка закреплены

```go
if err := f.SetPanes("Отчёт", &excelize.Panes{
    Freeze:      true,
    XSplit:      1,
    YSplit:      1,
    TopLeftCell: "B2",
    ActivePane:  "bottomRight",
}); err != nil {
    panic(err)
}
```

Одна строка и одна колонка закреплены: при прокрутке вниз уезжают данные, а заголовки колонок остаются, при прокрутке вправо остаётся колонка с наименованиями. TopLeftCell B2 — угол прокручиваемой области, ActivePane bottomRight говорит Excel, какое окно активно.

> **TopLeftCell — часть контракта.** Поля Panes работают в связке: YSplit 1 при TopLeftCell A1 — рассинхрон, и прокрутка ведёт себя странно. Держите соответствие: закрепили YSplit строк сверху — TopLeftCell начинается с колонки A и строки YSplit плюс один; добавили XSplit колонок слева — сдвиньте и букву. Правило для снятия то же: Freeze false, нули в сплитах и TopLeftCell A1 возвращают листу обычное окно.

### AutoFilter: autofilter excelize и выражения

Фильтр ставится вызовом f.AutoFilter с тремя аргументами: лист, диапазон и срез AutoFilterOptions. Пустой срез вешает на шапку диапазона кнопки фильтра — Excel покажет выпадающие списки со значениями колонок, и пользователь отберёт строки сам. Для готового среза на момент генерации есть выражение: AutoFilterOptions с Column — буквой колонки относительно начала диапазона — и Expression строкой вида "x > 1000", где x — значение ячейки. Выражения поддерживают сравнения вроде "x != 2" и логику "x == 1 or x == 2", а пустые ячейки отбираются через blank. Отличие от Excel в моменте применения: excelize вычисляет выражение сама и прячет неподошедшие строки в файле, помечая их скрытыми, — фильтр живёт не только в кнопках, но и в разметке строк. Отсюда и уроки чтения: GetRows по умолчанию вернёт и скрытые строки, поэтому парсер своего отфильтрованного файла обязан помнить о них или читать с учётом скрытия.

### Фильтр по порогу на колонку

```go
if err := f.AutoFilter("Отчёт", "A1:D21", []excelize.AutoFilterOptions{
    {Column: "C", Expression: "x > 1000"},
}); err != nil {
    panic(err)
}

f.SetPanes("Отчёт", &excelize.Panes{
    Freeze:      true,
    YSplit:      1,
    TopLeftCell: "A2",
    ActivePane:  "bottomLeft",
})
```

Фильтр по колонке C отберёт строки со значением больше тысячи: excelize спрячет остальные, кнопки фильтра встанут на шапку. Сразу закреплена первая строка — и шапка с кнопками не уедет при прокрутке отфильтрованного списка.

### Сортировка: кто отвечает за порядок строк

Фильтр на листе соседствует с сортировкой, и здесь нужен честный разговор: AutoFilter API сортировку не задаёт. Кнопка сортировки в Excel работает на живом файле: пользователь кликает по стрелке в фильтре и выстраивает строки как хочет — генератор на это не влияет. Если порядок нужен на момент генерации, сортируйте в Go до записи: sort.Slice по нужному полю, затем цикл записи — файл хранит строки ровно в том порядке, в каком их записали. Практическая схема такая: дефолтный порядок задаёт генератор — по дате, по коду, по сумме; конечный порядок и сортировку выбирает пользователь на живом файле. Отпустить сортировку в руки получателя — не потеря контроля, а спокойная работа: файл с фильтром приглашает к своим перестановкам, и никому не нужно просить пересобрать выгрузку в другом порядке.

### Порядок и локали: сравнение строк в Go

Есть тонкость, которая проявляется на русских данных: сравнение строк в Go идёт байтами, и русский текст сортируется им не как в Excel. Регистры раскладываются иначе, буква ё живёт за пределами основного алфавита, и наивный sort выдаёт порядок, в котором Заголовок встанет рядом с заголовком, но между ними влезет ёлка. Для человеческого порядка строки сравнивают готовыми коллаторами или приводят к одному регистру и нормализуют ё перед сравнением — тема знакомая по уроку про строки и руны базового курса. Числа сортируются честно, если читаются числами: сравнивать значения из строк GetRows лексикографически — типовая ошибка, где 1000 встанет раньше 900. Запрос autofilter excelize так и закрывается: фильтр и закрепление ставит код, сортировку и порядок — человек, а генератор готовит ему честный дефолт.

### Поля Panes и AutoFilterOptions

| Поле | Пример | Смысл |
| --- | --- | --- |
| Freeze | true | включает закрепление областей |
| XSplit, YSplit | 1, 1 | число закреплённых колонок и строк |
| TopLeftCell | "B2" | первая ячейка прокручиваемой области |
| ActivePane | "bottomRight" | какое окно активно после открытия |
| Column | "C" | колонка фильтра от начала диапазона |
| Expression | "x > 1000" | выражение отбора, x — значение ячейки |

> **Фильтр — это не удаление.** Скрытые строки остаются в файле со всеми данными: GetRows прочитает их, как и видимые, если не оговаривать обратное. Для машины фильтр ничего не убирает — он меняет отображение и держит признак скрытия в разметке строки. Если выгрузка предназначена машине, фильтр со скрытием смысла не добавляет: отбирайте строки в Go и пишите только нужные.

### Чек-лист закрепления и фильтров

- SetPanes принимает указатель на Panes: Freeze, XSplit, YSplit, TopLeftCell, ActivePane.
- YSplit закрепляет строки сверху, XSplit — колонки слева; TopLeftCell обязан совпадать с границей.
- Снятие — та же SetPanes с Freeze false и нулями: перегенерация не должна копить настройки.
- AutoFilter вешает фильтр на диапазон; пустой срез опций даёт только кнопки.
- Expression вида x > 1000 excelize применяет сама: неподошедшие строки прячет в файле.
- Сортировку не задаёт ни один из вызовов: порядок на генерации делает sort в Go, на живом файле — пользователь.

> **В песочнице файлов нет.** SetPanes и AutoFilter требуют книги на диске, поэтому в браузерной песочнице не запускаются: там доступны fmt, strings, strconv, math, sort, errors и time без файлового ввода-вывода. Сортировку потренировать можно: sort.Slice по структуре из пары полей и печать результата — логика та же, что при подготовке порядка строк, а файл соберите локально.

Кейс про выгрузку, которую листали вслепую. Ежедневная выгрузка на двадцать тысяч строк уходила руководителям без закреплений и фильтра: шапка уезжала на втором экране, колонки путались, а на вопросы «покажи строки больше ста тысяч» подчинённые фильтровали вручную и отправляли копии. В генератор добавили два вызова: SetPanes с закреплённой шапкой и колонкой наименований, AutoFilter на весь диапазон с пустыми опциями — кнопки без готового среза. Отдельный вопрос встал с выражением: сначала поставили Expression по умолчанию под самый частый запрос, но получили жалобу, что в файле «строки пропали» — получатель не заметил скрытых строк и посчитал выгрузку неполной. Выражение убрали, кнопки оставили: срез делает пользователь на живом файле. Спорная сторона осталась в команде: кто-то считает, что готовый срез экономит время, и держит отдельную версию с Expression для себя; общий файл — без скрытых строк, потому что доверие к выгрузке дороже одного клика.

### Проверка: что закрепится

**Вопрос:** Что закрепит SetPanes("Отчёт", &excelize.Panes{Freeze: true, YSplit: 1, TopLeftCell: "A2", ActivePane: "bottomLeft"})?

- ✅ Первую строку сверху при прокрутке
- Первую колонку слева при прокрутке
- Первую строку и первую колонку
- Ничего: YSplit про высоту окна

YSplit задаёт число закреплённых строк сверху — здесь одна, шапка. Колонку слева закрепляет XSplit, обе величины сразу дают закрепление крестом, а TopLeftCell A2 подтверждает: прокручиваемая область начинается со второй строки.

### Проверка: куда делись строки

**Вопрос:** После AutoFilter с Expression "x > 1000" парсер читает файл через GetRows. Что он увидит для строк, не подошедших под условие?

- ✅ Строки на месте: фильтр прячет их в файле, но не удаляет
- Строки удалены: их в файле больше нет
- Пустые строки вместо значений
- Ошибку: чтение скрытых строк запрещено

Excelize вычисляет выражение и помечает неподошедшие строки скрытыми — данные остаются в файле, и GetRows их вернёт. Для машины фильтр — признак отображения, а не удаление: отбор под парсер делайте в Go.

### Сколько строк вернёт чтение?

```go
for i := 1; i <= 20; i++ {
    f.SetCellValue("Sheet1", fmt.Sprintf("B%d", i), i*100)
}

f.AutoFilter("Sheet1", "A1:B21", []excelize.AutoFilterOptions{
    {Column: "B", Expression: "x >= 1500"},
})

rows, _ := f.GetRows("Sheet1")
fmt.Println(len(rows))
```

**Что выведет программа?**

- ✅ 21: фильтр прячет строки, чтение видит все
- 7: только строки со значениями от 1500
- 14: скрытых строк в GetRows нет
- 22: шапка посчитается дважды

Диапазон A1:B21 содержит 21 строку, и все они в файле: выражение спрятало неподошедшие, но не удалило их, а GetRows возвращает и скрытые. Число строк чтения от фильтра не зависит — это и есть ловушка парсера.

### Соберите шапку и фильтр

Допишите закрепление, число закреплённых строк, фильтр и поле выражения.

```go
f.___("Отчёт", &excelize.Panes{
    Freeze:      true,
    ___:         1,
    TopLeftCell: "A2",
})

f.___("Отчёт", "A1:D21", []excelize.AutoFilterOptions{
    {Column: "C", ___: "x > 1000"},
})
```

Подсказка: Закрепление ставит SetPanes, число строк сверху — YSplit, фильтр на диапазон — AutoFilter, отбор по колонке — поле Expression.

Правильные ответы в пропусках: `SetPanes`, `YSplit`, `AutoFilter`, `Expression`

### Соберите выгрузку для работы

Расставьте строки в порядке выполнения: записать шапку, записать строку данных, закрепить шапку, повесить фильтр на диапазон, сохранить файл, закрыть книгу.

Правильный порядок строк:

1. `f.SetCellValue("Отчёт", "A1", "Наименование")`
2. `f.SetCellValue("Отчёт", "A2", "Кофе в зёрнах")`
3. `f.SetPanes("Отчёт", &excelize.Panes{Freeze: true, YSplit: 1, TopLeftCell: "A2"})`
4. `f.AutoFilter("Отчёт", "A1:D21", []excelize.AutoFilterOptions{})`
5. `err := f.SaveAs("otchet.xlsx")`
6. `f.Close()`

### Карточки: закрепление и фильтры

- **SetPanes** — Настраивает окна листа: лист и указатель на Panes. Freeze true включает закрепление, false и нули снимают его.
- **XSplit и YSplit** — Число закреплённых колонок слева и строк сверху. Согласуются с TopLeftCell: одна строка — A2, строка и колонка — B2.
- **AutoFilter** — Вешает фильтр на диапазон: лист, адрес, срез AutoFilterOptions. Пустой срез — только кнопки для пользователя.
- **AutoFilterOptions** — Column — буква колонки от начала диапазона, Expression — условие вида x > 1000, где x — значение ячейки.
- **Скрытые строки** — Excelize применяет выражение сама и прячет неподошедшие строки: данные остаются в файле, GetRows их возвращает.
- **Сортировка** — AutoFilter её не задаёт: порядок на генерации делает sort.Slice до записи, на живом файле — пользователь в Excel.

Навигация готова: шапка закреплена, фильтр вешается вызовом, скрытые строки и сортировка разобраны честно. Первый блок курса экселя закрыт — оформление, вычисления и удобство на месте. Дальше файл начнёт защищать себя сам: в уроке про [защиту листа](/courses/excelize/lessons/16-zashchita-lista/) закрепление получит соседа в виде пароля и прав без редактирования, а в уроке про [StreamWriter](/courses/excelize/lessons/17-potokovyj-zapis/) выгрузка в двадцать тысяч строк соберётся в потоке, без укладки всего листа в память. Чтение данных с фильтрами переплетается с уроком про [GetRows](/courses/excelize/lessons/06-stroki-i-stolbcy/) — там же лежит порядок строк, который здесь обсуждали, а готовая выгрузка для работы собирается в [экспорте отчёта из базы](/courses/excelize/lessons/19-eksport-iz-bd/). Домашнее задание — закрепить шапку и повесить фильтр на свою выгрузку.

## Коротко: что запомнить

- SetPanes закрепляет области: Freeze, XSplit, YSplit, TopLeftCell и ActivePane работают в связке.
- TopLeftCell обязан совпадать с границей закрепления: рассинхрон даёт странную прокрутку.
- AutoFilter вешает фильтр на диапазон; пустой срез опций даёт только кнопки.
- Expression вида x > 1000 excelize применяет сама: неподошедшие строки прячутся, но не удаляются.
- GetRows возвращает и скрытые строки: парсер помнит о фильтре в файле.
- Сортировка не входит в API: порядок на генерации делает sort в Go, на живом файле — пользователь.

## Домашнее задание

Возьмите свою выгрузку на несколько сотен строк: закрепите шапку SetPanes, при необходимости и колонку с наименованиями, повесьте AutoFilter на весь диапазон данных с пустыми опциями. Затем в отдельной версии поставьте Expression по частому запросу и проверьте GetRows: убедитесь, что скрытые строки читаются, а после снятия Freeze файл возвращается к обычному окну.

## Вопросы и ответы по уроку

### Почему закрепление не сработало, хотя SetPanes вернул nil?

Проверьте связку полей: YSplit без TopLeftCell на границе или ошибочный ActivePane дают настройку, которую Excel рисует странно или игнорирует. Рабочая шапка — Freeze true, YSplit 1, TopLeftCell A2, ActivePane bottomLeft; для креста — оба сплита и bottomRight.

### Можно ли через excelize задать сортировку строк?

Нет: ни AutoFilter, ни Panes сортировку не записывают. Отсортируйте данные в Go до записи — sort.Slice по нужному полю — либо оставьте сортировку пользователю: кнопки фильтра в Excel её поддерживают на живом файле.

### После фильтра с Expression часть строк в файле не видна — это норма?

Да: excelize вычислила выражение и пометила неподошедшие строки скрытыми, данные при этом в файле. GetRows по умолчанию вернёт их все; для выгрузки, где скрытых строк быть не должно, отбирайте строки в Go и не ставьте выражение.
