Fluxo de Processamento de Eventos
No Qt, o ciclo de vida de um evento segue um caminho rigoroso desde a sua geração até o consumo final. O processo pode ser resumido nas seguintes etapas:
- Origem do Evento: Pode ser gerado pelo sistema (mouse, teclado), por timers, notificações de rede/IO ou via código do desenvolvedor.
- Modo de Envio:
- Síncrono (sendEvent): O evento é enviado diretamente ao reecptor. A execução é bloqueada até que o processamento termine. O programador deve gerenciar a memória do objeto de evento.
- Assíncrono (postEvent): O evento é postado em uma fila (QEventQueue). O controle retorna imediatamente ao chamador. O
QEventLoopretira o evento da fila posteriormente e o envia aonotify(). O Qt gerencia a desalocação da memória automaticamente.
- Distribuição (QCoreApplication::notify): O ponto central de entrada da aplicação. Antes de entregar o evento ao objeto, ele verifica os filtros de eventos instalados.
- Filtros de Eventos: Se um filtro retornar
true, o evento é interrompido. Caso contrário, ele prossegue para o métodoevent()do objeto. - Distribuição de Nível de Objeto (QObject::event): Atua como um distribuidor interno que encaminha o evento para handlers específicos (como
mousePressEventoukeyPressEvent) com base no tipo do evento.
Envio Síncrono vs. Assíncrono
O envio imediato utiliza sendEvent. É recomendável criar o evento na stack para evitar vazamentos de memória, já que o objeto não é deletado automaticamente pelo framework.
// Envio síncrono (bloqueante)
QKeyEvent pressionarTecla(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier);
bool foiProcessado = QCoreApplication::sendEvent(meuWidget, &pressionarTecla);
Para envio assíncrono, utiliza-se postEvent. O evento deve obrigatoriamente ser alocado no heap (usando new), pois o Qt assumirá a propriedade do ponteiro e o excluirá após o processamento.
// Envio assíncrono (não bloqueante)
QWheelEvent *eventoRoda = new QWheelEvent(QPointF(10, 10), QPointF(10, 10), QPoint(0, 120), QPoint(0, 120), Qt::NoButton, Qt::NoModifier, Qt::NoPhase, false);
QCoreApplication::postEvent(areaScroll, eventoRoda);
// O objeto 'eventoRoda' será deletado pelo Qt automaticamente
Filtros de Eventos (Event Filters)
Os filtros de eventos funcionam como interceptadores. Qualquer classe derivada de QObject pode implementar o método virtual eventFilter(). Isso permite que um objeto monitore e manipule eventos destinados a outro objeto antes que este último os receba.
Características Principais:
- Retornar
trueinterrompe a propagação (o evento é "comido"). - Retornar
falsepermite que o evento continue para o próximo filtro ou para o destinatário original. - Múltiplos filtros podem ser instalados em um único objeto; o último a ser instalado é o primeiro a ser executado.
// Implementação de um interceptador de teclado
bool MonitorTeclado::eventFilter(QObject *alvo, QEvent *evento)
{
if (evento->type() == QEvent::KeyPress) {
QKeyEvent *keyEv = static_cast<QKeyEvent *>(evento);
if (keyEv->key() == Qt::Key_Return) {
qDebug() << "Tecla Enter interceptada no objeto:" << alvo->objectName();
return true; // Bloqueia o processamento padrão
}
}
// Propaga para o comportamento padrão
return QObject::eventFilter(alvo, evento);
}
Filtros Globais
Para capturar eventos em toda a aplicação, pode-se instalar um filtro no objeto global qApp. Isso é útil para implementar logs de atividade, gerenciamento de inatividade ou atalhos globais personalizados.
// No construtor da MainWindow ou no main.cpp
qApp->installEventFilter(this);
// Processando eventos de todos os widgets da app
bool MainWindow::eventFilter(QObject *obj, QEvent *ev)
{
if (ev->type() == QEvent::MouseButtonPress) {
qDebug() << "Clique detectado em algum lugar da aplicação.";
}
return QMainWindow::eventFilter(obj, ev);
}
Sobrescrita do Método event()
Embora seja possível processar eventos sobrescrevendo handlers específicos (como paintEvent), o método event() oferece um nível de controle intermediário. Ele é útil para lidar com eventos personalizados ou para agrupar lógica de diferentes tipos de eventos em um único local antes da distribuição para as funções de conveniência.
bool MeuComponenteCustomizado::event(QEvent *e)
{
if (e->type() == QEvent::HoverEnter) {
atualizarEstiloDestaque(true);
return true;
}
// Tratamento de eventos de toque específicos
if (e->type() == QEvent::TouchBegin) {
e->accept();
return true;
}
// Encaminha eventos não tratados para a classe base
return QWidget::event(e);
}
Observação de Segurança: Se um objeto for deletado dentro de um eventFilter, é obrigatório retornar true. Caso contrário, o sistema de eventos tentará entregar o evento a um objeto que não existe mais, resultando em falha de segmentação.