Condividi tramite


Contenitori di oggetti Graphics

Lo stato della grafica, ovvero l'area di ritaglio, le trasformazioni e le impostazioni di qualità, viene archiviato in un oggetto Graphics . Windows GDI+ consente di sostituire o aumentare temporaneamente parte dello stato in un oggetto Graphics usando un contenitore. Per avviare un contenitore, chiamare il metodo Graphics::BeginContainer di un oggetto Graphics e terminare un contenitore chiamando il metodo Graphics::EndContainer . Tra Graphics::BeginContainer e Graphics::EndContainer, tutte le modifiche apportate allo stato apportate all'oggetto Graphics appartengono al contenitore e non sovrascrivono lo stato esistente dell'oggetto Graphics .

Nell'esempio seguente viene creato un contenitore all'interno di un oggetto Graphics . La trasformazione globale dell'oggetto Graphics è una conversione di 200 unità a destra e la trasformazione globale del contenitore è una conversione di 100 unità verso il basso.

myGraphics.TranslateTransform(200.0f, 0.0f);

myGraphicsContainer = myGraphics.BeginContainer();
   myGraphics.TranslateTransform(0.0f, 100.0f);
   myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50);
myGraphics.EndContainer(myGraphicsContainer);

myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50);

Si noti che nell'esempio precedente l'istruzione myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50) eseguita tra le chiamate a Graphics::BeginContainer e Graphics::EndContainer produce un rettangolo diverso rispetto alla stessa istruzione eseguita dopo la chiamata a Graphics::EndContainer. Solo la conversione orizzontale si applica alla chiamata DrawRectangle effettuata all'esterno del contenitore. Entrambe le trasformazioni, ovvero la conversione orizzontale di 200 unità e la conversione verticale di 100 unità, si applicano alla chiamata Graphics::D rawRectangle effettuata all'interno del contenitore. La figura seguente mostra i due rettangoli.

screenshot di una finestra con due rettangoli disegnati con una penna blu, una posizionata sopra l'altra

I contenitori possono essere annidati all'interno dei contenitori. Nell'esempio seguente viene creato un contenitore all'interno di un oggetto Graphics e un altro contenitore all'interno del primo contenitore. La trasformazione globale dell'oggetto Graphics è una traslazione di 100 unità nella direzione x e 80 unità nella direzione y. La trasformazione globale del primo contenitore è una rotazione a 30 gradi. La trasformazione globale del secondo contenitore è un ridimensionamento di un fattore pari a 2 nella direzione x. Una chiamata al metodo Graphics::D rawEllipse viene eseguita all'interno del secondo contenitore.

myGraphics.TranslateTransform(100.0f, 80.0f, MatrixOrderAppend);

container1 = myGraphics.BeginContainer();
   myGraphics.RotateTransform(30.0f, MatrixOrderAppend);

   container2 = myGraphics.BeginContainer();
      myGraphics.ScaleTransform(2.0f, 1.0f);
      myGraphics.DrawEllipse(&myPen, -30, -20, 60, 40);
   myGraphics.EndContainer(container2);

myGraphics.EndContainer(container1);

La figura seguente mostra l'ellisse.

screenshot di una finestra che contiene un'ellisse blu ruotata con il suo centro etichettato come (100,80)

Si noti che tutte e tre le trasformazioni si applicano alla chiamata Graphics::D rawEllipse effettuata nel secondo contenitore (più interno). Si noti anche l'ordine delle trasformazioni: prima scala, quindi ruota, quindi traduci. La trasformazione più interna viene applicata per prima e la trasformazione più esterna viene applicata per ultima.

Qualsiasi proprietà di un oggetto Graphics può essere impostata all'interno di un contenitore (tra le chiamate a Graphics::BeginContainer e Graphics::EndContainer). Ad esempio, un'area di ritaglio può essere impostata all'interno di un contenitore. Qualsiasi disegno eseguito all'interno del contenitore sarà limitato all'area di ritaglio del contenitore e sarà limitato anche alle aree di ritaglio di tutti i contenitori esterni e all'area di ritaglio dell'oggetto Graphics stesso.

Le proprietà descritte finora, ovvero la trasformazione globale e l'area di ritaglio, vengono combinate da contenitori annidati. Altre proprietà vengono sostituite temporaneamente da un contenitore annidato. Se, ad esempio, si imposta la modalità smoothing su SmoothingModeAntiAlias all'interno di un contenitore, tutti i metodi di disegno chiamati all'interno di tale contenitore useranno la modalità di smoothing antialias, ma i metodi di disegno chiamati dopo Graphics::EndContainer useranno la modalità di smoothing usata prima della chiamata a Graphics::BeginContainer.

Per un altro esempio di combinazione delle trasformazioni mondiali di un oggetto Graphics e di un contenitore, si supponga di voler disegnare un occhio e posizionarlo in varie posizioni su una sequenza di visi. Nell'esempio seguente viene disegnato un occhio centrato all'origine del sistema di coordinate.

