Управление текстовыми полями в презентациях PowerPoint на Python

Обзор

Текстовый абзац состоит из частей. Обычная Portion содержит буквальный текст; часть‑поле также имеет Field, тип которой определяет автоматически обновляемое значение, например номер слайда или дату. Две части могут отображать одинаковые символы, при этом только одна содержит поле.

Используйте Portion.field чтобы различать их: для обычного текста он равен None. Portion.add_field преобразует существующую часть в поле. Держите метку и её динамическое значение в отдельных частях, чтобы преобразование значения не заменило также метку.

Это руководство охватывает поля внутри текста, их форматирование и сохранение в PPTX и PPT. Для текстовых рамок и абзацев см. Управление текстом.

Создание поля номера слайда

В следующем полном примере создаётся текстовое поле, содержащее буквальную метку Slide , за которой следует автоматически обновляемый номер. Перед добавлением поля задаются размер, насыщенность и цвет номера, затем открывается сохранённая презентация и проверяются тип поля, текст и форматирование. Входной файл не требуется.

import aspose.pydrawing as draw
import aspose.slides as slides

with slides.Presentation() as presentation:
    slide = presentation.slides[0]
    shape = slide.shapes.add_auto_shape(slides.ShapeType.RECTANGLE, 40, 40, 240, 50)
    shape.add_text_frame("Slide ")
    paragraph = shape.text_frame.paragraphs[0]

    number_portion = slides.Portion()
    number_portion.portion_format.font_height = 24
    number_portion.portion_format.font_bold = slides.NullableBool.TRUE
    number_portion.portion_format.fill_format.fill_type = slides.FillType.SOLID
    number_portion.portion_format.fill_format.solid_fill_color.color = draw.Color.dark_blue
    paragraph.portions.add(number_portion)
    number_portion.add_field(slides.FieldType.slide_number)

    presentation.save("slide_number.pptx", slides.export.SaveFormat.PPTX)

with slides.Presentation("slide_number.pptx") as reopened:
    saved_shape = reopened.slides[0].shapes[0]
    saved_number = saved_shape.text_frame.paragraphs[0].portions[1]
    has_number_field = saved_number.field is not None and saved_number.field.type.internal_string == slides.FieldType.slide_number.internal_string
    portion_format = saved_number.portion_format
    formatting_preserved = portion_format.font_height == 24 and portion_format.font_bold == slides.NullableBool.TRUE
    formatting_preserved &= portion_format.fill_format.solid_fill_color.color.to_argb() == draw.Color.dark_blue.to_argb()

    print(f"Text: {saved_shape.text_frame.text}")
    print(f"Slide number field: {has_number_field}")
    print(f"Formatting preserved: {formatting_preserved}")

Новая презентация начинается с номера слайда 1, поэтому текст равен Slide 1, и обе проверки выводят True. После переоткрытия номер остаётся полем; это не буквальная 1. Индексы в проверке относятся к фигуре и частям, созданным в этом примере.

Выбор типа поля

FieldType предоставляет следующие предопределённые значения. Передайте соответствующее значение в add_field.

Значение Назначение
slide_number Текущий номер слайда.
date_time Дата/время в формате по умолчанию приложения рендеринга.
date_time1date_time9 Предопределённый формат даты или комбинированный формат даты/времени.
date_time10date_time13 Предопределённые форматы времени, с опциями для секунд и 12‑часового формата.
header Поле заголовка; см. ограничения заполнителя и формата ниже.
footer Поле нижнего колонтитула.

Например, date_time3 представляет день, полное название месяца и год на английском. Это предопределённые форматы полей, а не произвольные строки формата даты Python. language_id части и приложение, обрабатывающее презентацию, могут влиять на отображаемый результат.

Создание поля из внутренней строки

Перегрузка строкового параметра метода add_field принимает внутренний идентификатор поля. Используйте её, когда нужно сохранить идентификатор, предоставленный другим приложением, у которого нет предопределённого значения. Вы также можете создать объект FieldType из идентификатора. FieldType.internal_string раскрывает этот идентификатор для просмотра.

