View Full Version : [Java Swing] Canvas dentro JSplitPane
Salve a tutti, ho di nuovo un problema di interoperabilitá tra componenti AWT e Swing: ho inserito un JSplitPane (che splitta verticalmente) in un JFrame e ci ho messo dentro un Canvas AWT e una JTextArea, il primo sopra e la seconda sotto; il problema é che il Canvas si rifiuta di rimpicciolirsi: l'utente non riesce ad alzare lo splitter ma solo ad abbassarlo, ne' riesce a rimpicciolire tutto il JFrame perché questo provocherebbe un rimpicciolimento del Canvas :mbe:
naturalmente se invece del Canvas inserisco un JPanel funziona tutto regolarmente.
qualcuno saprebbe dirmi se c'é modo di correggere anche questa cosa? ^^
di nuovo grazie!
ho dimenticato un dettaglio fondamentale: in fase di costruzione della GUI io ho chiamato Canvas.setPreferredSize per far si' che la chiamata pack() finale effettuata sul JFrame non mi riduca il Canvas al minimo. in altre parole io vorrei che all'avvio dell'applicazione il Canvas avesse una certa dimensione, ma anche che l'utente sia in grado di alzare lo splitter e di rimpicciolire il JFrame.
ari-grazie.
^TiGeRShArK^
28-10-2009, 07:55
guarda, se non ricordo male era sconsigliato dalla sun stessa utilizzare componenti awt e swing insieme...
E tra l'altro ormai si dovrebbe usare solo swing.
come mai hai questa necessità? :fagiano:
perché in realtá non si tratta propriamente di un Canvas ma di un GLCanvas di JOGL (che eredita Canvas). so che in JOGL esiste anche GLJPanel, ma questo invece é sconsigliato dal team di JOGL perché é meno performante :fagiano:
e quindi se possibile volevo realizzare la mia GUI col GLCanvas. questo dovrebbe essere l'ultimo problema rimasto: oltre a questo avevo avuto solamente il problema relativo al fatto che il Canvas é heavyweight e nascondeva i menu.
banryu79
28-10-2009, 09:04
perché in realtá non si tratta propriamente di un Canvas ma di un GLCanvas di JOGL (che eredita Canvas). so che in JOGL esiste anche GLJPanel, ma questo invece é sconsigliato dal team di JOGL perché é meno performante :fagiano:
Ciao,
sicuro-sicuro sche sia ancora sconsigliato?
Te lo chiedo perchè anni fa per realizzare un visualizzatore per modelli 3D per un software CAM abbiamo avuto la stessa neccessità per motivi di performance.
In seguito poi, quando le JOGL sono diventate "più mature" anche in parallelo a miglioramenti lato Swing, siamo potuti passare alla versione con JPanel senza perdite di performance (ovvio che poi dipende da cosa devi renderizzare).
Quindi fossi in te/voi proverei prima con il GLJPanel, e poi, solo dopo aver riscontrato effettiva perdita di performance (e aver verificato con un profiler quale è l'effettivo collo di bottiglia, altra lezione imparata sulla mia pelle) come sicuramente imputabile al GLJPanel lo sostituite con GLCanvas.
In questo secondo caso dovrete escogitare una qualche strategia per integrarlo nella UI minimizzando i problemi di interoperabilità che avvengono quando si mescolano componenti Swing con componenti AWT (maggiori informazioni in tal senso le trovi spluciando sul sito della Sun, altrimenti, se ti servissero me lo dici via pvt che ti scrivo quache indicazione di massima).
Ciao,
sicuro-sicuro sche sia ancora sconsigliato? leggendo le guide varie vedo che ora la situazione é migliorata, ma le performances non sono ancora comparabili. il motivo é che JPanel (da cui eredita GLJPanel) é un componente lightweight e come tale non ha una finestra nativa (tipicamente in ambiente nativo per fare rendering con OpenGL serve una finestra nativa dedicata sulla quale si possa fare solo quello e non si possa renderizzare nient'altro), e se a questo aggiungi che un JPanel debba opzionalmente anche poter essere reso parzialmente trasparente la soluzione piu ragionevole per il team di JOGL é stata che quando disegni su un GLJPanel non disegni direttamente su schermo, ma viene prelevato il contenuto del frame buffer con glReadPixels o analoga e tale contenuto viene poi renderizzato sul GLJPanel con le eventuali semitrasparenze. questa soluzione, ragionevolissima, é inerentemente meno performante del funzionamento di un Canvas, per quanto si possa ottimizzare.
Quindi fossi in te/voi proverei prima con il GLJPanel, e poi, solo dopo aver riscontrato effettiva perdita di performance (e aver verificato con un profiler quale è l'effettivo collo di bottiglia, altra lezione imparata sulla mia pelle) come sicuramente imputabile al GLJPanel lo sostituite con GLCanvas. si, questo é giustissimo: in generale il programmatore non dovrebbe mai cercare di ottimizzare senza aver prima consultato il profiler. peró se mi dicono che giá in linea di principio é meglio usare GLCanvas e io al momento non ho preferenze non vedo perché fare diversamente. poi le preferenze mi sono arrivate assieme ai problemi di interoperabilitá AWT/Swing :D peró diamine, ho fatto 30 e il non poter fare 31 e dover refattorizzare un quintale di codice cristallino e perfettamente funzionante per un problema di GUI cosi idiota é piuttosto frustrante, mi secca assai :stordita:
specialmente dopo essere stato incoraggiato dall'incredibile semplicitá con cui mi hai fatto risolvere il problema dei menu che erano nascosti dal Canvas :D
In questo secondo caso dovrete escogitare una qualche strategia per integrarlo nella UI minimizzando i problemi di interoperabilità che avvengono quando si mescolano componenti Swing con componenti AWT (maggiori informazioni in tal senso le trovi spluciando sul sito della Sun, altrimenti, se ti servissero me lo dici via pvt che ti scrivo quache indicazione di massima). perché in pvt? penso che sia di interesse generalissimo.
per i motivi di cui sopra mi interesserebbe molto leggere qualcuna di queste strategie :stordita:
banryu79
29-10-2009, 09:54
perché in pvt? penso che sia di interesse generalissimo.
per i motivi di cui sopra mi interesserebbe molto leggere qualcuna di queste strategie :stordita:
D'accordo allora.
In pvt era perchè mi sarei trovato agevolato a scambiare con te del codice senza troppi patemi.
Comunque, a prescindere da queste considerazioni, vorrei che facessimo un passo indietro, se per te va bene.
Ho cercato di ricostruire la situazione che hai descritto: frame contentente uno JSplitPane che splitta verticalmente due componenti, uno AWT e uno Swing.
Ho di proposito "ignorato" che il componete AWT è un GLCanvas.
Ho usato invece un java.awt.Panel.
Ho anche aggiunto un menu, per far vedere, aprendolo, che il componente posizionato più in alto è efettivamente un componente AWT, con tutte le conseguenze del caso.
Ecco il codice:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Label;
import java.awt.Panel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
/**
* @author francesco
*/
public class SplitAWTComponent extends JFrame
{
public static void main(String... args) {
SplitAWTComponent frame = new SplitAWTComponent("Splitting Swing and AWT components");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(500, 400);
frame.setVisible(true);
}
public SplitAWTComponent(String title) {
super(title);
initialize();
}
private void initialize() {
// add a menu to the frame
JMenuBar menu = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem fileItem1 = new JMenuItem("Item1");
JMenuItem fileItem2 = new JMenuItem("Item2");
fileMenu.add(fileItem1);
fileMenu.add(fileItem2);
menu.add(fileMenu);
this.setJMenuBar(menu);
// create red AWT Panel
Panel awtPanel = new Panel();
Label awtlabel = new Label("Questo è un java.awt.Panel");
awtPanel.add(awtlabel);
awtPanel.setBackground(Color.red.darker());
awtPanel.setMinimumSize(new Dimension(0,0));
// create blue Swing JPanel
JPanel swingPanel = new JPanel();
JLabel swinglabel = new JLabel("Questo è un javax.swing.JPanel");
swingPanel.add(swinglabel);
swingPanel.setBackground(Color.blue);
swingPanel.setMinimumSize(new Dimension(0,0));
// create vertical JSplitter for red and blue panels
JSplitPane splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT, awtPanel, swingPanel);
splitter.setDividerLocation(0.5);
splitter.setContinuousLayout(true);
splitter.setOneTouchExpandable(true);
this.add(splitter, BorderLayout.CENTER);
}
}
Se lo lanci, dovresti riscontrare che i due componenti sono assolutamente ridimensionabili, sia usando lo splitter che ridimensionando il frame in cui sono stati inseriti.
Le cose da notare (in grassetto), sono le seguenti:
1) L'unico componente a cui viene esplicitamente impostata la dimensione (size) è il frame.
2) I pannelli sono inseriti direttamente nel frame, e il layout manager conivolto e' quello di default per JFrame (BorderLayout).
3) Ai pannelli inseriti viene imposta una minimumSize pari a zero: la minimumSize funge da limite per lo splitter, mettendola a zero si dice che si vuole che lo splitter possa estendersi fino a far "sparire"/"coprire completamente" quel componente.
Se invece sostiuissimo il blocco che crea il java.awt.Panel con un Canvas:
...
// create red AWT Canvas
Canvas awtCanvas = new Canvas(){
@Override
public void paint(Graphics g) {
g.setColor(Color.green.darker());
g.drawString("Questo è un javax.awt.Canvas", 15, 20);
}
};
awtCanvas.setBackground(Color.red.darker());
awtCanvas.setMinimumSize(new Dimension(0,0));
...
...
// create vertical JSplitter for red and blue panels
// JSplitPane splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT, awtPanel, swingPanel);
JSplitPane splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT, awtCanvas, swingPanel);
Il comportamento, mi pare, non muti.
Quindi il tuo problema sembra più aver a che fare con il setting delle dimensioni (preferredSize/minimum-maximumSize) e i componenti contenitori (JSplitPane) e i layout manager coinvolti tra loro che altro.
Per le guidelines da seguire quando si integrano tra loro ligthweight e heavyweight components c'era qualcosa sul sito sun.java ora non riesco più a trovarlo ma a casa ho delle informazioni che posso postarti domani.
P.S.: questa volta non ti ho potuto dare una risposta secca perchè la faccenda non è completamente chiara neanche a me, sto ancora studiando le Swing in dettaglio (finalmente con un libro, come si deve) e nell'applicativo CAM di cui sopra il problema era di un altro tipo (la sovvraposizione tra heavyw. e lightw.) ed era stato rimosso in modo semplice & brutale (relegando il viewer 3D in un pannello non ridimensionabile posizionato in alto a destra della finestra, funzionava come una sorta di preview, si poteva poi aprire una finestra dedicata solo per il GLCanvas e pochi altri componenti light affiancati, anche questa non ridimensionabile).
P.P.S.: qui (http://java.sun.com/docs/books/tutorial/uiswing/components/splitpane.html) trovi indicazioni su come usare uno split pane e settare i componenti coinvolti
P.P.P.S.: ho provato pure settando la preferredSize per i due pannelli contenuti e non impostando la size del frame contenitore e invocando un pack(): funziona tutto come ti ho descritto e non riscontro il problema che hai segnalato.
banryu79
29-10-2009, 10:12
Aggiungo una considerazione, a quanto dici qua:
si, questo é giustissimo: in generale il programmatore non dovrebbe mai cercare di ottimizzare senza aver prima consultato il profiler. peró se mi dicono che giá in linea di principio é meglio usare GLCanvas e io al momento non ho preferenze non vedo perché fare diversamente.
Sì vero, ma se consideri che l'unica differenza tra usare un GLJPanel e un GLCanvas sta nella dichiarazione del tipo (cioè fai presto a fare la prova)... Beh, potresti facilmente risolvere le tue "magagne" iniziando ad usare il GLJPanel, ed evitandoti così i problemi.
Se poi, POI, viene riscontrato che le performance di rendering vanno migliorate profili l'esecuzione del rendering per CAPIRE esattamente cosa causa la perdita di performance.
Se si verificasse questo scenario potrebbe anche saltare fuori facilmente che il problema non è l'uso del GLJPanel versus GLCanvas.
Ci sono un sacco di altre cose che posso essere il collo di bottiglia. Il modo in cui è stato implementato il rendering, ad esempio.
GLi oggetti coinvolti. Il tipo di Animator scelto per schedulare il rendering
Io, se fossi al tuo posto, userei fin da subito GLCanvas se e solo se fossi assolutamente sicuro che è strettamente neccessario.
banryu79
30-10-2009, 08:16
Fero, eccoti il link che spiega le 4 regole da tenere presente quando si costruiscono interfacce composte sia da componenti AWT che Swing:
- Mixing heavy and light components (http://java.sun.com./products/jfc/tsc/articles/mixing/index.html)
Dentro c'è un link che punta ad un articolo più recente (2009).
Ancora più importante, fero86, non so se hai mai letto questa pagina (http://download.java.net/media/jogl/doc/userguide/). In particolare guarda il paragrafo sotto il titolo "Heavyweight and Lightweight Issues", sembra che sia *esattamente* quello che vi serve per risolvere le questioni di resize che affliggono il vostro GLCanvas. ;)
In particolare guarda il paragrafo sotto il titolo "Heavyweight and Lightweight Issues", sembra che sia *esattamente* quello che vi serve per risolvere le questioni di resize che affliggono il vostro GLCanvas. ;) tácchete, eccolo lá: il 31 dopo il 30, la soluzione piacevolmente semplice al problema fastidiosissimo, il workaround giá pronto e non troppo brutto, la cosa che diresti che era esattamente quello che cercavi ringraziando sentitamente!! :D
che poi quella pagina me la saró scorsa un sacco di volte in passato, e ora che mi servivano alcune nozioni in essa contenute l'ho lisciata completamente :stordita:
poi quando ho tempo cerco la soluzione migliore e la provo; intanto sentitamente grazie :D
ma il post #8 si é possentemente ingigantito con l'ultimo edit? :|
ora sono di fretta ma quando ci ritorno lo leggo; grazie moltissime per l'interesse!!
ciao :)
banryu79, ho letto il post #8: grazie per l'interesse! :D
se me l'avessi chiesto avrei postato io del codice.
ho consultato la tua ricostruzione e in base a quella ho provato ad aggiungere una chiamata setMinimumSize(new Dimension(0, 0)) sul GLCanvas e ora funziona egregiamente! :)
banryu79
02-11-2009, 08:07
Prego :)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.