Schilderen en tekenen op besturingselementen (Windows Forms .NET)
Aangepast schilderen van besturingselementen is een van de vele gecompliceerde taken die eenvoudig zijn gemaakt door Windows Forms. Bij het ontwerpen van een custom control zijn er veel opties beschikbaar om het grafische uiterlijk van uw besturingselement te beheren. Als u een aangepast besturingselement ontwerpt, dat wil gezegd, een besturingselement dat overneemt van Control, moet u code opgeven om de grafische weergave ervan weer te geven.
Als u een samengesteld besturingselement maakt, is dat een besturingselement dat wordt overgenomen van UserControl of een van de bestaande Besturingselementen van Windows Forms, kunt u de standaard grafische weergave overschrijven en uw eigen grafische code opgeven.
Als u aangepaste rendering wilt bieden voor een bestaand besturingselement zonder een nieuw besturingselement te maken, worden uw opties beperkter. Er zijn echter nog steeds een breed scala aan grafische mogelijkheden voor uw besturingselementen en toepassingen.
De volgende elementen zijn betrokken bij het weergeven van besturingselementen:
- De tekenfunctionaliteit van de basisklasse System.Windows.Forms.Control.
- De essentiële elementen van de GDI-grafische bibliotheek.
- De geometrie van het tekengebied.
- De procedure voor het vrijmaken van grafische resources.
Tekening geleverd door besturingselement
De basisklasse Control biedt tekenfunctionaliteit via de Paint gebeurtenis. Een besturingselement triggert de Paint-gebeurtenis wanneer het de weergave moet bijwerken. Zie Afhandeling en het genereren van gebeurtenissenvoor meer informatie over gebeurtenissen in .NET.
De gebeurtenisgegevensklasse voor de Paint gebeurtenis, PaintEventArgs, bevat de gegevens die nodig zijn voor het tekenen van een besturingselement: een ingang voor een grafisch object en een rechthoek die de regio vertegenwoordigt die moet worden getekend.
public class PaintEventArgs : EventArgs, IDisposable
{
public System.Drawing.Rectangle ClipRectangle {get;}
public System.Drawing.Graphics Graphics {get;}
// Other properties and methods.
}
Public Class PaintEventArgs
Inherits EventArgs
Implements IDisposable
Public ReadOnly Property ClipRectangle As System.Drawing.Rectangle
Public ReadOnly Property Graphics As System.Drawing.Graphics
' Other properties and methods.
End Class
Graphics is een beheerde klasse die tekenfunctionaliteit inkapselt, zoals verderop in dit artikel wordt beschreven in de bespreking van GDI. De ClipRectangle is een exemplaar van de Rectangle structuur en definieert het beschikbare gebied waarin een besturingselement kan tekenen. Een besturingselementontwikkelaar kan de ClipRectangle berekenen met behulp van de eigenschap ClipRectangle van een besturingselement, zoals beschreven in de bespreking van geometrie verderop in dit artikel.
OnPaint
Een controle moet renderinglogica bieden door de OnPaint methode te overschrijven die het erft van Control. OnPaint krijgt toegang tot een grafisch object en een rechthoek om in te tekenen via de Graphics en ClipRectangle eigenschappen van het PaintEventArgs exemplaar dat aan hem is doorgegeven.
De volgende code maakt gebruik van de System.Drawing
-naamruimte:
protected override void OnPaint(PaintEventArgs e)
{
// Call the OnPaint method of the base class.
base.OnPaint(e);
// Declare and instantiate a new pen that will be disposed of at the end of the method.
using var myPen = new Pen(Color.Aqua);
// Create a rectangle that represents the size of the control, minus 1 pixel.
var area = new Rectangle(new Point(0, 0), new Size(this.Size.Width - 1, this.Size.Height - 1));
// Draw an aqua rectangle in the rectangle represented by the control.
e.Graphics.DrawRectangle(myPen, area);
}
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
' Declare and instantiate a drawing pen.
Using myPen = New System.Drawing.Pen(Color.Aqua)
' Create a rectangle that represents the size of the control, minus 1 pixel.
Dim area = New Rectangle(New Point(0, 0), New Size(Me.Size.Width - 1, Me.Size.Height - 1))
' Draw an aqua rectangle in the rectangle represented by the control.
e.Graphics.DrawRectangle(myPen, area)
End Using
End Sub
De OnPaint method van de basisklasse Control implementeert geen tekenfunctionaliteit, maar roept alleen de event-delegaten aan die zijn geregistreerd voor de Paint gebeurtenis. Wanneer u OnPaintoverschrijft, moet u doorgaans de OnPaint methode van de basisklasse aanroepen, zodat geregistreerde gemachtigden de Paint gebeurtenis ontvangen. Besturingselementen die hun hele oppervlak schilderen, moeten echter niet de OnPaintvan de basisklasse aanroepen, omdat dit flikkert.
Notitie
Roep OnPaint niet rechtstreeks vanuit uw besturingselement aan; Roep in plaats daarvan de Invalidate methode aan (overgenomen van Control) of een andere methode die Invalidateaanroept. De Invalidate methode roept op zijn beurt OnPaintaan. De methode Invalidate is overbelast en, afhankelijk van de argumenten die aan Invalidatee
worden opgegeven, wordt een deel of al het schermgebied opnieuw getekend.
De code in de OnPaint-methode van uw besturingselement wordt uitgevoerd wanneer het besturingselement voor het eerst wordt getekend en telkens wanneer het wordt vernieuwd. Om ervoor te zorgen dat uw controle telkens opnieuw wordt getekend wanneer het formaat wordt gewijzigd, voegt u de volgende regel toe aan de constructor van uw controle:
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.ResizeRedraw, True)
OnPaintBackground
De basisklasse Control definieert een andere methode die handig is voor tekenen, de OnPaintBackground methode.
protected virtual void OnPaintBackground(PaintEventArgs e);
Protected Overridable Sub OnPaintBackground(e As PaintEventArgs)
OnPaintBackground verft de achtergrond (en op die manier de vorm) van het venster en is gegarandeerd snel, terwijl OnPaint de details verft en langzamer kan zijn omdat afzonderlijke verfaanvragen worden gecombineerd tot één Paint gebeurtenis die alle gebieden omvat die opnieuw moeten worden getekend. U kunt de OnPaintBackground aanroepen als u bijvoorbeeld een kleurovergang als achtergrond voor uw controle wilt tekenen.
Hoewel OnPaintBackground een gebeurtenisachtige nomenclatuur heeft en hetzelfde argument als de methode OnPaint
gebruikt, is OnPaintBackground
geen echte gebeurtenismethode. Er is geen PaintBackground
gebeurtenis en OnPaintBackground
roept geen gedelegeerden voor gebeurtenissen aan. Bij het overschrijven van de OnPaintBackground
methode is een afgeleide klasse niet vereist om de OnPaintBackground
methode van de basisklasse aan te roepen.
GDI+ Basisbeginselen
De klasse Graphics biedt methoden voor het tekenen van verschillende vormen, zoals cirkels, driehoeken, bogen en weglatingstekens en methoden voor het weergeven van tekst. De System.Drawing naamruimte bevat naamruimten en klassen die grafische elementen inkapselen, zoals vormen (cirkels, rechthoeken, bogen en andere), kleuren, lettertypen, penselen enzovoort.
Geometrie van het tekengebied
De eigenschap ClientRectangle van een besturingselement specificeert de rechthoekige regio die beschikbaar is voor het besturingselement op het scherm van de gebruiker, terwijl de eigenschap ClipRectangle van PaintEventArgs het gebied specificeert dat is geverfd. Een besturingselement moet mogelijk slechts een deel van het beschikbare gebied schilderen, zoals het geval is wanneer een klein gedeelte van de weergave van het besturingselement verandert. In dergelijke situaties moet een ontwikkelaar voor bedieningselementen de werkelijke rechthoek berekenen om in te tekenen en deze doorgeven aan Invalidate. De overbelaste versies van Invalidate die een Rectangle of Region als argument hebben, gebruiken dat argument om de eigenschap ClipRectangle van PaintEventArgste genereren.
Grafische bronnen vrijmaken
Grafische objecten zijn duur omdat ze systeembronnen gebruiken. Dergelijke objecten omvatten exemplaren van de System.Drawing.Graphics klasse en exemplaren van System.Drawing.Brush, System.Drawing.Penen andere grafische klassen. Het is belangrijk dat u alleen een grafische resource maakt wanneer u deze nodig hebt en laat deze direct weer los zodra u klaar bent met het gebruik. Als u een exemplaar maakt van een type dat de IDisposable-interface implementeert, roept u de bijbehorende Dispose methode aan wanneer u hiermee klaar bent om resources vrij te maken.
Zie ook
.NET Desktop feedback