Alfabetização Qt - visão geral do sistema Qt Paint

I. Visão geral

O sistema de pintura do Qt pode usar a mesma API para desenhar na tela e no dispositivo de impressão.É baseado principalmente nas classes QPainter, QPaintDevice e QPaintEnengine.

QPainter é usado para executar operações de desenho. QPaintDevice é uma abstração de um espaço bidimensional no qual QPainter pode ser usado para desenhar. QPaintEngine fornece uma interface para QPainter desenhar em diferentes tipos de dispositivos. A classe QPaintEngine é usada internamente por QPainter e QPaintDevice e está oculta para nós como programadores de aplicativos, a menos que criemos nossos próprios tipos de dispositivos de desenho.

O principal benefício dessa abordagem é que todos os desenhos seguem o mesmo canal de desenho, o que torna mais fácil adicionar suporte para novos recursos e fornecer implementações padrão para recursos sem suporte. Em outras palavras, é muito escalável.

2. Dispositivo de desenho e back-end

A classe QPaintDevice é a classe base dos objetos desenháveis, ou seja, QPainter pode desenhar em qualquer subclasse de QPaintDevice. A função de desenho do QPaintDevice é realizada por QWidget, QImage, QPixmap, QPicture, QPrinter e QOpenGLPaintDevice.

As classes mencionadas abaixo todas herdam QPaintDevice para que tenham a função de desenhar

1. Widget

A classe QWidget é a classe base para os elementos da interface do usuário no módulo Qt Widgets. Ele recebe mouse, teclado e outros eventos do sistema de janelas e se exibe na tela. É uma parte importante do sistema de janelas

2. Imagem

A classe QImage fornece uma representação de imagem independente de hardware, projetada e otimizada para E/S e acesso direto e manipulação de pixel. O QImage suporta uma variedade de formatos de imagem, incluindo imagens monocromáticas, de 8 bits, 32 bits e alfa combinadas.

Há duas vantagens em usar o QImage como um dispositivo de desenho:

  1. A precisão de pixels de qualquer operação de desenho pode ser garantida de maneira independente da plataforma.
  2. O desenho pode ser executado em outro encadeamento que não seja o encadeamento da GUI atual.

3. Pixmap

A classe QPixmap é uma representação de imagem fora da tela projetada e otimizada para exibição de imagens na tela. Ao contrário do QImage, os dados de pixel no pixmap são internos e gerenciados pelo sistema de janela subjacente, ou seja, os pixels só podem ser acessados ​​por meio de funções QPainter ou convertendo QPixmap em QImage.

Para otimizar o desenho com QPixmap, o Qt fornece a classe QPixmapCache, que pode ser usada para armazenar pixmaps temporários que são caros de gerar sem usar espaço de armazenamento que exceda o limite do cache.

Qt também fornece a classe de conveniência QBitmap, que herda de QPixmap. O QBitmap garante um mapa de pixels monocromático (profundidade de 1 bit), usado principalmente para criar objetos QCursor e QBrush personalizados e construir objetos QRegion.

4. Dispositivo de desenho OpenGL

Como mencionado anteriormente, o Qt fornece classes que facilitam o uso do OpenGL em aplicativos Qt. Por exemplo, QOpenGLPaintDevice ativa a API OpenGL para renderização QPainter.

5. Foto

A classe QPicture é um dispositivo de desenho que grava e reproduz comandos QPainter. A imagem serializa comandos do pintor para dispositivos IO em um formato independente de plataforma. O QPicture também é independente da resolução, ou seja, um QPicture pode ser exibido em diferentes dispositivos (como svg, pdf, ps, impressora e tela) e ter a mesma aparência.

O Qt fornece funções QPicture::load() e QPicture::save() e operadores de fluxo para carregar e salvar imagens.

6. Back-end de desenho personalizado

O suporte para novos backends pode ser obtido derivando da classe QPaintDevice e reimplementando a função fictícia QPaintDevice::paintEngine() para informar ao QPainter qual mecanismo de pintura ele deve usar para desenhar neste dispositivo específico.

Para poder desenhar no dispositivo, esse mecanismo de desenho deve ser um mecanismo de desenho personalizado criado pela classe QPaintDevice derivada.

3. Desenho e preenchimento

1. Desenho

