Qt Literacy - visão geral da teoria da estrutura de visualização gráfica

I. Visão geral

A visualização gráfica fornece uma superfície para gerenciar e interagir com um grande número de itens gráficos 2D personalizados e um widget de visualização para visualizar esses itens, com suporte para zoom e rotação.

A estrutura inclui uma arquitetura de propagação de eventos que permite interação precisa de dupla precisão entre itens em uma cena. Os elementos podem lidar com eventos de tecla, mouse pressionado, mover, liberar e clicar duas vezes, além de rastrear o movimento do mouse.

A visualização gráfica usa uma árvore BSP (particionamento de espaço binário) para fornecer uma descoberta de itens muito rápida, para que possa visualizar grandes cenas em tempo real, mesmo com milhões de itens.

O Graphics View foi introduzido no Qt 4.2, substituindo seu predecessor QCanvas.

2. Arquitetura de Visualização Gráfica

Graphics View fornece uma abordagem baseada em itens para programação de visualização de modelo, muito parecido com as classes de conveniência QTableView, QTreeView e QListView do InterView. Várias visualizações podem observar a mesma cena, que contém itens de diferentes formas geométricas.

1. A cena

QGraphicsScene fornece a Cena da Visualização Gráfica. As responsabilidades da cena são as seguintes:

  • Fornece uma interface rápida para gerenciar um grande número de itens
  • Propagar o evento para cada Item
  • Gerenciar o estado do item, como seleção e manipulação de foco
  • Fornece funcionalidade de renderização não transformada; usado principalmente para funcionalidade de impressão

A cena atua como um contêiner para objetos QGraphicsItem. Os itens são adicionados à cena chamando QGraphicsScene::addItem() e, em seguida, recuperados chamando uma das muitas funções de descoberta de itens. QGraphicsScene::items() e suas funções sobrecarregadas retornam todos os elementos contidos ou interceptados por um ponto, retângulo, polígono ou caminho vetorial geral . QGraphicsScene::itemAt() Retorna o elemento mais alto na posição especificada.Todas as funções de descoberta de itens retornam itens empilhados em ordem decrescente (ou seja, o primeiro item retornado está no topo e o último item retornado está na parte inferior).

  QGraphicsScene scene;
  QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100));

  QGraphicsItem *item = scene.itemAt(50, 50);
  // item == rect

A arquitetura de propagação de eventos do QGraphicsScene agenda eventos de cena para entrega aos itens e gerencia a propagação entre os itens. Se a cena receber um evento de mouse pressionado em um determinado local, a cena passará o evento para qualquer elemento nesse local.

QGraphicsScene também gerencia certos estados de itens, como seleção e foco de itens. Você pode selecionar elementos na Cena chamando QGraphicsScene::setSelectionArea(), passando um argumento de qualquer formato. Esse recurso também é usado como base para a seleção de elástico no QGraphicsView. Para obter uma lista de todos os itens atualmente selecionados, chame QGraphicsScene::selectedItems(). Outro estado que QGraphicsScene manipula é se o item tem foco de entrada de teclado. Podemos definir o foco em um item chamando QGraphicsScene::setFocusItem() ou QGraphicsItem::setFocus(), ou obter o item atualmente focado chamando QGraphicsScene::focusItem().

Finalmente, QGraphicsScene nos permite renderizar partes da Cena para o dispositivo de desenho através da função QGraphicsScene::render().

Isso nos fornece uma base para a saída de imagens.

2. A Visão

QGraphicsView fornece um controle de visualização, que pode visualizar o conteúdo da Cena. Você pode adicionar várias visualizações à mesma cena, fornecendo várias janelas de visualização para o mesmo conjunto de dados. O widget de exibição é uma área de rolagem que fornece barras de rolagem para navegar em uma cena grande. Para habilitar o suporte OpenGL, um QGLWidget pode ser definido como a visualização chamando QGraphicsView::setViewport().

  QGraphicsScene scene;
  myPopulateScene(&scene);

  QGraphicsView view(&scene);
  view.show();

A View recebe eventos de entrada do teclado e do mouse, e converte esses eventos em eventos de Cena (converte as coordenadas usadas em coordenadas de Cena), e então envia os eventos para a Cena visual.

