惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
量子位
MongoDB | Blog
MongoDB | Blog
N
Netflix TechBlog - Medium
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog
A
About on SuperTechFans
腾讯CDC
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
雷峰网
雷峰网
Last Week in AI
Last Week in AI
H
Help Net Security
WordPress大学
WordPress大学
博客园 - 司徒正美
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
Tailwind CSS Blog
博客园 - 【当耐特】
S
SegmentFault 最新的问题
美团技术团队
M
MIT News - Artificial intelligence
L
LangChain Blog
博客园 - 聂微东

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания
Как правильно управлять диалогами в QML: Singleton + Java...
slavacpp · 2026-05-08 · via Все публикации подряд на Хабре

Почему управление диалогами в QML почти всегда сделано плохо

Уже не первый раз сталкиваюсь в проектах на Qt QML с проблемой управления диалогами и всплывающими окнами.

QML — декларативный язык и это здорово! Мы описываем, что хотим видеть на экране, и, если всё сделали правильно, при запуске программы получаем желаемый результат.

Но иногда хочется динамики — и именно с диалогами начинаются проблемы, которые все решают по-разному. Кто-то продолжает так же декларативно описывать диалог для очередного экрана приложения. Да, так можно поступить, но у этого подхода есть несколько проблем.

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

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

Другой вариант, который тоже часто встречается — это обёртка диалога в Component и его непосредственное создание в нужный момент. С точки зрения потребления памяти это уже лучше, но проблему лишнего кода это не решает. Зачастую из-за подготовки такого диалога кода может оказаться даже больше. К тому же нужно не забывать вызывать destroy() для всех динамически созданных объектов, когда они больше не нужны.

Всё становится ещё хуже, если один и тот же диалог нужен в нескольких местах. В большинстве случаев люди либо не парятся, либо им просто некогда — и в итоге мы видим обычную копипасту тут и там.

Я хочу предложить совсем другой вариант — более простой и удобный.

Singleton + JavaScript Promise

Я хочу предложить совсем другой вариант, который проще и удобнее: это связка QML Singleton и JavaScript Promise.

Создаем Singleton от QtObject и добавляем в него readonly property Component, в котором будет находится экземпляр нашего диалога, и который мы будем создавать только тогда, когда он нам действительно нужен. В качестве диалога я выбрал стандартный Dialog из модуля QtQuick.Controls. Быстрый и простой вариант выглядит так:

readonly property Component instancer: Component {
    Dialog {
        id: dlg
        anchors.centerIn: Overlay.overlay
        property variant context: null
        property string text: ""
        modal: true
        standardButtons: Dialog.Yes | Dialog.No
        closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside
        // Действия по кнопке сбросят контекст, чтобы не было повторного вызова
        // reject при закрытии диалога
        onAccepted: { context?.accept?.(); context = null; }
        onRejected: { context?.reject?.(); context = null; }
        Label { width: parent.width; text: dlg.text; visible: text }
    }
}

Здесь в качестве свойства context выступает обычный Object из JavaScript, в котором два свойства: accept и reject. Оба этих свойства — функции, которые связаны с нашим Promise.

Теперь добавим в наш Singleton функцию, которая будет показывать диалог и возвращать Promise:

function open(options, parent) {
    return new Promise((resolve, reject) => {
        const context = Object.freeze({
            accept: resolve,
            reject: reject,
        });
        options.context = context;
        const dialog = root.instancer.createObject(parent, options);
        dialog.closed.connect(() => {
            dialog.context?.reject?.();
            dialog.destroy();
        });
        dialog.open();
    });
}

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

Дальше создаем наш диалог из компонента и подписываемся на его событие закрытия, чтобы вызвать destroy и освободить память. Здесь так же может вызваться reject, но только в том случае, если пользователь закрыл диалог не по кнопке, а, например, нажал ESC на клавиатуре.

Собственно, на этом все — нашим Singleton теперь можно пользоваться. Например вот так, по нажатию на кнопку:

Button {
    text: "Confirm"
    onClicked: {
        ConfirmDialog.open({
            title: "Dialog title",
            text: "Dialog body text",
        }, root)
        .then(() => console.log("Accepted"))
        .catch(() => console.log("Rejected"));
    }
}

Не забываем только добавить pragma Singleton в начало файла нашего Singleton и правильно зарегистрировать его в CMake:

set_source_files_properties(
    qml/ConfirmDialog.qml
    PROPERTIES
        QT_QML_SINGLETON_TYPE TRUE
)