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.
- 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 macroQ_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ósemitsó 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.
- 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 queoperator[]. - 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.
- 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"
}