Usando sua matriz de transformação QGraphicsView::transform(), a view pode transformar o sistema de coordenadas da Cena. As visualizações também permitem recursos avançados de navegação, como zoom e rotação. Por conveniência, QGraphicsView também fornece funções para converter entre as coordenadas de visualização e cena: QGraphicsView::mapToScene() e QGraphicsView::mapFromScene().
insira a descrição da imagem aqui

3. Item de elemento gráfico

QGraphicsItem é a classe base de elementos gráficos em Scene. A visualização de gráficos fornece alguns itens padrão para formas comumente usadas, como retângulo (QGraphicsItem), elipse (QGraphicsEllipseItem) e item de texto (QGraphicsTextItem), mas ao escrever itens personalizados, podemos usar os recursos QGraphicsItem mais poderosos. Basta herdar esta função.

QGraphicsItem suporta os seguintes recursos:

  • Eventos de mouse para baixo, mover, liberar e clicar duas vezes, bem como eventos de passar o mouse, roda e menu de contexto.
  • Foco de entrada do teclado e eventos principais
  • Arraste e solte Solte e arraste
  • Gerenciamento de grupo, relacionamento pai-filho e método de agrupamento QGraphicsItemGroup
  • Verificação de impacto

Os itens existem em um sistema de coordenadas local.Como o QGraphicsView, ele também fornece muitas funções para mapear as coordenadas entre os itens e a Cena, e as coordenadas entre os itens e os itens. Além disso, como o QGraphicsView, ele pode transformar seu sistema de coordenadas usando a matriz QGraphicsItem::transform(). Isso é útil para girar e dimensionar elementos individuais.

Os itens podem conter outros itens (subitens). A transformação de um pai é herdada por todos os seus filhos. No entanto, todas as suas funções (como QGraphicsItem::contains(), QGraphicsItem::boundingRect(), QGraphicsItem::collidesWith()) ainda operam em coordenadas locais, independentemente da transformação cumulativa do elemento.

QGraphicsItem oferece suporte à detecção de colisão por meio da função QGraphicsItem::shape() e da função QGraphicsItem::collidesWith(), ambas funções virtuais. Retornando a forma do Item de QGraphicsItem::shape() como uma coordenada local QPainterPath, QGraphicsItem tratará de toda a detecção de colisão para você. No entanto, se você deseja fornecer sua própria detecção de colisão, pode reimplementar QGraphicsItem::collidesWith().

insira a descrição da imagem aqui

3. Sistema de Coordenadas de Visualização Gráfica

A visualização gráfica é baseada em um sistema de coordenadas cartesianas: a posição e a geometria de um item na cena são representadas por dois conjuntos de números: a coordenada x e a coordenada y. Ao visualizar uma cena com uma visão não transformada, uma unidade na cena é representada por um pixel na tela.

Nota: Como a exibição do gráfico usa o sistema de coordenadas do Qt, um sistema de coordenadas do eixo y reverso (y cresce para cima) não é suportado.

Existem três sistemas de coordenadas disponíveis em uma visualização gráfica: Coordenadas de item, Coordenadas de cena e Coordenadas de visualização. Para simplificar a implementação, o Graphics View fornece funções de conveniência que permitem mapear entre os três sistemas de coordenadas.

Ao renderizar, as coordenadas da cena da visualização gráfica correspondem às coordenadas lógicas do QPainter e as coordenadas da visualização são iguais às coordenadas do dispositivo. Na documentação do sistema de coordenadas, podemos ler sobre a relação entre as coordenadas lógicas e as coordenadas do dispositivo.

insira a descrição da imagem aqui

1. As coordenadas do Item primitivo

Os elementos existem em seu próprio sistema de coordenadas local. Suas coordenadas são geralmente centradas em torno do ponto central (0,0), que também é o centro de todas as transformações. Primitivas geométricas no sistema de coordenadas de itens são geralmente chamadas de pontos de itens, linhas de itens ou retângulos de itens.

Ao criar itens personalizados, você só precisa se preocupar com as coordenadas do item; QGraphicsScene e QGraphicsView realizarão todas as transformações para nós. Isso facilita muito a implementação de personalizações. Por exemplo, se você receber um evento mousedown ou drag-in, a localização do evento é fornecida nas coordenadas do elemento.