В этом примере сохраняется поле custom-report-id, специфичное для приложения, с запасным текстом Report-042. Идентификатор не регистрирует вычисление: Aspose.Slides не генерирует идентификаторы отчётов для неизвестного типа. Приложение, которое понимает этот идентификатор, должно предоставить его смысл и обновлять значение.

import aspose.slides as slides

with slides.Presentation() as presentation:
    shape = presentation.slides[0].shapes.add_auto_shape(slides.ShapeType.RECTANGLE, 40, 40, 300, 50)
    shape.add_text_frame("Report-042")
    portion = shape.text_frame.paragraphs[0].portions[0]
    portion.add_field("custom-report-id")

    presentation.save("custom_field.pptx", slides.export.SaveFormat.PPTX)

with slides.Presentation("custom_field.pptx") as reopened:
    saved_shape = reopened.slides[0].shapes[0]
    saved_portion = saved_shape.text_frame.paragraphs[0].portions[0]
    type_name = saved_portion.field.type.internal_string if saved_portion.field is not None else "ordinary text"
    print(f"Type: {type_name}")
    print(f"Text: {saved_portion.text}")

После этого цикла PPTX тип остаётся custom-report-id, а текст — Report-042. Передача строки вроде %Y-%m-%d задаст тип поля; она не настроит пользовательский формат даты. Для фиксированной даты в произвольном формате используйте обычный текст.

Просмотр, изменение и удаление полей даты/времени

Прочитайте и измените существующее поле через Field.type. Проверьте, что поле существует, прежде чем обращаться к его типу. Чтобы остановить автоматические обновления, вызовите Portion.remove_field. Это сохраняет часть и её текущий текст, удаляя связь с полем. Если нужен конкретный фиксированный результат, присвойте этот текст после удаления поля.

Настройку API, связанную с обработкой полей даты/времени, см. в Presentation.current_date_time. Пример ниже использует явную дату утверждения при преобразовании поля в обычный текст. Кортеж названий месяцев на английском сохраняет фиксированную дату независимо от региональных настроек системы.

Скачайте sample.pptx и разместите его в рабочем каталоге. Файл содержит две именованные текстовые фигуры UpdatedAt и ApprovedDate, каждая с полем даты/времени, а также обычные текстовые метки. Ниже приведён пример обхода текстовых фигур верхнего уровня на обычных слайдах. Он меняет поля даты/времени на длинный формат даты и делает их курсивом, сохраняя остальное форматирование. Только поля в ApprovedDate становятся фиксированным текстом.

Пример распознаёт встроенные внутренние идентификаторы datetime и datetime1datetime13. Группы, таблицы, заметки, макеты и шаблоны требуют обхода их собственных контейнеров текста и не охвачены данным примером.

from datetime import date

import aspose.slides as slides

with slides.Presentation("sample.pptx") as presentation:
    approval_date = date(2030, 4, 5)
    english_months = ("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December")
    approval_text = f"{approval_date.day:02d} {english_months[approval_date.month - 1]} {approval_date.year}"
    date_time_types = {"datetime"} | {f"datetime{index}" for index in range(1, 14)}

    for slide in presentation.slides:
        for shape in slide.shapes:
            if not isinstance(shape, slides.AutoShape) or shape.text_frame is None:
                continue

            for paragraph in shape.text_frame.paragraphs:
                for portion in paragraph.portions:
                    field = portion.field
                    if field is None:
                        continue

                    if field.type.internal_string not in date_time_types:
                        continue

                    field.type = slides.FieldType.date_time3
                    portion.portion_format.language_id = "en-US"
                    portion.portion_format.font_italic = slides.NullableBool.TRUE

                    if shape.name == "ApprovedDate":
                        portion.remove_field()
                        portion.text = approval_text

    presentation.save("updated_dates.pptx", slides.export.SaveFormat.PPTX)

