2014-09-10 26 views
5

Ho uno TSpeedButton e uno TImageList che contiene vari glifi. Uno di questi ha un canale alfa e sembra molto carino quando viene disegnato su certe parti dell'interfaccia utente ... ma quando questo glifo viene disegnato su un TSpeedButton, non prende il canale alfa in effetto.Come si disegna un'immagine con un canale alfa su un TSpeedButton?

Guardando il codice rilevante in TButtonGlyph.DrawButtonGlyph, è sempre passato true per il parametro Transparent, ma Transparent non viene presa in considerazione a tutti nel percorso if FThemesEnabled di codice; viene referenziato solo nella sezione else. Dal momento che questo programma ha temi abilitati, vuol dire che è impossibile disegnare un'immagine alfa in un TSpeedButton?

C'è un modo per aggirare questo problema?

MODIFICA: Guardando un po 'più da vicino, sembra che tenga conto della trasparenza ... una specie di. I pixel completamente trasparenti non vengono disegnati affatto, il che è un comportamento corretto. Ma l'antialiasing (trasparenza parziale) attorno ai bordi viene disegnato completamente opaco.

+1

Nel caso in cui David Heffernan legge questo: ** non ** chiedere esempi di codice o ti contrassegno. Questa non è una domanda sul mio codice; questa è una domanda sul modo in cui VCL disegna le immagini in un contesto altamente specifico. Grazie. –

+2

'DrawThemeIcon': * Disegna un'immagine da un elenco di immagini con l'effetto dell'icona definito dallo stile visivo. * - Quindi questo è l'effetto dell'icona, qualunque cosa significhi .. –

+0

In realtà, AFAICS, disegna parzialmente trasparenza parziale, ma disegna contro uno sfondo bianco. Forse quel colore dipende dallo stile visivo. –

risposta

4

Da quello che posso vedere, TSpeedButton prende la bitmap e la aggiunge a un elenco di immagini. Quello è FGlyphList nella sezione privata di TButtonGlyph. L'elenco di immagini ha ColorDepth di cdDeviceDependent. Avresti bisogno che quell'elenco di immagini abbia ColorDepth di cd32Bit se vuoi che la trasparenza alfa sia rispettata. In modo che proprio lì spiega gli artefatti.

Non sono sicuro di come si lavora su questo. Penso che personalmente sottoclassi lo TButtonGlyph e lo colleghi direttamente a un elenco di immagini della tua selezione. Quindi sostituire TButtonGlyph.DrawButtonGlyph con il codice che attinge dal tuo elenco di immagini. Sono sicuro che sarai in grado di elaborare la codifica.

Ma non ci sarà una soluzione semplice. Senza modifiche importanti al VCL, quell'elenco di immagini utilizzerà cdDeviceDependent e non c'è un modo semplice per cambiarlo. Non c'è una soluzione rapida ovvia che io possa vedere.

In realtà, quello che farei sarebbe utilizzare TButton, ma quello sono solo io.


Per quanto riguarda la Transparent proprietà del pulsante di velocità documentation dice:

Specifica se lo sfondo del pulsante è trasparente.

Utilizzare Trasparente per specificare se lo sfondo del pulsante è trasparente.

Questa proprietà funziona solo se la proprietà Flat di TSpeedButton è impostata su True.

Quando i temi di Windows sono abilitati, la proprietà Transparent non può rendere trasparente lo sfondo del pulsante.

Vale a dire, la proprietà influenza lo sfondo del pulsante, per i pulsanti piatti, quando non è disponibile, e non ha rilevanza per il disegno del glifo.

+0

Utilizzare semplicemente TButton non è un'opzione; Ho bisogno di un pulsante con uno stato 'Down' che può essere usato come una casella di controllo. Potrei dover guardare componenti di terze parti, se questo è ciò che sta succedendo sotto il cofano. Grazie. –

+0

Si potrebbe semplicemente creare il proprio pulsante usando 'TSpeedButton' come modello. Puoi tagliare un sacco di cruft di cui non hai bisogno. –