Função virtual QGraphicsItem::contains(), se um ponto estiver dentro do Item, retorna verdadeiro, caso contrário retorna falso, aceita o parâmetro ponto nas coordenadas do Item. Da mesma forma, o retângulo delimitador e a forma do Item estão nas coordenadas do Item.

A posição de um item At é a coordenada do ponto central do item no sistema de coordenadas de seu pai; às vezes também chamada de coordenadas do pai. Nesse sentido, a cena é considerada o "pai" de todos os itens sem pai. A posição do item de nível superior está nas coordenadas da cena.

As coordenadas do elemento filho são relativas às coordenadas do elemento pai. Se o elemento filho não for transformado, a diferença entre as coordenadas do elemento filho e as coordenadas do pai é a mesma que a distância entre os itens nas coordenadas do pai. Por exemplo: Se um filho não transformado estiver posicionado exatamente no ponto central do pai, os sistemas de coordenadas de ambos os filhos serão os mesmos. Se a posição do nó filho for (10,0), então o ponto (0,10) do nó filho corresponderá ao ponto (10,10) do nó pai.

Como a posição e a transformação de um elemento são relativas ao elemento pai, as coordenadas de um elemento filho não são afetadas pela transformação do pai, embora a transformação do pai transforme implicitamente o filho. No exemplo acima, mesmo que o elemento pai seja girado e dimensionado, o ponto (0,10) do elemento filho ainda corresponde ao ponto (10,10) do elemento pai. No entanto, em relação à Cena, os elementos filho seguirão a transformação e a posição do elemento pai. Se o elemento pai for dimensionado (2x, 2x), a posição do elemento filho estará nas coordenadas da cena (20,0) e seu ponto (10,0) corresponderá ao ponto (40,0) na cena .

QGraphicsItem::pos() é uma das poucas exceções.As funções de QGraphicsItem operam em coordenadas de item, não importando qual seja o item ou qual seja sua transformação pai. Por exemplo, o retângulo delimitador de um Item (ou seja, QGraphicsItem::boundingRect()) é sempre dado nas coordenadas do Item.

2. Cena Coordenadas da cena

A cena representa o sistema de coordenadas base de todos os itens. O sistema de coordenadas da cena descreve a posição de cada item de nível superior e também forma a base para todos os eventos de cena enviados da exibição para a cena. Cada item na cena tem uma posição de cena e retângulo delimitador (QGraphicsItem::scenePos(), QGraphicsItem::sceneBoundingRect()), além de sua posição de item local e retângulo delimitador. A posição da cena descreve a posição do item nas coordenadas da cena, e seu retângulo delimitador da cena forma a base de como o QGraphicsScene determina quais áreas da cena foram alteradas. Mudanças de cena são comunicadas através do sinal QGraphicsScene::changed(), e o parâmetro é uma lista de retângulos de cena.

3. Veja as coordenadas da vista

As coordenadas da vista são as coordenadas do controle. Cada unidade nas coordenadas de visualização corresponde a um pixel. A coisa especial sobre este sistema de coordenadas é que ele é relativo ao widget (ou viewport) e não é afetado pela cena observada. O canto superior esquerdo da viewport do QGraphicsView é sempre (0,0) e o canto inferior direito é sempre (largura da viewport, altura da viewport). Todos os eventos de mouse e eventos de arrastar e soltar são inicialmente recebidos na forma de coordenadas de exibição e você precisa mapear essas coordenadas na cena para interagir com os elementos.

4. Mapeamento de coordenadas

Frequentemente, ao trabalhar com itens em uma cena, é útil mapear coordenadas e formas arbitrárias de uma cena para um item, de um item para outro ou de uma exibição para uma cena. Por exemplo, quando você clica com o mouse na viewport de um QGraphicsView, você pode perguntar ao Scene qual Item está sob o cursor chamando QGraphicsView::mapToScene(), seguido por QGraphicsScene::itemAt(). Se você quiser saber onde o item está na viewport, você pode chamar QGraphicsItem::mapToScene() no item e, em seguida, chamar QGraphicsView::mapFromScene() na exibição. Finalmente, se você quiser encontrar itens dentro da elipse de exibição, você pode passar um QPainterPath para mapToScene() e, em seguida, passar o caminho mapeado para QGraphicsScene::items().

