Modelo de Objetos e Contêineres no Qt – Conceitos Essenciais

O framework Qt oferece um conjunto de classes e mecanismos que permitem a criação de interfaces gráficas eficientes e flexíveis. Entre seus pilares estão o modelo de objetos (com signals & slots, propriedades e árvore de objetos) e as classes de contêiner (sequenciais e associativas). Abaixo, revisamos esses tópicos de forma prática e direta.

  1. Modelo de Objetos

1.1 Signals e Slots

Esse mecanismo substitui o padrão clássico de callbacks (ponteiros de função) usado em outras bibliotecas, como WinForms ou WPF. Com signals e slots, objetos se comunicam de maneira segura e desacoplada.

Exemplo típico: transferir um valor de uma janela de diálogo para a janela principal.

// Dialog1.h
signals:
    void valorSelecionado(int);

private slots:
    void on_botaoOk_clicked();

// Dialog1.cpp
void DialogoEntrada::on_botaoOk_clicked()
{
    int valor = ui->spinBox->value();
    emit valorSelecionado(valor);
    close();
}

// MainWindow.h
private slots:
    void atualizarLabel(int valor);

// MainWindow.cpp
DialogoEntrada *dlg = new DialogoEntrada(this);
connect(dlg, &DialogoEntrada::valorSelecionado, this, &MainWindow::atualizarLabel);

void MainWindow::atualizarLabel(int valor)
{
    ui->labelResultado->setText(tr("Valor recebido: %1").arg(valor));
}

Regras importantes:

  • A classe deve herdar de QObject (ou uma subclasse) e conter a macro Q_OBJECT.
  • Os parâmetros do sinal devem corresponder (ou ser compatíveis) com os do slot; o sinal não pode ter mais argumentos que o slot.
  • Sinais são apenas declarações (sem implementação) e retornam void.

A função connect() tem a seguinte assinatura:

connect(sender, signal, receiver, slot, connectionType = Qt::AutoConnection)

O quarto parâmetro pode ser outro sinal (conectando sinal a sinal). O último parâmetro define o modo de conexão:

  • Qt::AutoConnection (padrão): o slot é executado imediatamente após o sinal ser emitido, e o código após emit só continua quando o slot termina.
  • Qt::QueuedConnection: a emissão do sinal retorna imediatamente, e o slot é executado mais tarde (quando o loop de eventos for processado), útil para threads.

Também é possível usar lambda expressions como slot:

connect(dlg, &DialogoEntrada::valorSelecionado, [=](int v){
    ui->labelResultado->setText(tr("Valor: %1").arg(v));
});

Auto-conexão (conexão automática por nome): se você nomear os widgets com setObjectName() antes de chamar setupUi(), o Qt pode conectar sinais a slots automaticamente seguindo a convenção on_NOMEDOWIDGET_SINAL().

Desconectar sinais/slots:

disconnect(objeto, nullptr, nullptr, nullptr);               // remove todas as conexões do objeto
disconnect(objeto, SIGNAL(meuSinal()), nullptr, nullptr);    // remove conexões desse sinal
disconnect(objeto, nullptr, receptor, nullptr);              // remove conexões com esse receptor
disconnect(objeto, SIGNAL(meuSinal()), receptor, SLOT(meuSlot())); // remove conexão específica

1.2 Sistema de Propriedades

O Qt fornece um sistema de propriedades dinâmicas através da macro Q_PROPERTY, permitindo acessar atributos como se fossem membros da classe, com suporte a meta-object system.

1.3 Árvore de Objetos e Propriedade

Quando um objeto QObject é criado com um pai (ex: new QPushButton(parent)), ele se torna filho na árvore de objetos. Se o pai for destruído, todos os filhos são automaticamente deletados. Isso simplifica o gerenciamento de memória: normalmente cria-se o widget principal na stack (ex: QMainWindow w;) e os demais widgets na heap com pai explícito, evitando o uso de delete.

1.4 Meta-Object System

O meta-object system (MOC) é o mecanismo que permite signals/slots, propriedades dinâmicas e introspecção. Qualquer classe que herde de QObject e contenha Q_OBJECT terá meta-informação gerada pelo MOC.

  1. Classes Contêiner

O Qt oferece contêineres sequenciais e associativos, todos com iteradores estilo Java e STL, além do suporte a foreach.

2.1 Contêineres Sequenciais

  • QList – indicado para listas pequenas (até 1000 elementos); insere/remove rapidamente no meio; para acesso, prefira at() que é mais rápido que operator[].
  • QLinkedList – lista ligada, inserções/remoções frequentes no meio.
  • QVector – array contíguo, acesso indexado muito rápido; inserções no final são ótimas.
  • QStack – pilha (LIFO), baseado em QVector.
  • QQueue – fila (FIFO), baseado em QList.

2.2 Contêineres Associativos

  • QMap – dicionário ordenado por chave (árvore rubro-negra).
  • QMultiMap – permite chaves duplicadas.
  • QHash – tabela hash, acesso O(1) médio.
  • QMultiHash – hash com chaves duplicadas.
  • QSet – conjunto baseado em hash, sem duplicatas.

2.3 Iteração

O Qt oferece iteradores Java-style (QListIterator, QMutableListIterator) e iteradores STL-style (como begin()/end()). Os iteradores STL são mais rápidos e compatíveis com algoritmos da STL. Use iteradores const sempre que possível para ganhar performance.

Nos iteradores STL, os operadores ++/-- podem ser prefixados (mais eficientes, retornam referência) ou sufixados (retornam cópia do estado anterior). Prefira prefixo se não precisar do valor anterior.

2.4 Algoritmos Genéricos

O cabeçalho <QtAlgorithms> oferece funções como qCopy(), qEqual(), qFind(), qFill(), qCount(), qLowerBound(), qSort(), qGreater(), qSwap(). O cabeçalho <QtGlobal> disponibiliza qAbs(), qMax(), qMin().

2.5 QString

Compartilhamento implícito (copy-on-write): Quando uma string é copiada, apenas um ponteiro é passado; a cópia real (deep copy) ocorre apenas quando o objeto é modificado. Isso reduz uso de memória e cópias desnecessárias.

QString oferece métodos de edição (append, prepend, insert, replace, remove), consulta (indexOf, contains, startsWith, endsWith) e conversão (toInt, toDouble, para/from UTF-8, Latin1, etc.).

2.6 QByteArray e QVariant

QByteArray armazena dados binários ou strings não Unicode; ideal para buffers e comunicação serial. QVariant pode armazenar qualquer tipo registrado no meta-system (int, double, QString, QColor, etc.), sendo útil em propriedades genéricas.

  1. Expressões Regulares

O Qt 5 introduziu a clase QRegularExpression (substituindo a antiga QRegExp). Ela oferece suporte completo a Perl-like regex, com flags para case-insensitive, multiline, etc. Exemplos de uso:

QRegularExpression regex("\\d+", QRegularExpression::CaseInsensitiveOption);
QRegularExpressionMatch match = regex.match("123 abc");
if (match.hasMatch()) {
    qDebug() << match.captured(0); // "123"
}

Tags: Qt Signals and Slots QObject Container Classes QString

Publicado em 6-30 01:09