O QPainter fornece funções altamente otimizadas para fazer o desenho exigido pela maioria dos programas GUI. Ele pode desenhar qualquer coisa, desde primitivas gráficas simples (representadas pelas classes QPoint, QLine, QRect, QRegion e QPolygon) até formas complexas, como caminhos vetoriais. No Qt, os caminhos vetoriais são representados pela classe QPainterPath. QPainterPath fornece um contêiner para operações de desenho, permitindo que formas gráficas sejam construídas e reutilizadas.

insira a descrição da imagem aqui

1. QPainterPath
QPainterPath é um objeto composto de linhas e curvas. Por exemplo, retângulos são feitos de linhas retas e elipses são feitas de linhas curvas.

A principal vantagem dos caminhos do pintor sobre as operações normais de desenho é que as formas complexas precisam ser criadas apenas uma vez; elas podem ser desenhadas várias vezes simplesmente chamando a função QPainter::drawPath().

Os objetos QPainterPath podem ser usados ​​para preenchimento, contorno e recorte. Para gerar um contorno preenchível para um determinado caminho de pintor, use a classe QPainterPathStroker.

Linhas e contornos são desenhados usando a classe QPen. Uma caneta é definida por seu estilo (ou seja, seu tipo de linha), largura, pincel, como as tampas são desenhadas (estilo de tampa) e como duas linhas conectadas se conectam (estilo de junção). O pincel da caneta é um objeto QBrush, que é utilizado para preencher os traços gerados pela caneta, ou seja, a classe QBrush define o modo de preenchimento.

O QPainter também pode desenhar texto alinhado e mapas de pixels.

Ao desenhar texto, a fonte é especificada usando a classe QFont. O Qt usará a fonte com as propriedades especificadas, se nenhuma fonte correspondente existir, o Qt usará a fonte instalada mais próxima. As propriedades reais da fonte usadas podem ser obtidas usando a classe QFontInfo. Além disso, a classe QFontMetrics fornece métricas de fonte e a classe QFontDatabase fornece informações sobre fontes disponíveis no sistema de janela subjacente.

Normalmente, o QPainter desenha em um sistema de coordenadas "natural", mas pode usar a classe QTransform para realizar transformações entre a visão e os sistemas de coordenadas do mundo. Para obter mais informações, consulte Sistemas de coordenadas, que também descreve o processo de renderização, a relação entre representações lógicas e pixels renderizados e os benefícios do desenho suavizado.

2. Desenho suavizado
Ao desenhar, a renderização de pixels é controlada pela dica de renderização QPainter::Antialiasing. A enumeração QPainter::RenderHint é usada para especificar sinalizadores para QPainter que podem ou não ser usados ​​por qualquer mecanismo.

O valor QPainter::Antialiasing indica que o mecanismo deve eliminar as bordas da primitiva, se possível, ou seja, suavizar as bordas usando diferentes intensidades de cores.

insira a descrição da imagem aqui

2. Preenchimento

Preencha a forma usando a classe QBrush. Um pincel é definido por sua cor e estilo (ou seja, seu modo de preenchimento).

Qualquer cor no Qt é representada pela classe QColor, que suporta modelos de cores RGB, HSV e CMYK. QColor também oferece suporte a contornos e preenchimentos combinados alfa (para especificar efeitos de transparência), e a classe é independente de plataforma e dispositivo (use a classe QColormap para mapear cores para hardware).
insira a descrição da imagem aqui

Os padrões de preenchimento disponíveis são descritos pela enumeração Qt::BrushStyle. Isso inclui padrões básicos que variam de cores uniformes a padrões muito esparsos, várias combinações de linhas, preenchimentos de gradiente e texturas. O Qt fornece a classe QGradient para definir um preenchimento de gradiente personalizado e usa a classe QPixmap para especificar o modo de textura.

1. QGradient
A classe QGradient é usada em conjunto com a classe QBrush para especificar o preenchimento de gradiente.
insira a descrição da imagem aqui

Qt atualmente suporta três tipos de preenchimentos de gradiente: gradientes lineares interpolam a cor entre os pontos inicial e final, gradientes radiais interpolam a cor entre o ponto focal e o ponto final na circunferência e gradientes cônicos interpolam a cor ao redor do ponto central.

4. Sistema de coordenadas

