Questa classe gestisce delle immagini indipendenti dalla piattaforma, viene usata per caricare in memoria immagini memorizzate su file o per salvare delle immagini verso file. wxImage ha alcuni metodi utili per modifcare l'immagine (ad esempio modificandone le dimensioni o ruotandola) ma nessun metodo per disegnarci altre figure o per disegnare l'immagine in una finestra, per questo sono necessari wxBitmap e i DC. I tipi supportati sono:
Bitmap: solo in lettura
PNG: per caricamento e salvataggio
JPEG: per caricamento e salvataggio
GIF: solo per caricamento per motivi legali
PCX: per caricamento e salvataggio
PNM: per caricamento e salvataggio
TIFF: per caricamento e salvataggio
XPM: per caricamento e salvataggio
Icone: per caricamento e salvataggio
Vediamo come può essere usata la classe wxImage con un esempio di un programma che (con le opportune modifiche) potrebbe essere utile: tutti i file che corrispondono alla stringa passata sulla linea di comando allo script (o tutti i file con estensione ".bmp" se la linea di comando è vuota) vengono aperti, salvati come immagini PNG, poi ridotti a dimensioni 100 x 100 e infine salvati come immagini JPEG.
01: wxInitAllImageHandlers()
02: if len(sys.argv) == 2:
03: # Se sulla riga di comando viene passato un
04: # argomento si cerca fra i file che corrispondono
05: # all'argomento...
06: pathname = sys.argv[1]
07: else:
08: # ...altrimenti si aprono solo i file con estensione ".bmp".
09: pathname = "*.bmp"
10: # glob.glob(pathname) restituisce una lista che contiene tutti
11: # i file (o directory) che corrispondono a pathname.
12: for filename in glob.glob(pathname):
13: image = wxImage(filename, wxBITMAP_TYPE_ANY)
14: # I metodi di wxImage GetWidth e GetHeight ritornano entrambi
15: # un intero, che indica rispettivamente larghezza e altezza
16: # dell'immagine
17: print "'%s' caricato, larghezza = %d, altezza = %d" % \
18: (filename, image.GetWidth(), image.GetHeight())
19: image.SaveFile(filename + ".png", wxBITMAP_TYPE_PNG)
20: image.Rescale(100, 100)
21: image.SaveFile(filename + ".jpg", wxBITMAP_TYPE_JPEG)
linea 1: viene chiamata wxInitAllImageHandlers che fa in modo che sia possibile caricare immagini da tutti i tipi di file supportati
linea 13: viene caricata l'immagine, il primo argomento è il nome del file, il secondo è il tipo del file. Il tipo può essere: wxBITMAP_TYPE_BMP, wxBITMAP_TYPE_GIF, wxBITMAP_TYPE_JPEG, wxBITMAP_TYPE_PCX, wxBITMAP_TYPE_PNG, wxBITMAP_TYPE_PNM, wxBITMAP_TYPE_TIF, wxBITMAP_TYPE_XPM, wxBITMAP_TYPE_ICO. Questi corrispondono ai tipi di file supportati da wxImage, inoltre esiste wxBITMAP_TYPE_ANY che carica l'immagine tentando di riconoscere automaticamente il tipo. È anche possibile caricare un'immagine all'interno di un'istanza di wxImage già esistente con il metodo LoadFile che accetta gli stessi argomenti del costruttore
linea 19 e linea 21: SaveFile salva l'immagine nel file il cui nome è specificato come primo argomento. Il secondo argomento indica il formato con cui l'immagine deve essere salvata, i valori possibili sono wxBITMAP_TYPE_JPEG, wxBITMAP_TYPE_PNG, wxBITMAP_TYPE_PCX, wxBITMAP_TYPE_PNM, wxBITMAP_TYPE_TIFF, wxBITMAP_TYPE_XPM, wxBITMAP_TYPE_ICO
linea 20: Rescale permette di modificare le dimensioni dell'imagine localmente, cioè viene modificata l'istanza di wxImage della quale è stato richiamato il metodo. Se si vuole modificare le dimensioni dell'immagine senza modificare l'immagine stessa è possibile utilizzare il metodo Scale che ritorna una copia dell'immagine ridimensionata. Gli argomenti accettati da Scale e Rescale sono la nuova larghezza e la nuova altezza
Offre le stesse capacità di caricamento e salvataggio di wxImage ma aggiunge il supporto per alcuni file; per il caricamento sono accettati (oltre a quelli validi per wxImage) i valori wxBITMAP_TYPE_XBM e (solo su windows) wxBITMAP_TYPE_RESOURCE, wxBITMAP_TYPE_BMP_RESOURCE; questi ultimi due vengono usati per caricare immagini da file eseguibili (tipicamente .exe o .dll), probabilmente non vi serviranno se non in rari casi. Per il salvataggio invece sono supportati anche wxBITMAP_TYPE_BMP, wxBITMAP_TYPE_GIF (MA NE SIAMO PROPRIO SICURI?) e wxBITMAP_TYPE_XBM. wxBitmap però non supporta le utili operazioni che possono essere eseguite con wxImage (come modificare le dimensioni dell'immagine) ma si dimostra particolarmente utile in congiunzione con i wxDC (di cui si parlerà più avanti) per cui sarà ad esempio possibile disegnare immagini sulle finestre o su altre immagini. Non sempre è comunque necessario creare una wxBitmap da un file già esistente, ad esempio si può avere l'esigenza di creare semplicemente una wxBitmap vuota, per questo esiste wxEmptyBitmap che accetta come argomenti la larghezza in pixel dell'immagine, la larghezza e infine un argomento opzionale che indica la profondità dell'immagine. Bisogna però ricordarsi che se viene creata un'immagine vuota questa conterrà dati "casuali", potrebbe essere tutta nera, contenere pixel di colori casuali o anche contenere parti di immagini usate precedentemente in altre parti del programma in modo imprevedibile.
Durante le operazioni di disegno un'esigenza frequente è quella di disegnare solo una parte non rettangolare di immagine lasciando le altri parti trasparenti, questo effetto può essere raggiunto facilmente in wxPython usando la classe wxMask. Vi sono due possibili costrottori:
wxMask: accetta come unico parametro un'istanza di wxBitmap contenente l'immagine da usare come maschera, l'immagine deve essere monocromatica, le parti trasparenti sono nere, quelle non trasparenti bianche
wxMaskColour: accetta due argomenti il primo è un'istanza di wxBitmap, il secondo un'istanza di wxColour; serve a costruire una maschera delle dimensioni della bitmap passata come primo argomento in cui le parti trasparenti sono quelle il cui colore corrisponde al secondo argomento.
I font sono un'entità di cui probabilmente qualunque utente di computer ha già conoscenza, i font vengono rappresentati in wxPython dalla classe wxFont. Il metodo più importante di wxFont è il costruttore che accetta i seguenti paramentri:
pointSize: la dimensione in punti (un punto è circa 0.35 mm) del font
family: la famiglia a cui appartiene il font, è un modo di indicare l'aspetto di un font senza specificare di che font si tratta. Può essere:
wxDEFAULT: il font viene scelto automaticamente
wxDECORATIVE: font decorativo (ad esempio Old English)
wxROMAN: font a dimensione variabile con serif (ad esempio MS Serif)
wxSCRIPT: font simili alla scrittura a mano (ad esempio Script)
wxSWISS: font a larghezza variabile senza serif (ad esempio MS Sans Serif)
wxMODERN: font a larghezza fissa con o senza serif (ad esempio Courier New)
style: stile del testo, può essere wxNORMAL, wxSLANT (inclinato) o wxITALIC (corsivo)
weight: spessore del testo, può essere wxNORMAL, wxBOLD (grassetto) o wxLIGHT (sottile, non sempre disponibile)
underline: sottolineato, può essere 1 (il testo è sottolineato) o 0 (non sottolineato); è disponibile solo su Windows. Il valore di default è non sottolineato
faceName: nome del font, può essere un qualunque font installato sul sistema, il valore di deault è una stringa vuota, in questo caso il font viene scelto automaticamente da wxPython in base a family. È importante ricordare che il font deve essere installato sul PC, quindi generalmente è meglio non specificare il nome del font e laciare al sistema operativo la scelta del font migliore
encoding: codifica usata dal font, questo parametro è raramente usato e si può quindi generalmente ignorare. Il valore di default fa in modo che sia scelta la codifica di default di sistema
I singoli colori sono rappresentati in wxPython dalla classe wxColour di cui può essere creata un'istanza in diversi modi, i due principali sono attraverso:
wxColour: accetta tre argomenti interi compresi fra 0 e 255 che identificano le singole componenti del colore (rosso, verde e blu), con la combinazione di questi si possono esprimere tutti i colori
wxNamedColour: accetta solo un argomento contenente una stringa in inglese che specifica il colore, i valori possibili sono molti e quindi non saranno elencati qui, si può trovare l'elenco completo nel demo di wxPython selezionando nel controllo ad albero "wxPython Library" e poi "ColourDB"
Prima di parlare di come disegnare sulle finestre è necessario introdurre due oggetti fondamentali wxPen e wxBrush. Le wxPen sono usate per disegnare linee o bordi di figure geometriche, le caratteristiche principali delle penne sono il colore, la larghezza e lo stile; Questi parametri vengono impostati durante la creazione dell'istanza di wxPen (o rispettivamente attraverso i metodi SetColour, SetWidth e SetStyle). Gli argomenti del costruttore sono:
colour: un'istanza di wxColour, specifica il colore della penna; può anche essere una stringa che identifica il colore (vedi la sezione precedente)
width: larghezza in pixel della penna
style: stile della penna, i valori possibili sono numerosi, i principali sono: wxSOLID (normale senza interruzioni), wxTRANSPARENT (non viene usata nessuna penna), wxDOT (punti), wxLONG_DASH (trattini lunghi), wxSHORT_DASH (trattini corti), wxDOT_DASH (punti alternati a trattini). Alcuni stili possono non avere effetto in Windows se la larghezza della penna è maggiore di 1.
Per comodità sono già costruite alcune penne di larghezza 1 con stile wxSOLID dei principali colori; queste sono: wxRED_PEN, wxCYAN_PEN, wxGREEN_PEN, wxBLACK_PEN, wxWHITE_PEN, wxTRANSPARENT_PEN, wxBLACK_DASHED_PEN, wxGREY_PEN, wxMEDIUM_GREY_PEN, wxLIGHT_GREY_PEN. I wxBrush sono usati per il riempimento di figure geometriche. Le caratteristiche principali dei pennelli sono colore e stile, passati al costruttore o impostati rispettivamente con i metodi SetColour e SetStyle. Gli argomenti del costruttore sono quindi:
colour: un'istanza di wxColour o una stringa che identifica il colore
style: stile del penello, gli stili principali sono wxTRANSPARENT (nessun riempimento) e wxSOLID (riempimento uniforme)
Come per wxPen esistono già delle istanze predefinite di wxBrush che corrispondono a pennelli con riempimento uniforme nei colori principali: wxBLUE_BRUSH, wxGREEN_BRUSH, wxWHITE_BRUSH, wxBLACK_BRUSH, wxGREY_BRUSH, wxMEDIUM_GREY_BRUSH, wxLIGHT_GREY_BRUSH, wxTRANSPARENT_BRUSH, wxCYAN_BRUSH, wxRED_BRUSH.
Un wxDC è un "device context" cioè un oggetto su cui si possono disegnare immagini, testo o figure geometriche. wxDC è un'astrazione che può rappresentare molti dispositivi di output (uno schermo o la stampante ad esempio) permettendo così di usare lo stesso codice in più situazioni. Per permettere ciò ci sono più classi derivate da wxDC che aggiungono i pochi metodi necessari in quel contesto, le principali sono:
wxClientDC: solo l'area client, cioè sono esclusi i bordi
wxWindowDC: tutta l'area della finestra, compresi bordi e barra del titolo. Disponibile solo su Windows
I disegni fatti su una finestra vengono però cancellati se la finestra viene nascosta per cui c'è la necessità di ridisegnare le parti cancellate. Per questo si può usare l'event handler EVT_PAINT che richiama una funzione scelta dall'utente quando serve, in questo caso è però consigliato usare wxPaintDC invece di wxClientDC, in questo modo le operazioni di disegno possono essere accelerate perché viene permesso il disegno solo nelle parti che ne hanno realmente bisogno. Per eseguire le operazioni di disegno è necessario specificare le coordinate in cui esse avvengono, queste cordinate normalmente hanno valore 0, 0 nell'angolo superiore sinistro del wxDC, l'asse delle ascisse è orientato verso destra (cioè muovendosi verso destra il valore della coordinata orizzontale aumenta) mentre quelle delle ordinate è orientato verso il basso (cioè muovendosi verso il basso il valore della coordinata verticale aumenta).
01: class MiaDialog(wxDialog):
02: def __init__(self):
03: wxDialog.__init__(self, None, -1, "Prova di disegno",
04: size=(400, 200))
05: wxInitAllImageHandlers()
06: EVT_PAINT(self, self.OnPaint)
07: # Carica "immagine.bmp" in memoria.
08: self.bmp = wxBitmap("immagine.bmp", wxBITMAP_TYPE_BMP)
09: # Viene creata una maschera per l'immagine appena caricata.
10: mask = wxMaskColour(self.bmp, "magenta")
11: # La maschera viene associata all'immagine.
12: self.bmp.SetMask(mask)
13:
14: def OnPaint(self, event):
15: # Crea il DC e lo prepara per il disegno.
16: dc = wxPaintDC(self)
17: dc.BeginDrawing()
18: # Disegna un rettangolo verde con bordo giallo.
19: penna_gialla_spessa = wxPen("yellow", 5, wxSOLID)
20: dc.SetPen(penna_gialla_spessa)
21: dc.SetBrush(wxGREEN_BRUSH)
22: dc.DrawRectangle(5, 5, 100, 100)
23: # Disegna una linea molto larga.
24: penna_molto_spessa = wxPen(wxColour(180, 27, 93), 18, wxNORMAL)
25: dc.SetPen(penna_molto_spessa)
26: dc.DrawLine(50, 50, 200, 90)
27: # Disegna un'immagine con una maschera trasparente.
28: dc.DrawBitmap(self.bmp, 10, 20, 1)
29: # Disegna un'immagine senza la maschera trasparente.
30: dc.DrawBitmap(self.bmp, 250, 80)
31: # Scrive "Hello world" con un carattere grande, in corsivo
32: # e grassetto, sottolineato (solo su Windows) e di tipo
33: # decorativo.
34: font_grande = wxFont(20, wxDECORATIVE, wxITALIC, wxBOLD, 1)
35: dc.SetFont(font_grande)
36: dc.DrawText("Hello world", 120, 0)
37: # Scrive "Hello world" con un carattere piccolo, con
38: # larghezza fissa, di colore rosso e sfondo nero.
39: font_piccolo = wxFont(10, wxMODERN, wxNORMAL, wxNORMAL)
40: dc.SetBackgroundMode(wxSOLID)
41: dc.SetTextBackground(wxBLACK)
42: dc.SetTextForeground(wxRED)
43: dc.SetFont(font_piccolo)
44: dc.DrawText("Hello world", 10, 120)
45: # Finisce le operazioni di disegno.
46: dc.EndDrawing()
linea 6: quando è necessario ridisegnare la finestra viene chiamata la funzione passata come secondo argomento a EVT_PAINT
linea 16: viene creato il dc, poiché siamo nella funzione che gestisce l'evento OnPaint utilizziamo un wxPaintDC, l'unico argomento accettato dal costruttore della classe è la finestra che deve essere ridisegnata
linea 17, linea 46: è necessario che il codice di disegno sia racchiuso fra BeginDrawing e EndDrawing, questo permette alcune ottimizzazioni su Windows e in certi casi è indispensabile
linea 19, linea 24: crea una penna come spiegato nella sezione precedente, nel primo caso il colore viene specificato con una stringa, nel secondo viene passata un'istanza di wxColour creata passando tre valori che indicano rispettivamente i valori di rosso, verde e blu
linea 20, linea 25: la penna creata viene impostata con il metodo SetPen. Fino a quando non viene impostata una nuova penna verrà usata questa per ogni operazione di disegno
linea 21: viene impostato il pennello con SetBrush, verrà usato come riempimento dopo le operazioni di disegno fino a quando non si imposta un altro pennello
linea 22: con DrawRectangle viene disegnato un rettangolo, i primi due argomenti sono rispettivamente la posizione orizzontale e verticale dell'angolo superiore sinistro, gli ultimi due sono invece relativi alla posizione dell'angolo inferiore destro. Esistono altre funzioni simili per disegnare altre figure geometriche (ad esempio DrawRoundedRectangle e DrawEllipse)
linea 26: disegna una linea con la penna corrente nel wxDC, il significato degli argomenti è lo stesso di DrawRectangle
linea 28, linea 30: DrawBitmap disegna una wxBitmap sul dc, gli argomenti accettati dalla funzione sono quattro. Il primo argomento è l'istanza di wxBitmap che deve essere disegnta. Il secondo e il terzo argomento sono la posizione orizzontale e verticale in cui disegnare l'immagine. Il quarto parametro può essere 1 o 0, nel primo caso viene usata la maschera impostata nella bitmap per disegnare le trasparenze; se viene specificato 0 (il valore di default) non vengono disegnate le trasperenze. Se la bitmap non ha nessuna maschera impostata l'ultimo parametro viene ignorato
linea 34, : vengono creati i font come spiegato in precedenza
linea 35, : la funzione SetFont imposta il wxFont creato in precedenza e passato come unico argomento alla funzione come font di default usato per tutte le successive operazioni sul wxDC fino a quando non viene impostato un nuovo font
linea 36, linea 44: il testo può essere scritto sul dc con il metodo DrawText, gli argomenti sono il testo scritto sul wxDC, e due argomenti che indicano rispettivamente la posizione orizzontale e verticale in cui iniziare a scrivere il testo
linea 40: quando viene disegnato del testo in un wxDC può venir disegnato anche un rettangolo che circonda la scritta. Se si desidera che venga disegnato il rettangolo è necessario utilizzare il metodo di wxDC SetBackgroundMode passandogli come argomento wxSOLID, se invece si vuole non disegnare il rettangolo (condizione di default se prima non è stato importato wxSOLID) si deve passare come argomento wxTRANSPARENT
linea 41: imposta il colore di sfondo usato quando si scrive del testo su un wxDC, il rettangolo è visibile solo se è impostato wxSOLID con SetBackgroundMode
linea 42: SetTextForeground imposta il colore delle scritte
immagine 9.1
Un metodo sicuramente molto utile e frequentemente usato dei wxDC (specialmente con i wxMemoryDC) è Blit, questa funzione permette di copiare parte di un wxDC su un altro wxDC, accetta i seguenti 11 argomenti:
xdest, ydest: posizione orizzontale e verticale espressa in pixel dell'angolo in alto a sinistra della regione in cui sarà copiato il wxDC source
width, height: larghezza ed altezza del rettangolo da copiare da source
source: istanza di wxDC che deve essere copiata
xsrc, ysrc: posizione orizzontale e verticale da cui copiare l'immagine
logicalFunc: modo in cui l'immagine viene copiata sulla destinazione, il valore di default è wxCOPY che semplicemente copia il rettangolo specificato dal wxDC sorgeente a quello di destinazione. L'elenco completo dei possibili valori può essere trovato nella guida di wxWindows e degli esempi di come utilizzarlo nel demo di wxPython selezionando "Miscellaneous" e poi "wxMask"
useMask: se 0 non viene impostata nessuna trasparenza, se 1 viene usata la trasparenza della bitmap selezionata nel wxDC di origine (vedi wxMask e wxMemoryDC), il valore di default è 0
xsrcMask, ysrcMask: posizione orizzontale e verticale della maschera del wxDC source, il valore di defualt è -1 che significa che verranno usate xsrc e xdest. Implementato solo sotto Windows
Spesso si ha la necessità di disegnare immagini senza farlo su una finestra, per questo si può usare la classe wxMemoryDC. Poiché wxMemoryDC è derivata da wxDC si hanno a disposizione tutti i metodi già esposti nella sezione precedente. Il costruttore non accetta parametri e crea un'immagine bianca e nera 1 per 1, è quindi necessario selezionare una wxBitmap nel DC con il metodo SelectObject che accetta come solo argomento un'istanza di wxBitmap. Dopo che una bitmap è stata selezionata in un DC tutte le operazioni di disegno la modificheranno. Un motivo tipico in cui serve usare un wxMemoryDC è quando si devono eseguire delle operazioni di disegno lunghe e in cui vi sono elementi che si sovrappongono, in questo caso disegnando direttamente sullo schermo l'utente può vedere dei flash. Nell'esempio seguente si può vedere questo effetto e come evitarlo usando un wxMemoryDC.
01: class MiaDialog(wxDialog):
02: def __init__(self):
03: wxDialog.__init__(self, None, -1,
04: "Prova di disegno con wxMemoryDC",
05: size=(350, 250))
06: # E` possibile scegliere se usare un wxMemoryDC o no.
07: self.radio_box =wxRadioBox(self, -1, "Usare un wxMemoryDC?",
08: (10, 160), (150, 40),
09: choices=["No", "Sì"])
10: # Il pulsante permette di ridisegnare la finestra.
11: BTN_ID = wxNewId()
12: btn = wxButton(self, BTN_ID, "Ridisegna",
13: (170, 160), (-1, 40))
14: EVT_BUTTON(self, BTN_ID, self.OnButtonDown)
15:
16: def OnButtonDown(self, event):
17: # Il pulsante è stato premuto, ridisegna la
18: # finestra, se è selezionato "No" viene ritornato 0
19: # da GetSelection perché "No" è il primo controllo,
20: # altrimenti viene ritornato "1" perché il radiobutton
21: # "Sì" è il secondo pulsante del radiobox. (?)
22: usa_memory_dc = self.radio_box.GetSelection()
23: self.Ridisegna(usa_memory_dc)
24:
25: def Ridisegna(self, usa_memory_dc):
26: # Crea un wxClientDC ed inizia le operazioni di disegno.
27: client_dc = wxClientDC(self)
28: client_dc.BeginDrawing()
29: # Larghezza ed altezza del rettangolo in cui avvengono le
30: # operazioni di disegno.
31: larghezza = 300
32: altezza = 150
33: # Le operazioni di disegno avvengono su dest_dc che si
34: # riferisce a diversi wxDC in base a usa_memory_dc
35: if usa_memory_dc:
36: # Se usa_memory_dc è 1 allora dest_dc è un wxMemoryDC.
37: dest_dc = wxMemoryDC()
38: # Viene creata una bitmap che viene poi selezionata
39: # nel wxMemoryDC.
40: bmp = wxEmptyBitmap(larghezza, altezza)
41: dest_dc.SelectObject(bmp)
42: dest_dc.BeginDrawing()
43: else:
44: # Se usa_memory_dc è 0 allora viene usato client_dc.
45: dest_dc = client_dc
46: # Lista dei possibili colori fra cui scegliere per
47: # disegnare i cerchi.
48: lista_colori = ("BLUE",
49: "BLUE VIOLET",
50: "BROWN",
51: "CYAN",
52: "DARK GREY",
53: "DARK GREEN",
54: "GOLD",
55: "GREY",
56: "GREEN",
57: "MAGENTA",
58: "NAVY",
59: "PINK",
60: "RED",
61: "SKY BLUE",
62: "VIOLET",
63: "YELLOW",
64: "PALE GREEN")
65: # Disegna 1000 cerchi di colore, dimensione e posizione casuale
66: for i in range(1000):
67: # Il colore è estratto fra la lista dei possibili colori,
68: # random.randrange(min, max) ritorna un numero casuale
69: # compreso fra min e max.
70: n_colore = random.randrange(0, len(lista_colori))
71: colore = lista_colori[n_colore]
72: # Vengono creati e selezionati nel wxDC i pennelli e le penne
73: # di colore casuale.
74: penna = wxPen(colore, 1, wxSOLID)
75: dest_dc.SetPen(penna)
76: pennello = wxBrush(colore, wxSOLID)
77: dest_dc.SetBrush(pennello)
78: # Diametro del cerchio.
79: dim = random.randrange(5, 30)
80: # Posizione in cui disegnare il cerchio, viene usato
81: # "- dim" perxhé altrimenti le operazioni di disegno
82: # potrebbero avvenire fuori dal rettangolo scelto.
83: pos_x = random.randrange(0, larghezza - dim)
84: pos_y = random.randrange(0, altezza - dim)
85: # Disegna il cerchio.
86: dest_dc.DrawEllipse(pos_x, pos_y, dim, dim)
87: if usa_memory_dc:
88: # I 500 cerchi sono stati disegnati sul wxMemporyDC,
89: # adesso devono essere ricopiati su client_dc.
90: client_dc.Blit(0, 0, larghezza, altezza, dest_dc, 0, 0)
91: dest_dc.EndDrawing()
92: client_dc.EndDrawing()
Il risultato finale del codice è, come si può vedere dall'immagine seguente, identico nei due casi eccetto che per lo sfondo del rettangolo in cui sono avvenute le operazioni di disegno, infatti usando direttamente il wxClientDC il disegno avviene subito sulla finestra, invece usando il wxMemoryDC le operazioni avvengono in memoria e poi viene ricopiato il disegno sulla finestra. Potete evitare questo problema in diversi modi, ad esempio se il wxMemoryDC viene ricopiato su una finestra uniforme potete selezionare nel wxMemoryDC un wxBrush del colore della finestra e poi richiamare il metodo Clear che ricopre il wxDC con il pennello impostato per lo sfondo.