Operações Avançadas de Imagem com QGraphicsView no Qt

O framework QGraphicsView do Qt oferece uma solução robusta e flexível para a exibição e manipulação de elementos gráficos 2D. Esta arquitetura é composta por três classes principais interligadas: QGraphicsScene (a cena), QGraphicsView (a visualização) e QGraphicsItem (os itens gráficos). Compreender a função de cada uma é fundamental para desenvolver aplicações gráficas interativas.

O Core do Framework: QGraphicsScene, QGraphicsView e QGraphicsItem

  • QGraphicsScene atua como um container lógico, invisível por si só, que hospeda todos os itens gráficos. É responsável por gerenciar esses itens, distribuir eventos (como cliques do mouse e teclas) entre eles e manter seu estado (seleção, foco). Além disso, a cena oferece capacidaeds de renderização sem transformação, úteis para operações como impressão.
  • QGraphicsView é o componente visível que exibe o conteúdo de uma QGraphicsScene. Uma única cena pode ser visualizada por múltiplas instâncias de QGraphicsView, cada uma podendo ter sua própria transformação (zoom, rotação, deslocamneto), permitindo diferentes perspectivas da mesma cena.
  • QGraphicsItem é a classe base para todos os elementos que podem ser adicionados a uma QGraphicsScene. O Qt fornece subclasses padrão para formas comuns, como retângulos (QGraphicsRectItem), elipses (QGraphicsEllipseItem) e texto (QGraphicsTextItem), bem como itens para imagens (QGraphicsPixmapItem).

Funcionalidades da QGraphicsScene

A QGraphicsScene desempenha um papel central no gerenciamento de itens gráficos:

  • Gerenciamento de Itens: Itens podem ser adicionados à cena usando QGraphicsScene::addItem(). A recuperação de itens é possível através de métodos como QGraphicsScene::items() (que pode retornar todos os itens que se interseccionam com um ponto, retângulo, polígono ou caminho vetorial) e QGraphicsScene::itemAt() (para o item mais superior em um ponto específico). A ordem de empilhamento (Z-order) é respeitada, com os itens mais superiores retornados primeiro.
  • Propagação de Eventos: A cena é o primeiro ponto de contato para eventos de entrada. Ela encaminha esses eventos para os itens apropriados. Por exemplo, um clique do mouse é enviado ao item mais superior sob o cursor.
  • Gerenciamento de Estado: A cena controla estados importantes como a seleção de itens e o foco do teclado.
    • Seleção: Múltiplos itens podem ser selecionados usando QGraphicsScene::setSelectionArea(), que aceita um QPainterPath para definir a área de seleção. A lista de itens selecionados pode ser obtida com QGraphicsScene::selectedItems().
    • Foco: O foco do teclado pode ser definido em um item específico via QGraphicsScene::setFocusItem() ou QGraphicsItem::setFocus(). O item atualmente com foco é recuperado com QGraphicsScene::focusItem().
  • Renderização: A função QGraphicsScene::render() permite desenhar a cena diretamente em um dispositivo de pintura, útil para saídas não interativas.

Exemplo de Implementação de Operações de Imagem

As funcionalidades interativas são tipicamente implementadas manipulando as propriedades dos QGraphicsItem e as transformações da QGraphicsView. A seguir, demonstraremos como implementar operações comuns como zoom, rotação e troca de camadas.

Controle de Zoom com Roda do Mouse

O zoom pode ser implementado capturando eventos da roda do mouse. Para um zoom centralizado na posição do cursor, a transformação da visualização deve ser ajustada corretamente.


void MinhaVisualizacaoGrafica::wheelEvent(QWheelEvent *evento)
{
   // Definir o ponto de âncora para a transformação como a posição do mouse.
   // Isso garante que o zoom seja centralizado onde o cursor está.
   setTransformationAnchor(QGraphicsView::AnchorUnderMouse);

   // Fatores de escala
   qreal fatorDeEscala = 1.1; // Fator para zoom in
   if (evento->angleDelta().y() < 0) { // Roda do mouse para trás (zoom out)
       fatorDeEscala = 1.0 / fatorDeEscala; // Fator para zoom out
   }

   // Limites de zoom para evitar escalas extremas
   qreal escalaAtual = transform().m11(); // Obtém a escala atual no eixo X (assumindo escala uniforme)
   if ((fatorDeEscala > 1 && escalaAtual > 50.0) || // Limite máximo (50x o tamanho original)
       (fatorDeEscala < 1 && escalaAtual < 0.1)) { // Limite mínimo (0.1x o tamanho original)
       return;
   }

   // Aplicar a escala à visualização
   scale(fatorDeEscala, fatorDeEscala);
}
   

Rotação de Imagens

A rotação de itens gráficos, como um QGraphicsPixmapItem, envolve a definição de um ponto de origem de transformação e o ajuste do ângulo de rotação.


void EditorDeImagens::rotacionarEsquerda() {
   if (!camadasDeImagem.isEmpty()) {
       QGraphicsPixmapItem *camadaAtiva = camadasDeImagem[seletorDeCamadas->currentIndex()];
       // O ponto de origem da transformação é o centro do item para uma rotação em torno de seu próprio eixo.
       QPointF centro = camadaAtiva->boundingRect().center();
       camadaAtiva->setTransformOriginPoint(centro);
       // Diminui o ângulo para rotação para a esquerda
       camadaAtiva->setRotation(camadaAtiva->rotation() - 15);
   }
}

void EditorDeImagens::rotacionarDireita() {
   if (!camadasDeImagem.isEmpty()) {
       QGraphicsPixmapItem *camadaAtiva = camadasDeImagem[seletorDeCamadas->currentIndex()];
       QPointF centro = camadaAtiva->boundingRect().center();
       camadaAtiva->setTransformOriginPoint(centro);
       // Aumenta o ângulo para rotação para a direita
       camadaAtiva->setRotation(camadaAtiva->rotation() + 15);
   }
}
   

Troca de Camadas

Para gerenciar a visibilidade ou a ordem de empilhamento (Z-order) de diferentes camadas, podemos iterar sobre os itens e ajustar suas propriedades. Por exemplo, para "selecionar" ou destacar uma camada, podemos garantir que apenas uma esteja ativa ou trazer a selecionada para a frente.


void EditorDeImagens::selecionarCamada(int indiceDaCamada) {
   // Desativa a seleção de todas as camadas visíveis
   for (QGraphicsPixmapItem *camada : camadasDeImagem) {
       if (camada) { // Verifica se a camada não é nula
           camada->setSelected(false);
           camada->setZValue(0); // Reseta Z-value para manter a ordem base
       }
   }

   // Ativa a nova camada selecionada, se o índice for válido
   if (indiceDaCamada >= 0 && indiceDaCamada < camadasDeImagem.size()) {
       QGraphicsPixmapItem *novaCamada = camadasDeImagem[indiceDaCamada];
       if (novaCamada) {
           novaCamada->setSelected(true);
           novaCamada->setZValue(1); // Traz a camada selecionada para frente
           // Opcional: ajustar a visibilidade ou focar a visualização na nova camada
       }
   }
}
   

Tags: Qt QGraphicsView QGraphicsScene QGraphicsItem C++

Publicado em 6-15 18:48 por Thomas