0

Nell'interesse di una completa informativa: Mi sono imbattuto in un problema simile e usato questo Q & A di basare la mia soluzione iniziale on. Poiché avevo bisogno di una soluzione rapida per la mia app e compilatore (utilizzo C++ Builder 2009) ho deciso di "hackerare" i membri privati ​​di VCL e impostarea cd32Bit, fino a quando non avevo tempo di lavorare su qualcosa di più permanente. Questo hack ha funzionato, con qualche modifica in più, ma era lontano dallo dall'ideale, per tutte le ovvie ragioni, ma anche per quanto riguarda la funzionalità, c'erano problemi da considerare.

Tuttavia, mentre così facendo ho sperimentato ulteriormente e finalmente sono arrivato al di sotto, soluzione di lavoro, senza sporchi trucchi necessari. Non essendo così familiare con il funzionamento interno di VCL e il "non è possibile come è" il feedback di persone che sono molto più approfondite in VCL, sono un po 'insicuro su ciò che mi manca in questo momento! Perché sotto la soluzione funziona per me. Confermato su XP, XP-Alto contrasto, W7 e W10. I glifi non hanno un bell'aspetto su W2K, ma questo vale anche per le icone del menu principale e dei popup, quindi è così.

Codice I in C++ ma uso lo stesso VCL sottostante, quindi posterò la mia soluzione C++ qui, come risposta a una domanda Delphi. Spero che sia OK, nell'interesse di offrire un percorso verso una soluzione piuttosto che tenerla per me. Un guru di Delphi può convertire e pubblicare come risposta pure, a meno che mi manchi qualcosa e la mia soluzione non è ciò che era necessario da sempre.

Da quando ho iniziato con l'approccio 'hack', ho prima suddiviso TSpeedButton e inserito il codice in una funzione MyTSpeedButton, ma non è necessario per farlo funzionare. Tuttavia, è il codice che sto postando:

intestazione

class MyVCLTSpeedButton : public TSpeedButton 
    { 
    public: 

    __fastcall MyVCLTSpeedButton(Classes::TComponent* AOwner) ; 

    void __fastcall AddGlyphWithAlphaChannel(Imglist::TCustomImageList* ImageList, int UpIndex, int DisabledIndex = -1, int ClickedIndex = -1, int DownIndex = -1) ; 

    }; 

cpp

void __fastcall MyVCLTSpeedButton::AddGlyphWithAlphaChannel(Imglist::TCustomImageList* ImageList, int UpIndex, int DisabledIndex, int ClickedIndex, int DownIndex) 
{ 
Glyph->Assign(NULL) ; // Clear the current bitmap 

NumGlyphs = (DisabledIndex > -1)?((ClickedIndex > -1)?((DownIndex > -1)?(4):(3)):(2)):(1) ; 

Graphics::TBitmap *BitMap = new Graphics::TBitmap ; 

//BitMap->AlphaFormat = afDefined ; // Don't Change AlphaFormat, it will negatively affect rendering ! 
BitMap->PixelFormat = pf32bit ; // Doesn't seem to be that important 
BitMap->Height = ImageList->Height ; 
BitMap->Width = (ImageList->Width * NumGlyphs) ; 

BitMap->Canvas->Brush->Color = Parent->Brush->Color ; 
BitMap->Canvas->Brush->Style = bsSolid ; 
BitMap->Canvas->FillRect(BitMap->Canvas->ClipRect) ; 

TIcon *Icon = new TIcon() ; 

for (int x = 0 ; x < NumGlyphs ; x++) 
    { 
    ImageList->GetIcon((x == 0)?(UpIndex):((x == 1)?(DisabledIndex):((x == 2)?(ClickedIndex):(DownIndex))), Icon) ; 
    BitMap->Canvas->Draw((ImageList->Width * x), 0, Icon) ; 
    } 

Glyph->Assign(BitMap) ; 

delete Icon ; 
delete BitMap ; 
}