with slides.Presentation("updated_dates.pptx") as reopened:
    for shape in reopened.slides[0].shapes:
        if not isinstance(shape, slides.AutoShape) or shape.text_frame is None:
            continue
        if shape.name not in {"UpdatedAt", "ApprovedDate"}:
            continue

        portion = shape.text_frame.paragraphs[0].portions[0]
        type_name = portion.field.type.internal_string if portion.field is not None else "ordinary text"
        print(f"{shape.name}: {type_name}; {portion.text}")
        print(f"Italic: {portion.portion_format.font_italic == slides.NullableBool.TRUE}")

После переоткрытия UpdatedAt имеет тип datetime3 и остаётся динамичным. ApprovedDate не содержит поля и содержит 05 April 2030. Обе части даты курсивом, при этом их исходный размер шрифта, жирность и цвет сохраняются. Обычные текстовые метки не изменились. Проверка читает первую часть двух известных фигур в предоставленном образце.

Сохранение форматирования текста

Работайте с существующей частью при добавлении поля, изменении его типа или удалении. Эти операции сохраняют форматирование части. Используйте Portion.portion_format для изменения только необходимых свойств, как в примерах для цвета или курсива.

Избегайте перестройки всей текстовой рамки лишь для обновления одного поля: это может привести к потере оригинальных границ частей и их индивидуального форматирования. Также различайте явно установленное форматирование и наследуемое из абзаца, макета или темы. См. Форматирование текста для более широких вариантов форматирования.

Поля и заполнители заголовка/подвала

Поле является частью текстовой части. Заполнитель — это фигура с ролью в презентации, например нижний колонтитул или номер слайда. Добавление поля в обычный текстовый блок не превращает эту фигуру в заполнитель.

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

Предопределённые типы заголовка и подвала не создают соответствующие заполнители и не предоставляют их содержимое. В частности, обычный слайд PowerPoint не имеет заполнителя заголовка; заголовки относятся к страницам заметок и раздаточным материалам. Не следует полагать, что поле заголовка или подвала в произвольной фигуре автоматически получит текст, настроенный через менеджер заполнителей. Для такого процесса см. Presentation Headers and Footers.

Ограничения PPTX и PPT

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

Формат Поведение поля и ограничения
PPTX Сохраняет внутренние идентификаторы полей вместе с их текстом. При проверках кругового прохода предопределённые типы и пользовательский идентификатор, использованный выше, выжили после сохранения и переоткрытия. Неизвестный пользовательский тип сохранил свой запасный текст; он не получил автоматической логики расчёта. Другое приложение может обрабатывать неподдерживаемые идентификаторы по‑другому.
PPT Использует устаревшие представления полей и имеет более ограниченную совместимость. При проверках кругового прохода поля номера слайда и предопределённые поля даты/времени выжили после сохранения и переоткрытия. Пользовательское поле в обычном текстовом блоке слайда открылось с его идентификатором, но с текстом *; поле заголовка в том же контексте также дало *. Не полагайтесь на то, что пользовательские поля или неподдерживаемые контексты полей сохранят видимый текст.

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

FAQ

Как определить, является ли отображаемый номер или дата полем?
Проверьте Portion.field. Значение, отличное от None, указывает на поле; один лишь отображаемый текст не может дать ответ.

Удаление поля удаляет его текст или форматирование?
Нет. remove_field преобразует существующую часть в обычный текст. При необходимости конкретной фиксированной даты или запасного значения задайте его явно после удаления.

Может ли внутренняя строка определить новый формат даты или формулу?
Нет. Она идентифицирует тип поля. Неизвестный идентификатор не предоставляет вычислитель или шаблон формата даты Python. Используйте поддерживаемый предопределённый тип или отформатируйте значение самостоятельно как обычный текст.

Зачем снова проверять презентацию после её сохранения?
Идентификаторы полей, вычисляемый текст и форматирование — это отдельные элементы, которые нужно проверять. При конвертации формата видимый результат может измениться, даже если идентификатор поля остаётся.