void DrawEye(Graphics* pGraphics)
{
   GraphicsContainer eyeContainer;
   
   eyeContainer = pGraphics->BeginContainer();

      Pen myBlackPen(Color(255, 0, 0, 0));
      SolidBrush myGreenBrush(Color(255, 0, 128, 0));
      SolidBrush myBlackBrush(Color(255, 0, 0, 0));

      GraphicsPath myTopPath;
      myTopPath.AddEllipse(-30, -50, 60, 60);

      GraphicsPath myBottomPath;
      myBottomPath.AddEllipse(-30, -10, 60, 60);

      Region myTopRegion(&myTopPath);
      Region myBottomRegion(&myBottomPath);

      // Draw the outline of the eye.
      // The outline of the eye consists of two ellipses.
      // The top ellipse is clipped by the bottom ellipse, and
      // the bottom ellipse is clipped by the top ellipse.
      pGraphics->SetClip(&myTopRegion);
      pGraphics->DrawPath(&myBlackPen, &myBottomPath);
      pGraphics->SetClip(&myBottomRegion);
      pGraphics->DrawPath(&myBlackPen, &myTopPath);

      // Fill the iris.
      // The iris is clipped by the bottom ellipse.
      pGraphics->FillEllipse(&myGreenBrush, -10, -15, 20, 22);

      // Fill the pupil.
      pGraphics->FillEllipse(&myBlackBrush, -3, -7, 6, 9);

   pGraphics->EndContainer(eyeContainer);
}

La figura seguente mostra l'occhio e gli assi delle coordinate.

illustrazione che mostra un occhio composto da tre puntini di sospensione: uno per il contorno, l'iride e la pupilla

La funzione DrawEye, definita nell'esempio precedente riceve l'indirizzo di un oggetto Graphics e crea immediatamente un contenitore all'interno di tale oggetto Graphics . Questo contenitore isola qualsiasi codice che chiama la funzione DrawEye dalle impostazioni delle proprietà effettuate durante l'esecuzione della funzione DrawEye. Ad esempio, il codice nella funzione DrawEye imposta l'area di ritaglio dell'oggetto Graphics , ma quando DrawEye restituisce il controllo alla routine chiamante, l'area di ritaglio sarà come prima della chiamata a DrawEye.

Nell'esempio seguente vengono tracciati tre puntini di sospensione (visi), ognuno con un occhio interno.

// Draw an ellipse with center at (100, 100).
myGraphics.TranslateTransform(100.0f, 100.0f);
myGraphics.DrawEllipse(&myBlackPen, -40, -60, 80, 120);

// Draw the eye at the center of the ellipse.
DrawEye(&myGraphics);

// Draw an ellipse with center at 200, 100.
myGraphics.TranslateTransform(100.0f, 0.0f, MatrixOrderAppend);
myGraphics.DrawEllipse(&myBlackPen, -40, -60, 80, 120);

// Rotate the eye 40 degrees, and draw it 30 units above
// the center of the ellipse.
myGraphicsContainer = myGraphics.BeginContainer();
   myGraphics.RotateTransform(-40.0f);
   myGraphics.TranslateTransform(0.0f, -30.0f, MatrixOrderAppend);
   DrawEye(&myGraphics);
myGraphics.EndContainer(myGraphicsContainer);

// Draw a ellipse with center at (300.0f, 100.0f).
myGraphics.TranslateTransform(100.0f, 0.0f, MatrixOrderAppend);
myGraphics.DrawEllipse(&myBlackPen, -40, -60, 80, 120);

// Stretch and rotate the eye, and draw it at the 
// center of the ellipse.
myGraphicsContainer = myGraphics.BeginContainer();
   myGraphics.ScaleTransform(2.0f, 1.5f);
   myGraphics.RotateTransform(45.0f, MatrixOrderAppend);
   DrawEye(&myGraphics);
myGraphics.EndContainer(myGraphicsContainer);

La figura seguente mostra i tre puntini di sospensione.

screenshot di una finestra con tre puntini di sospensione, ognuno dei quali contiene un occhio con dimensioni e rotazioni diverse

Nell'esempio precedente tutti i puntini di sospensione vengono disegnati con la chiamata DrawEllipse(&myBlackPen, -40, -60, 80, 120), che disegna un'ellisse allineata al centro all'origine del sistema di coordinate. I puntini di sospensione vengono spostati dall'angolo superiore sinistro dell'area client impostando la trasformazione globale dell'oggetto Graphics . L'istruzione fa sì che il primo ellisse venga centrato su (100, 100). L'istruzione fa sì che il centro del secondo ellisse sia di 100 unità a destra del centro del primo ellisse. Analogamente, il centro del terzo ellisse è di 100 unità a destra del centro del secondo ellisse.

I contenitori nell'esempio precedente vengono usati per trasformare l'occhio rispetto al centro di un determinato ellisse. Il primo occhio viene disegnato al centro dell'ellisse senza alcuna trasformazione, quindi la chiamata DrawEye non si trova all'interno di un contenitore. Il secondo occhio viene ruotato di 40 gradi e disegnato 30 unità sopra il centro dell'ellisse, quindi la funzione DrawEye e i metodi che impostano la trasformazione vengono chiamati all'interno di un contenitore. Il terzo occhio è allungato e ruotato e disegnato al centro dell'ellisse. Come per il secondo occhio, la funzione DrawEye e i metodi che impostano la trasformazione vengono chiamati all'interno di un contenitore.