Ao chamar QGraphicsItem::mapToScene() e QGraphicsItem::mapFromScene(), as coordenadas e formas podem ser mapeadas para a cena do item. Você também pode mapear para o Item pai de um Item chamando QGraphicsItem::mapToParent() e QGraphicsItem::mapFromParent(), ou mapear entre Itens chamando QGraphicsItem::mapToItem() e QGraphicsItem::mapFromItem(). Todas as funções de mapeamento podem mapear pontos, retângulos, polígonos e caminhos simultaneamente.

Há também a mesma função de mapeamento na exibição para mapeamento com Cena. QGraphicsView::mapFromScene() e QGraphicsView::mapToScene(). Para mapear de uma exibição para um item, primeiro mapeie para a cena e depois mapeie da cena para o item.

4. Principais recursos

1. Dimensionar e girar

QGraphicsView suporta a mesma transformação afim que QPainter através de QGraphicsView::setMatrix(). Ao aplicar transformações às exibições, podemos facilmente adicionar suporte para recursos de navegação comuns, como zoom e rotação.
Aqui está um exemplo de como implementar slots de escala e rotação em uma subclasse de QGraphicsView:

  class View : public QGraphicsView
  {
    
    
  Q_OBJECT
      ...
  public slots:
      void zoomIn() {
    
     scale(1.2, 1.2); }
      void zoomOut() {
    
     scale(1 / 1.2, 1 / 1.2); }
      void rotateLeft() {
    
     rotate(-10); }
      void rotateRight() {
    
     rotate(10); }
      ...
  };

Slots podem ser conectados a QToolButtons com autoRepeat habilitado.

QGraphicsView mantém o centro da visualização alinhado quando você alterna a visualização.

2. imprimir

Graphics View fornece impressão de linha única através de suas funções de renderização QGraphicsScene::render() e QGraphicsView::render(). Essas funções fornecem a mesma API: você pode fazer com que uma Cena ou Visualização renderize todo ou parte de seu conteúdo para qualquer dispositivo de desenho passando um QPainter para qualquer uma das funções de renderização. Este exemplo mostra como usar o QPrinter para imprimir toda a cena em uma página completa.

  QGraphicsScene scene;
  scene.addRect(QRectF(0, 0, 100, 200), QPen(Qt::black), QBrush(Qt::green));

  QPrinter printer;
  if (QPrintDialog(&printer).exec() == QDialog::Accepted) {
    
    
      QPainter painter(&printer);
      painter.setRenderHint(QPainter::Antialiasing);
      scene.render(&painter);
  }

A diferença entre as funções de renderização Scene e View é que uma opera nas coordenadas Scene e a outra opera nas coordenadas View. QGraphicsScene::render() é normalmente usado para imprimir um fragmento inteiro de uma cena não transformada, como desenhar dados geométricos ou imprimir um documento de texto. Por outro lado, QGraphicsView::render() é adequado para tirar screenshots; seu comportamento padrão é usar o pintor fornecido para renderizar o conteúdo fora da janela do controle.

  QGraphicsScene scene;
  scene.addRect(QRectF(0, 0, 100, 200), QPen(Qt::black), QBrush(Qt::green));

  QPixmap pixmap;
  QPainter painter(&pixmap);
  painter.setRenderHint(QPainter::Antialiasing);
  scene.render(&painter);
  painter.end();

  pixmap.save("scene.png");

Quando o tamanho da área de origem e a área de destino não correspondem, o conteúdo da área de origem é ampliado para caber na área de destino. Ao passar Qt::AspectRatioMode para a função de renderização que você está usando, você pode optar por manter ou ignorar a proporção da cena enquanto o conteúdo é estendido.

3. Arraste e solte

Como o QGraphicsView herda o QWidget indiretamente, ele já fornece a mesma funcionalidade de arrastar e soltar que o QWidget fornece. Além disso, por conveniência, a estrutura de exibição de gráficos fornece suporte para arrastar e soltar para Cena e cada Item. Quando a exibição recebe um arrasto, ela converte o evento arrastar e soltar em um QGraphicsSceneDragDropEvent, que é encaminhado para a cena. A Cena assume o agendamento deste evento e o envia para o primeiro Item sob o cursor do mouse que aceitar o drop.

