Gerenciamento de Janelas Sobrepostas e Atributos de Topo no Qt

Ao desenvolver interfaces complexas com o Qt, é comum a necessidade de integrar múltiplos arquivos .ui criados no Qt Designer em uma classe principal. Um desafio frequente é garantir que determinadas janelas auxiliares permaneçam à frente (Always on Top) ou funcionem como diálogos controlados manualmente sem bloquear completamente a thread principal.

Quando um arquivo .ui é compilado, o uic gera um cabeçalho correspondente (ex: ui_form_ajustes.h). Esse arquivo define uma classe dentro do namespace Ui que deve ser instanciada para que os componentes visuais sejam acessíveis via código C++.

Estrutura do Cabeçalho (janelaprincipal.h)

Para gerenciar múltiplos widgets customizados, declaramos os ponteiros para as interfaces geradas e os widgets que servirão como containers para essas interfaces.

#ifndef JANELAPRINCIPAL_H
#define JANELAPRINCIPAL_H

#include <QMainWindow>
#include <QWidget>

namespace Ui {
    class JanelaPrincipal;
    class FormConfig;
    class FormStatus;
}

class JanelaPrincipal : public QMainWindow {
    Q_OBJECT

public:
    explicit JanelaPrincipal(QWidget *parent = nullptr);
    ~JanelaPrincipal();

private:
    Ui::JanelaPrincipal *ui_base;
    
    // Interfaces geradas pelo Qt Designer
    Ui::FormConfig *ui_config;
    Ui::FormStatus *ui_status;

    // Widgets containers
    QWidget *containerConfig;
    QWidget *containerStatus;
    QWidget *janelaAtiva = nullptr;
};

#endif // JANELAPRINCIPAL_H

Impelmentação e Controle de Janelas (janelaprincipal.cpp)

O segredo para manter uma janela no topo está no método setWindowFlags utilizando o atributo Qt::WindowStaysOnTopHint. No exemplo abaixo, as janelas são configuradas como diálogos que forçam a sobreposição.

#include "janelaprincipal.h"
#include "ui_janelaprincipal.h"
#include "ui_form_config.h"
#include "ui_form_status.h"
#include <QTimer>
#include <QApplication>
#include <QDebug>

JanelaPrincipal::JanelaPrincipal(QWidget *parent) :
    QMainWindow(parent),
    ui_base(new Ui::JanelaPrincipal)
{
    ui_base->setupUi(this);

    // Inicialização dos containers e das UIs
    containerConfig = new QWidget();
    containerStatus = new QWidget();
    ui_config = new Ui::FormConfig();
    ui_status = new Ui::FormStatus();

    ui_config->setupUi(containerConfig);
    ui_status->setupUi(containerStatus);

    // Configuração de títulos e flags de comportamento
    containerConfig->setWindowTitle("Ajustes do Sistema");
    containerStatus->setWindowTitle("Monitoramento");

    // Define a janela para ficar sempre visível sobre as outras
    containerConfig->setWindowFlags(Qt::Dialog | Qt::WindowStaysOnTopHint);
    containerStatus->setWindowFlags(Qt::Dialog | Qt::WindowStaysOnTopHint);

    // Lógica para abrir a janela de configuração
    connect(ui_base->btnAbrirConfig, &QPushButton::clicked, this, [=]() {
        if(janelaAtiva) janelaAtiva->hide();
        
        containerConfig->show();
        janelaAtiva = containerConfig;
        
        // Desabilita a janela principal para simular um comportamento modal customizado
        this->setEnabled(false);
    });

    // Retorno ao fechar ou cancelar nos widgets secundários
    auto fecharSubjanela = [=]() {
        this->setEnabled(true);
        if(janelaAtiva) {
            janelaAtiva->hide();
            janelaAtiva = nullptr;
        }
    };

    connect(ui_config->btnSalvar, &QPushButton::clicked, this, fecharSubjanela);
    connect(ui_config->btnCancelar, &QPushButton::clicked, this, fecharSubjanela);

    // Monitoramento de foco com Timer para feedback visual
    QTimer* monitorFoco = new QTimer(this);
    connect(monitorFoco, &QTimer::timeout, this, [=]() {
        QWidget *focoAtual = QApplication::activeWindow();
        
        if (janelaAtiva) {
            if (focoAtual == janelaAtiva) {
                // Remove destaque se a janela estiver com foco
                janelaAtiva->setStyleSheet("");
            } else {
                // Aplica uma borda vermelha se o usuário clicar fora da janela ativa
                janelaAtiva->setStyleSheet("border: 2px solid red;");
            }
        }
    });
    monitorFoco->start(200);
}

JanelaPrincipal::~JanelaPrincipal() {
    delete ui_base;
    delete containerConfig;
    delete containerStatus;
    delete ui_config;
    delete ui_status;
}

Diferenças de Modalidade

Ao lidar com janelas no Qt, existem duas abordagens principais para gerenciar o foco:

  1. Qt::ApplicationModal: Bloqueia a interação com todas as outras janelas da aplicação automaticamente. É a forma mais simples de criar um diálogo, mas oferece menos controle sobre animações ou estados intermediários da janela principal.
  2. setWindowFlags com setEnabled: Ao desabilitar manualmente a janela principal (this->setEnabled(false)) e usar a flag WindowStaysOnTopHint, o desenvolvedor ganha flexibilidade. Isso permite, por exemplo, manter processos de background visíveis ou aplicar estilos de CSS (como a borda de alerta no exemplo do timer) quando a atenção do usuário é desviada.

O uso do QApplication::activeWindow() combinado com um QTimer é uma técnica útil para validação em tempo real de interfaces que exigem resopsta imediata do operador, garantindo que janelas críticas não sejam ignoradas atrás de outros elementos da interface.

Tags: Qt C++ QtDesigner QWidget GUI-Development

Publicado em 9-6 03:58