O sistema de coordenadas é controlado pela classe QPainter. Juntamente com as classes QPaintDevice e QPaintEngine, QPainter forma a base do sistema de pintura do Qt. QPainter é usado para executar operações de desenho. QPaintDevice é uma abstração de um espaço bidimensional no qual QPainter pode ser usado para desenhar. QPaintEngine fornece uma interface para QPainter desenhar em diferentes tipos de dispositivos.

A classe QPaintDevice é a classe base para objetos desenháveis: sua funcionalidade de desenho é herdada pelas classes QWidget, QImage, QPixmap, QPicture e QOpenGLPaintDevice. O sistema de coordenadas padrão para dispositivos de desenho se origina no canto superior esquerdo. Os valores x aumentam para a direita e os valores y aumentam para baixo. A unidade padrão é um pixel em dispositivos baseados em pixel e um ponto (1/72 de polegada) em impressoras.

O mapeamento das coordenadas lógicas do QPainter para as coordenadas físicas do QPaintDevice é feito pela matriz de transformação, viewport e "janela" do QPainter. O sistema de coordenadas lógicas e o sistema de coordenadas físicas coincidem por padrão. O QPainter também suporta transformações de coordenadas (como rotação e escala).

1. Renderização

1. Representação lógica
O tamanho (largura e altura) de uma primitiva gráfica sempre corresponde ao seu modelo matemático, independentemente da largura da pena utilizada para renderização:
insira a descrição da imagem aqui

2. Pintura sem suavização
Ao desenhar, a renderização de pixels é controlada pelo parâmetro de renderização QPainter::Antialiasing.

A enumeração RenderHint é usada para especificar sinalizadores para QPainter que podem ou não ser usados ​​por qualquer mecanismo. O valor QPainter::Antialiasing indica que o mecanismo deve eliminar as bordas da primitiva se possível, ou seja, suavizar as bordas usando diferentes intensidades de cores.

Mas, por padrão, o pintor é renderizado com aliasing e outras regras se aplicam: ao renderizar com uma caneta de um pixel de largura, os pixels serão renderizados à direita e abaixo de um ponto definido matematicamente. Por exemplo:

insira a descrição da imagem aqui

Ao renderizar com uma caneta com pixels pares, os pixels serão renderizados simetricamente em torno de um ponto definido matematicamente, enquanto com uma caneta com pixels ímpares, os pixels livres serão renderizados à direita e abaixo do ponto matemático, exatamente como um mesmo de 1 pixel situação. Para um exemplo específico, consulte o diagrama QRectF abaixo.

insira a descrição da imagem aqui

Observe que, por razões históricas, os valores de retorno das funções QRect::right() e QRect::bottom() desviam do verdadeiro canto inferior direito do retângulo.

A função right() de QRect retorna left() + width() - 1, enquanto a função bottom() retorna top() + height() - 1. Os pontos verdes na imagem acima mostram as coordenadas de retorno dessas funções.

Recomendamos que você use QRectF diretamente: a classe QRectF usa coordenadas de ponto flutuante para definir um retângulo no plano para garantir precisão (QRect usa coordenadas inteiras), enquanto as funções QRectF::right() e QRectF::bottom() retornam o verdadeiro canto inferior direito.

Como alternativa, usando um QRect, aplique x() + width() e y() + height() para encontrar o canto inferior direito, evitando as funções right() e bottom().

3. Pintura anti-aliased
Se você definir a dica de renderização anti-aliased do QPainter, os pixels serão renderizados simetricamente em ambos os lados do ponto definido matematicamente:
insira a descrição da imagem aqui
4. Transformação

Por padrão, o QPainter opera no próprio sistema de coordenadas do dispositivo associado, mas também suporta totalmente as transformações de coordenadas afins.
insira a descrição da imagem aqui

Podemos dimensionar o sistema de coordenadas por um determinado deslocamento usando a função QPainter::scale(), podemos girá-lo no sentido horário usando a função QPainter::rotate() e podemos traduzi-lo usando a função QPainter::translate() ( ou seja, adiciona o deslocamento dado ao ponto).

Você também pode girar o sistema de coordenadas ao redor da origem usando a função QPainter::shear(). Todas as operações de transformação são executadas na matriz de transformação do QPainter, que você pode obter usando a função QPainter::worldTransform(). Uma matriz transforma um ponto em um plano em outro.