Para começar a arrastar de um elemento, crie um objeto QDrag, passando um ponteiro para o widget começar a arrastar. Múltiplas visualizações podem observar o Item ao mesmo tempo, mas apenas uma visualização pode iniciar o arrasto. Na maioria dos casos, arrastar é iniciado pressionando ou movendo o mouse, portanto, em mousePressEvent() ou mouseMoveEvent(), você pode obter o ponteiro inicial do widget a partir do evento. Por exemplo:

  void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
  {
    
    
      QMimeData *data = new QMimeData;
      data->setColor(Qt::green);

      QDrag *drag = new QDrag(event->widget());
      drag->setMimeData(data);
      drag->start();
  }

Para interceptar os eventos de arrastar e soltar da cena, precisamos reimplementar QGraphicsScene::dragEnterEvent() e quaisquer manipuladores de eventos necessários para a cena específica na subclasse QGraphicsItem. Podemos ler mais sobre como arrastar e soltar exibições de gráficos na documentação de cada manipulador de eventos do QGraphicsScene.

Os itens podem ser arrastados e soltos chamando QGraphicsItem::setAcceptDrops(). Para lidar com os arrastos recebidos, reimplemente QGraphicsItem::dragEnterEvent(), QGraphicsItem::dragMoveEvent(), QGraphicsItem::dragLeaveEvent() e QGraphicsItem::dropEvent().

4. Ponteiro e dicas do mouse

Similar ao QWidget, QGraphicsItem também suporta mouse (QGraphicsItem::setCursor()) e ToolTip (QGraphicsItem::setToolTip()). Quando o cursor do mouse entra na área do item (detectado chamando QGraphicsItem::contains()), QGraphicsView ativa o ponteiro do mouse e a dica de ferramenta.
Você também pode definir o ponteiro padrão do mouse diretamente na exibição chamando QGraphicsView::setCursor().

5. Animação

A exibição do gráfico oferece suporte a vários níveis de animação. Você pode facilmente montar animações usando estruturas de animação. Para fazer isso, precisamos que nossos itens herdem QGraphicsObject e associem QPropertyAnimation a eles. QPropertyAnimation permite animar qualquer propriedade QObject.
Outra opção é criar um item personalizado herdado de QObject e QGraphicsItem. O Item pode definir seu próprio timer e controlar a animação em etapas incrementais em QObject::timerEvent().

Uma terceira opção é avançar a cena chamando QGraphicsScene::advance(), que por sua vez chama QGraphicsItem::advance(), principalmente para compatibilidade com QCanvas no Qt 3.

6. Renderização OpenGL

Para habilitar a renderização OpenGL, simplesmente defina um novo QGLWidget como viewport do QGraphicsView chamando QGraphicsView::setViewport(). Se você quiser antialiasing OpenGL, você precisa de suporte de buffer de amostra OpenGL (consulte QGLFormat::sampleBuffers()).

  QGraphicsView view(&scene);
  view.setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));

7. Grupo de itens

Ao tornar um item filho de outro item, você pode obter as propriedades mais básicas do agrupamento de itens: todos os itens se movem juntos e todas as transformações podem ser propagadas de pai para filho.

Além disso, QGraphicsItemGroup é um item especial que combina a manipulação de eventos filhos com uma interface útil para adicionar e remover itens de e para o grupo. Adicionar um elemento a um QGraphicsItemGroup manterá a posição original e a transformação do elemento, enquanto a reorganização dos elementos geralmente fará com que os elementos filhos sejam reposicionados em relação ao novo pai. Por conveniência, você pode criar QGraphicsItemGroups chamando QGraphicsScene::createItemGroup() da cena.

8. Peças e Layout

O Qt 4.4 introduziu suporte para geometria e itens com reconhecimento de layout via qgraphicwidget. Este item base especial é semelhante ao QWidget, mas ao contrário do QWidget, ele não herda do QPaintDevice; ele não deriva do QGraphicsItem. Isso nos permite escrever widgets completos com eventos, sinais e slots, dicas de tamanho e políticas, e também podemos gerenciar a geometria dos widgets no layout via QGraphicsLinearLayout e QGraphicsGridLayout.

