0Pricing
Learn Rust Coding · Урок

Основы интерфейса немедленного режима

Поймите, как egui выполняет отрисовку.

«Основы интерфейса немедленного режима» — бесплатный урок Learn Rust Coding на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Learn Rust Coding, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Learn Rust Coding содержит 4 уроков всего.

Что означает непосредственный режим

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

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

Цикл обновления

Приложение egui реализует eframe::App, метод update которого вызывается один раз за кадр, обычно 60 раз в секунду.

Внутри update Вы описываете, как интерфейс должен выглядеть прямо сейчас, исходя из текущего состояния. egui ничего не сравнивает — он просто заново создаёт всё содержимое.

impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _f: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.label("Hello, egui!");
        });
    }
}

Контекст и Ui

Два основных типа встречаются повсюду. egui::Context — это общий, недорого клонируемый дескриптор всего состояния интерфейса в текущем кадре.

Ui — это область, в которую Вы добавляете виджеты. Панели и окна передают Вам &mut Ui внутри своего замыкания; в нём Вы вызываете методы вроде ui.label или ui.button.

egui::CentralPanel::default().show(ctx, |ui| {
    ui.heading("Dashboard");
    ui.separator();
    ui.label("Widgets go here.");
});

Виджеты возвращают ответы

Поскольку интерфейс перестраивается в каждом кадре, Вы не можете регистрировать обратные вызовы так, как это делают наборы инструментов с сохранением состояния. Вместо этого каждый вызов виджета сразу возвращает объект Response.

Вы проверяете Response в том же кадре: .clicked(), .hovered(), .changed(). Благодаря этому обработка событий выполняется непосредственно рядом с описанием размещения.

if ui.button("Save").clicked() {
    self.save();
}
let resp = ui.text_edit_singleline(&mut self.name);
if resp.changed() {
    self.dirty = true;
}

Состояние хранится в Вашем коде

egui почти не хранит данные приложения. Значения виджетов находятся в self структуры App, а в виджеты передаются изменяемые ссылки.

Текстовое поле принимает &mut String, а флажок — &mut bool. egui записывает изменения обратно по ссылке, поэтому Ваша структура является единственным источником истины.

struct MyApp {
    name: String,
    enabled: bool,
}

// inside update:
ui.text_edit_singleline(&mut self.name);
ui.checkbox(&mut self.enabled, "Enabled");

Настройка eframe

eframe — официальный фреймворк, размещающий egui на компьютере и в веб-среде. Он управляет нативным окном, поверхностью GPU и циклом событий.

Запуск выполняется с помощью eframe::run_native: передайте заголовок окна, нативные параметры и замыкание, создающее Ваш App.

fn main() -> eframe::Result<()> {
    let opts = eframe::NativeOptions::default();
    eframe::run_native(
        "My App",
        opts,
        Box::new(|_cc| Ok(Box::new(MyApp::default()))),
    )
}

Перерисовка по событию ввода

По умолчанию egui перерисовывает интерфейс только при каком-либо событии: перемещении мыши, нажатии клавиши или явном запросе. Это экономит CPU в бездействующих приложениях.

Для анимаций или актуальных данных вызовите ctx.request_repaint(), чтобы запланировать ещё один кадр, либо request_repaint_after с интервалом для обновлений по времени.

ui.label(format!("Tick: {}", self.counter));
self.counter += 1;
ctx.request_repaint(); // keep animating

Почти никаких сохраняемых идентификаторов виджетов

egui выводит идентификатор виджета из порядка и положения вызовов, автоматически создавая Id. Это важно для таких элементов, как сворачиваемые заголовки, которым нужна стабильная память между кадрами.

Если два виджета могут столкнуться — например, кнопки с одинаковой подписью в цикле, — оберните их в ui.push_id(i, |ui| ...), чтобы различать их.

for (i, item) in self.items.iter().enumerate() {
    ui.push_id(i, |ui| {
        if ui.button(&item.label).clicked() {
            println!("clicked {}", i);
        }
    });
}

Компромиссы непосредственного режима

Непосредственный режим делает код интерфейса естественно управляемым данными: if показывает или скрывает раздел, а for отображает список. Не требуется вручную добавлять или удалять узлы, и модель с представлением не рассинхронизируются.

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

if self.logged_in {
    ui.label(format!("Welcome, {}", self.user));
} else {
    ui.label("Please sign in.");
}

Минимальное полноценное приложение

Соберём всё вместе: структура хранит состояние, update отображает его, а main запускает окно. Это весь каркас любой настольной программы на egui.

Всё остальное — размещение, оформление, упаковка — строится на этом цикле.

#[derive(Default)]
struct App { count: i32 }

impl eframe::App for App {
    fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            if ui.button("+1").clicked() { self.count += 1; }
            ui.label(format!("Count: {}", self.count));
        });
    }
}

Почему Rust отлично подходит для egui

Дизайн egui использует сильные стороны Rust. Передача &mut self в один вызов update означает, что проверка заимствований гарантирует отсутствие гонок данных между виджетами и Вашей моделью.

Нет обратных вызовов, захватывающих общее изменяемое состояние, и нет графов Rc<RefCell>, навязанных деревом с сохранением состояния, — только обычное владение и один изменяемый проход за кадр.

Быстрая проверка

Проверьте, насколько хорошо Вы поняли непосредственный режим.

Итоги

egui работает в непосредственном режиме: весь интерфейс перестраивается в каждом кадре внутри eframe::App::update. Виджеты являются вызовами функций, сразу возвращающими объект Response, который Вы проверяете.

Ваши данные хранятся в self и передаются по изменяемой ссылке, поэтому проверка заимствований поддерживает синхронность модели и представления. eframe::run_native управляет окном и циклом событий. Далее Вы изучите набор виджетов и систему размещения.

Часто задаваемые вопросы

Урок «Основы интерфейса немедленного режима» бесплатный?

Да — полный текст урока «Основы интерфейса немедленного режима» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Learn Rust Coding, подпишись на CoddyKit PRO. Курс Learn Rust Coding содержит 4 уроков всего.

Чему я научусь в уроке «Основы интерфейса немедленного режима»?

Поймите, как egui выполняет отрисовку. Ты практикуешь Learn Rust Coding с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Learn Rust Coding?

Предыдущий опыт не требуется. Learn Rust Coding на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Основы интерфейса немедленного режима»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Learn Rust Coding?

Да. Каждый урок Learn Rust Coding включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы интерфейса немедленного режима
  2. Виджеты и компоновка
  3. Управление состоянием приложения
  4. Сборка настольного приложения
← Назад к Learn Rust Coding