Se precisar usar a mesma transformação repetidamente, você também pode usar o objeto QTransform e as funções QPainter::worldTransform() e QPainter::setWorldTransform(). Você pode salvar a matriz de transformação do QPainter a qualquer momento chamando a função QPainter::save(), que salva a matriz na pilha interna. A função QPainter::restore() o exibe.

As matrizes de transformação geralmente são necessárias ao reutilizar o mesmo código de desenho em vários dispositivos de desenho. Sem transformações, o resultado estará fortemente vinculado à resolução do dispositivo de desenho. As impressoras têm altas resoluções, como 600 pontos por polegada, enquanto as telas normalmente têm entre 72 e 100 pontos por polegada.

O exemplo Analog Clock mostra como usar a matriz de transformação do QPainter para pintar o conteúdo de um controle personalizado.
Recomendamos compilar e executar este exemplo antes de ler mais. Em particular, tente redimensionar a janela para um tamanho diferente.

insira a descrição da imagem aqui

  void AnalogClockWindow::render(QPainter *p)
  {
    
    
      static const QPoint hourHand[3] = {
    
    
          QPoint(7, 8),
          QPoint(-7, 8),
          QPoint(0, -40)
      };
      static const QPoint minuteHand[3] = {
    
    
          QPoint(7, 8),
          QPoint(-7, 8),
          QPoint(0, -70)
      };

      QColor hourColor(127, 0, 127);
      QColor minuteColor(0, 127, 127, 191);

      p->setRenderHint(QPainter::Antialiasing);
      p->translate(width() / 2, height() / 2);

      int side = qMin(width(), height());
      p->scale(side / 200.0, side / 200.0);

Transformamos o sistema de coordenadas para que o ponto (0,0) fique no centro do controle, e não no canto superior esquerdo. Também dimensionamos o sistema por lado/100, onde lado é a largura ou a altura do controle, o que for menor. Queremos que o relógio seja quadrado, mesmo que o dispositivo não seja.

Isso nos dará uma área quadrada de 200 x 200 com a origem (0,0) no centro, na qual podemos desenhar. O que desenhamos aparecerá no maior quadrado possível que caiba no controle.

Consulte também a seção de conversão de janela para viewport.

      QTime time = QTime::currentTime();

      p->save();
      p->rotate(30.0 * ((time.hour() + time.minute() / 60.0)));
      p->drawConvexPolygon(hourHand, 3);
      p->restore();

Desenhamos o ponteiro das horas do relógio girando o sistema de coordenadas e chamando QPainter::drawConvexPolygon(). Devido à rotação, é desenhado na orientação correta.
O polígono é especificado como uma matriz de valores x, y alternados, armazenados na variável estática hourHand (definida no início da função), que corresponde aos quatro pontos (2,0), (0,2), (- 2,0 ) e (0, -25).

Chamadas para QPainter::save() e QPainter::restore() ao redor do código garantem que o code-behind não interfira nas transformações que usamos.

      p->save();
      p->rotate(6.0 * (time.minute() + time.second() / 60.0));
      p->drawConvexPolygon(minuteHand, 3);
      p->restore();

Fazemos o mesmo para o ponteiro dos minutos do relógio, que é definido pelos quatro pontos (1,0), (0,1), (-1,0) e (0,-40). Essas coordenadas especificam um ponteiro mais fino e mais longo que uma agulha.

      p->setPen(minuteColor);

      for (int j = 0; j < 60; ++j) {
    
    
          if ((j % 5) != 0)
              p->drawLine(92, 0, 96, 0);
          p->rotate(6.0);
      }

Por fim, desenhamos o mostrador do relógio, que consiste em 12 linhas curtas espaçadas em 30 graus.

Conversão de Janela-Viewport

Ao desenhar com QPainter, especificamos pontos usando coordenadas lógicas, que são então convertidas para as coordenadas físicas do dispositivo de desenho.

O mapeamento de coordenadas lógicas para coordenadas físicas é tratado pela transformação de mundo do QPainter worldTransform() (descrito na seção Transformação) e viewport() e window() do QPainter. A viewport representa coordenadas físicas especificando um retângulo arbitrário. Uma "janela" descreve o mesmo retângulo em coordenadas lógicas. Por padrão, os sistemas de coordenadas lógico e físico são coincidentes, equivalentes ao retângulo de desenho do dispositivo.

Usando a transformação janela-janela, podemos fazer com que o sistema lógico de coordenadas corresponda às nossas preferências. O também pode ser usado para tornar o código de desenho independente do QPaintDevice. Por exemplo, você pode estender as coordenadas lógicas de (-50,-50) para (50,50), com (0,0) no meio, chamando a função QPainter::setwinwindow():

  QPainter painter(this);
  painter.setWindow(QRect(-50, -50, 100, 100));

Agora as coordenadas lógicas (-50,-50) correspondem às coordenadas físicas (0,0) do dispositivo de desenho. Independente do dispositivo de desenho, nosso código de desenho sempre operará em coordenadas lógicas especificadas. É equivalente a que podemos definir manualmente essa relação de coordenadas. Uma relação conveniente para você mesmo definir essas coordenadas.

Definindo a "janela" ou o retângulo da viewport, uma transformação linear de coordenadas pode ser executada. Observe que cada canto da "janela" é mapeado para um canto correspondente da viewport e vice-versa. Por esse motivo, geralmente é uma boa ideia manter a viewport e a "janela" na mesma proporção para evitar distorções:

  int side = qMin(width(), height())
  int x = (width() - side / 2);
  int y = (height() - side / 2);

  painter.setViewport(x, y, side, side);

Se definirmos o sistema de coordenadas lógicas como quadrado, também devemos definir a viewport como quadrada usando a função QPainter::setViewport(). No exemplo acima, configuramos para o maior quadrado que cabe no retângulo de desenho do dispositivo. Você pode manter seu código de desenho independente do dispositivo de desenho levando em consideração o tamanho do dispositivo de desenho ao configurar a janela ou viewport.

Observe que a transformação de janela para viewport é apenas uma transformação linear, ou seja, não realiza recorte. Isso significa que, se você desenhar fora da "janela" definida atualmente, seu desenho ainda será convertido para a viewport usando o mesmo método de álgebra linear.

insira a descrição da imagem aqui

As matrizes de viewport, "janela" e transformação determinam como as coordenadas lógicas do QPainter são mapeadas para as coordenadas físicas do dispositivo de desenho. Por padrão, a matriz de transformação do mundo é a matriz de identidade, e as configurações de "janela" e viewport são equivalentes às do dispositivo de desenho, ou seja, o mundo, a "janela" e os sistemas de coordenadas do dispositivo são equivalentes, mas como vimos , o sistema pode manipular usando operações de transformação e transformações de janela de visualização.

5. Leia e grave arquivos de imagem

A maneira mais comum de ler uma imagem é através dos construtores QImage e QPixmap, ou chamando as funções QImage::load() e QPixmap::load(). Além disso, o Qt fornece a classe QImageReader, que fornece mais controle sobre o processo. Dependendo do suporte subjacente do formato de imagem, a classe fornece funções que economizam memória e aceleram o carregamento da imagem.

Da mesma forma, o Qt fornece a classe QImageWriter, que suporta a configuração de opções específicas de formato, como gama, nível de compactação e qualidade antes de armazenar a imagem. Se não precisarmos dessas opções, podemos usar QImage::save() ou QPixmap::save().

insira a descrição da imagem aqui

1. QMovie

QMovie é uma classe de conveniência para exibir animações, usando internamente a classe QImageReader. Depois de criada, a classe QMovie fornece várias funções para executar e controlar uma determinada animação.

As classes QImageReader e QImageWriter dependem da classe QImageIOHandler. A classe QImageIOHandler é uma interface de E/S de imagem geral para todos os formatos de imagem em Qt. QImageReader e QImageWriter usam internamente o objeto QImageIOHandler para adicionar suporte a diferentes formatos de imagem para Qt.
As funções QImageReader::supportedImageFormats() e QImageWriter::supportedImageFormats() fornecem uma lista de formatos de arquivo suportados. O Qt suporta vários formatos de arquivo por padrão, além disso, novos formatos podem ser adicionados por meio de plug-ins. Os formatos suportados atualmente estão listados na documentação da classe QImageReader e QImageWriter.
O mecanismo de plug-in do Qt também pode ser usado para escrever manipuladores de formato de imagem personalizados. Isso é feito derivando da classe QImageIOHandler e criando um objeto QImageIOPlugin, que é uma fábrica para criar objetos QImageIOHandler. Quando o plug-in é instalado, o QImageReader e o QImageWriter carregam automaticamente o plug-in e começam a usá-lo.

6. Equipamento relacionado ao desenho

Relacionado à pintura Função
QBitmap Mapa de pixels monocromático (profundidade de 1 bit)
QBrushGenericName Define o modo de preenchimento para formas desenhadas pelo QPainter
QColor Cores baseadas em valores RGB, HSV ou CMYK
QColorSpaceGenericName abstração de espaço de cor
QColorTransform Conversão entre espaços de cores
QColormap Mapeia QColors independentes de dispositivo para valores de pixel dependentes de dispositivo
QGradiente Cônico Usado em combinação com QBrush para especificar um pincel de gradiente cônico
QFont Especifica consultas de fonte para desenho de texto
QFontMetrics informações de métricas de fonte
QFontMetricsF informações de métricas de fonte
QGenericMatrixComment Uma classe de modelo representando uma matriz de transformação NxM com N colunas e M linhas
QGradiente Usado em combinação com QBrush para especificar preenchimentos de gradiente
QIcon Ícones escaláveis ​​em diferentes modos e estados
QIconEngineGenericName Classe base abstrata para renderizadores QIcon
QImage Uma representação de imagem independente de hardware que permite acesso direto a dados de pixel e pode ser usada como um dispositivo de desenho
QImageReader Interface independente de formato para leitura de imagens de arquivos ou outros dispositivos
QImageWriterGenericName Interface independente de formato para gravar imagens em arquivos ou outros dispositivos
QLine Vetor 2-D usando precisão inteira
QLineF Vetores 2D usam precisão de ponto flutuante
QLinearGradient Usado em combinação com QBrush para especificar um pincel de gradiente linear
QMargins Defina as quatro margens do retângulo
QMargensF Defina as quatro margens do retângulo
QPagedPaintDeviceName Indica um dispositivo de desenho que suporta várias páginas
QPaintDevice Classe base para objetos que podem ser desenhados com QPainter
QPaintEngineGenericName Uma definição abstrata de como o QPainter desenha para um determinado dispositivo em uma determinada plataforma
QPainter Execute desenhos de baixo nível em widgets e outros dispositivos de desenho
QPainterPathGenericName Um contêiner para operações de desenho, permitindo que os gráficos sejam construídos e reutilizados
QPainterPathStrokerName Usado para gerar um contorno preenchível para um determinado caminho de desenho
QPdfWriter classe para gerar pdfs que podem ser usados ​​como dispositivos de plotagem
QPen Define como um QPainter deve desenhar os contornos de linhas e formas
QPixmap Uma representação de imagem fora da tela que pode ser usada como um dispositivo de desenho
PontoQ definir um ponto no plano usando precisão inteira
QPointF definir um ponto no plano usando precisão de ponto flutuante
QPolígono Vetor de ponto usando precisão inteira
QPolygonF Vetor de ponto usando precisão de ponto flutuante
QRadialGradient Especificando um pincel de gradiente radial usando combinação com QBrush
QRect definir um retângulo no plano usando precisão inteira
QRectF define um retângulo no plano usando precisão de ponto flutuante
QRegion Especifica a região de recorte para o paintr
QRgba64 Estrutura contendo cores RGB de 64 bits
QSize Defina o tamanho de um objeto 2D usando precisão de ponto inteiro
QSizeF Defina o tamanho de um objeto 2D usando precisão de ponto flutuante
QStylePainter Classe de conveniência para desenhar elementos QStyle em widgets
QSistemas de Escrita Suportados Ao registrar fontes com o uso do banco de dados de fonte Qt interno
QSvgGenerator Um dispositivo de desenho para criar desenhos SVG
QSvgRendererGenericName Usado para desenhar o conteúdo de um arquivo SVG em um dispositivo de desenho
QSvgWidgetGenericName Um controle para exibir o conteúdo de um arquivo Scalable Vector Graphics (SVG)
QTransform Transformação 2D do sistema de coordenadas especificado
QVector2D representam vetores ou vértices no espaço bidimensional

Acho que você gosta

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