1. QGraphicsWidget

Com base nos recursos e recursos simplificados do QGraphicsItem, o QGraphicsWidget oferece o melhor dos dois mundos: os recursos extras do QWidget, como estilos, fontes, paletas, direções de layout e sua geometria, e a independência de resolução e suporte de transição do QGraphicsItem. Como a exibição de gráficos usa coordenadas reais em vez de números inteiros, as funções de geometria do QGraphicsWidget também podem operar em QRectF e QPointF. Isso também se aplica aos retângulos, margens e espaçamento do quadro. Por exemplo, ao usar QGraphicsWidget é muito comum especificar as margens de conteúdo como (0.5,0.5,0.5,0.5). Tanto os componentes da janela filho quanto as janelas de "nível superior" podem ser criados; em alguns casos, agora podemos usar exibições gráficas para aplicativos MDI avançados.

Algumas propriedades do QWidget são suportadas, incluindo sinalizadores de janela e atributos, mas não todas. Devemos consultar a documentação da classe QGraphicWidget para obter uma visão geral completa do que é e do que não é suportado. Por exemplo, você pode criar janelas decorativas passando o sinalizador de janela Qt::Window para o construtor qgraphicwidget, mas a visualização gráfica atualmente não suporta os sinalizadores Qt::Sheet e Qt::Drawer usuais no macOS.

2. QGraphicsLayout

QGraphicsLayout faz parte da estrutura de layout de segunda geração projetada especificamente para qgraphicwidgets. Sua API é muito semelhante ao QLayout. Você pode gerenciar widgets e sublayouts em QGraphicsLinearLayout e QGraphicsGridLayout. Você também pode facilmente escrever seu próprio layout herdando QGraphicsLaytItem você mesmo, ou adicionar seu próprio QGraphicsItem Item ao layout escrevendo uma subclasse adaptadora de QGraphicsLayoutItem.

9. Suporte para incorporar widgets

A Visualização Gráfica fornece suporte contínuo para incorporar qualquer controle em uma Cena. Controles simples como QLineEdit ou QPushButton, controles complexos como QTabWidget ou até mesmo janelas principais completas podem ser incorporados. Para incorporar um widget em uma cena, basta chamar QGraphicsScene::addWidget() ou criar uma instância de QGraphicsProxyWidget para incorporar o widget manualmente.

Por meio do QGraphicsProxyWidget, o Graphics View pode integrar profundamente a funcionalidade do widget do cliente, incluindo cursor, dica de ferramenta, mouse, tablet e eventos de teclado, widgets filhos, animações, janelas pop-up (por exemplo, QComboBox ou QCompleter) e foco e ativação de entrada do widget. O QGraphicsProxyWidget integra até mesmo a ordem de tabulação dos widgets incorporados para que possamos entrar e sair dos widgets incorporados. Podemos até incorporar o novo QGraphicsView em nossa cena para fornecer cenas aninhadas complexas.

Ao converter controles incorporados, a Visualização gráfica garante que os controles convertam a resolução independentemente, permitindo que fontes e estilos permaneçam legíveis quando ampliados. (Observe que o efeito da independência de resolução depende do estilo.)

5. Desempenho

Para aplicar transformações e efeitos especiais aos elementos com precisão e rapidez, a visualização gráfica é construída assumindo que o hardware do usuário pode fornecer desempenho razoável para instruções de ponto flutuante.
Muitas estações de trabalho e computadores de mesa são equipados com hardware apropriado para acelerar esses cálculos, mas alguns dispositivos incorporados podem fornecer apenas bibliotecas para lidar com operações matemáticas ou emular instruções de ponto flutuante em software.

Portanto, alguns tipos de efeitos podem ser mais lentos do que o esperado em alguns dispositivos. Essa perda de desempenho pode ser compensada otimizando de outras maneiras; por exemplo, renderizando uma Cena usando OpenGL. No entanto, se essa otimização em si também depender de hardware de ponto flutuante, o desempenho será prejudicado.

Acho que você gosta

Origin blog.csdn.net/qq_43680827/article/details/132252105
Recomendado
Clasificación