2010-02-16 8 views
6

Sto provando a eseguire il rendering di un componente Swing personalizzato in cui ho esteso la classe JComponent.Quando getGraphics() restituisce un'istanza grafica valida?

Allo scopo di semplificare i requisiti del componente, è sufficiente riepilogare il mio componente come se fosse necessario eseguire il rendering di alcune stringhe, ciascuna con i propri font.

Ho bisogno che il mio componente venga ridimensionato esattamente alla larghezza e all'altezza delle stringhe renderizzate.

Per determinare questa dimensione, utilizzo FontMetrics per calcolare le dimensioni di ciascuna stringa. Avendo questa informazione posso capire quale dimensione sarà il mio componente e ridimensionarlo in modo appropriato.

Il problema è che quando accedo a getGraphics() è sempre nullo, quindi non riesco ad ottenere l'istanza FontMetrics. Se aspetto di calcolare la dimensione del mio componente dal metodo overriden paintComponent(), è troppo tardi (il componente ha già una dimensione, giusto?).

La documentazione dice che "Questo metodo restituirà null se questo componente non è attualmente visualizzabile". Quindi, quando so quando il componente è pronto per essere visualizzato e ha un oggetto Graphics per ridimensionare il mio componente?

Qual è l'ordine di invocazione di Swing per il rendering del componente quando viene chiamato il frame setVisible (true)?

Grazie


Aggiornamento: Martedì, 06 Febbraio, 2010 alle 23:34

Come accennato soffietto nei commenti, il GridLayout non rispetta alcun setXxxSize() a tutti. Per chiunque sia interessato, ho pubblicato i risultati dell'utilizzo di GridLayout, BoxLayout e FlowLayout utilizzando un semplice frame che riceve 5 componenti di dimensione fissa di 200 di larghezza per 50 di altezza (impostando min, max e preferito).

risultati dei test:

Il GridLayout è sempre ridimensionate lungo la larghezza e l'altezza (come detto nei commenti)

Il FlowLayout sempre rispettato i componenti tg a prescindere.

quanto riguarda la della BoxLayout ...

Il PAGE_AXIS e Y_AXIS ristretto la larghezza dei componenti per circa metà della loro dimensione (104), ma non ridurre l'altezza.

Il LINE_AXIS e X_AXIS si è ridotto l'altezza dei componenti di quello che sembrava zero, ma non ha toccato la larghezza.

risposta

7

Innanzitutto, è possibile misurare le stringhe utilizzando la classe TextLayout e le relative risorse.Per esempio

public static void main(final String[] args) throws Exception 
{ 
    final FontRenderContext frc = new FontRenderContext(null, true, true); 
    final Font font = new Font("serif", Font.PLAIN, 18); 
    final TextLayout layout = new TextLayout("This is a test", font, frc); 
    final Rectangle2D bounds = layout.getBounds(); 
    System.err.println((int) (bounds.getWidth() + .5)); 
} 

In secondo luogo, è possibile essere informati quando il componente è diventato visibile utilizzando un ComponentListener, ma non è necessaria per misurare le stringhe in "anticipo"!

+0

Vedo che stai creando il tuo font? Quando ho provato getFont(), il carattere è nullo. Suppongo che un JComponent non abbia un carattere predefinito? – Jeach

+0

Un componente il cui font non è impostato in modo esplicito utilizza il font del genitore. Se non hai un genitore, non hai font. Faresti meglio a impostare esplicitamente il tuo font nel tuo costruttore. –

+0

Grazie Jonathan! L'impostazione del font è ciò che ho iniziato a fare. Posso rendere il componente correttamente ora in questo modo, ma per qualche motivo questo componente si rifiuta ancora di ridimensionare le mie dimensioni. Se creo un frame con un layout di griglia (0 righe, 1 colonna) e aggiungo 10 dei miei componenti, quindi rendere il frame a schermo intero. Ogni oggetto ottiene 1/10 dell'altezza dello schermo in altezza quando non dovrebbero essere molto più piccoli. Ho impostato il minimo, il massimo, il preferito, setSize() e ancora in qualche modo rende a proprio piacimento !! – Jeach

2

Utilizzare una JLabel per il rendering delle stringhe, quindi è sufficiente utilizzare il metodo getPreferredSize() dell'etichetta.

+0

Credo che mi aspettassi che qualcuno mi dicesse di usare i componenti Swing esistenti per fare questo . I miei requisiti sono di rimuovere gran parte del bloat esistente da questo componente e renderlo direttamente me stesso. Utilizzava etichette e icone all'interno di pannelli e all'interno di più pannelli con layout, ecc. Immagino che sia stato creato con uno strumento automatico. Ora deve andare a dieta mi è stato detto! – Jeach

+0

A pensarci bene, gli eventi di JLabel sono problematici perché come accennato nel mio commento sopra a Jonathan, l'etichetta dovrebbe rimanere ad un'altezza fissa non molto più grande della dimensione del carattere. JLabel ha la tendenza a fare esattamente ciò che il mio componente sta facendo ... allungare! – Jeach

+0

Come accennato da Jonathan, questo è un problema di layout, non un calcolo della "dimensione preferita". Se vuoi ancora utilizzare GridLayout per il tuo pannello, un altro approccio consiste nel creare un pannello genitore con BorderLayout. Aggiungi il tuo pannello con GridLayout al NORD del pannello genitore. Ora tutto lo spazio extra verrà assegnato al centro e il pannello verrà visualizzato alla sua dimensione preferita. – camickr

Problemi correlati