Perché il nuovo componente viene visualizzato in un gestore di layout nulla?
-
02-10-2019 - |
Domanda
C'è un pannello in una JFrame
chiamato WatchPanel extends JPanel
che utilizza un GroupLayout
e contiene una WatchListPanel extends JPanel
. Il WatchListPanel
utilizza un null
LayoutManager
e contiene diverse istanze di WatchItemPanel extends JPanel
. Il WatchItemPanel
delinea il contenuto con un GridBagLayout
.
Quando carico il telaio e istanziare il WatchPanel
, ho pre-caricare la WatchListPanel
con tre istanze WatchItemPanel
con dati. Questi funzionano bene. Mia implementazione consente questi per essere riordinati trascinando (da qui il layout null
), e che funziona pure. Sul WatchPanel
è un pulsante per aggiungere un nuovo orologio, che si apre un nuovo pannello nel proprio JFrame
cui un orologio può essere aggiunto. Quando si preme il pulsante "Salva" su questo nuovo pannello, si aggiunge il nuovo orologio al WatchPanel
, che gocciola giù nella WatchListPanel
e chiude il JFrame
per l'aggiunta di un nuovo orologio.
Il problema è che quando si aggiunge questo nuovo WatchItemPanel
, non ottiene dipinta a meno a ridimensionare il JFrame
che contiene il WatchPanel
. Riesco a comunicare con esso tramite drag-n-drop. Posso anche trascinare quel pannello specifico - ma è vuota. Nel momento in cui ridimensionare il WatchPanel
, appare ed è dipinto in modo corretto.
Ora, ho ignorato il metodo setBounds
su WatchListPanel
alla chiamata setSize
e repaint
su ciascuna delle istanze WatchItemPanel
nella lista, ma sto chiamando setBounds
e repaint
sul nuovo WatchItemPanel
già come lo aggiungo. Ho provato ad aggiungere le chiamate repaint
e invalidate
in ogni luogo immaginabile pensare forse ho perso qualcosa, ma senza fortuna. Sono assolutamente aggiunto il WatchItemPanel
al WatchListPanel
e chiamato setBounds
, setVisible(true)
, e repaint
sul nuovo pannello.
Questi sono i metodi addWatch
e updatePositions
sul WatchListPanel
:
public void addWatch(Watch watch) { WatchItemPanel watchPanel = new WatchItemPanel(watch); synchronized (this.watches) { this.watches.add(watch); } this.watchPanels.put(watch, watchPanel); this.add(watchPanel); watchPanel.setOpaque(false); watchPanel.setForeground(this.getForeground()); watchPanel.setBackground(this.getBackground()); watchPanel.setVisible(true); watchPanel.setSize(this.getWidth(), WatchItemPanel.PANEL_HEIGHT); for (MouseListener l: this.mouseListeners) watchPanel.addMouseListener(l); for (MouseMotionListener l: this.mouseMotionListeners) watchPanel.addMouseMotionListener(l); this.updatePositions(); } private void updatePositions() { int count = 0; synchronized (this.watches) { for (Watch watch: this.watches) { if ((this.selectedWatchPanel != null) && (count == this.selectedWatchPanelPosition)) count++; WatchItemPanel panel = this.watchPanels.get(watch); if (panel == this.selectedWatchPanel) continue; panel.setBounds(0, count * WatchItemPanel.PANEL_HEIGHT, this.getWidth(), WatchItemPanel.PANEL_HEIGHT); count++; } } if (this.selectedWatchPanel != null) this.selectedWatchPanel.setBounds(0, (this.selectedWatchPanelPosition * WatchItemPanel.PANEL_HEIGHT) + this.selectedWatchPanelDragOffset, this.getWidth(), WatchItemPanel.PANEL_HEIGHT); this.repaint(); }
E qui sono i metodi setBounds
su WatchListPanel
:
@Override public void setBounds(Rectangle r) { super.setBounds(r); for (WatchItemPanel panel: this.watchPanels.values()) { panel.setSize(r.width, WatchItemPanel.PANEL_HEIGHT); panel.repaint(); } } @Override public void setBounds(int x, int y, int width, int height) { super.setBounds(x, y, width, height); for (WatchItemPanel panel: this.watchPanels.values()) { panel.setSize(width, WatchItemPanel.PANEL_HEIGHT); panel.repaint(); } }
Un altro pezzo di informazione qui - tutti i quattro pannelli vengono dipinte. Ho calpestato paintComponent
nel WatchItemPanel
e aggiunto un System.out.println
e ottenuto questo risultato:
WatchItemPanel[,0,66,366x22,invalid,layout=java.awt.GridBagLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777219,maximumSize=,minimumSize=,preferredSize=] WatchItemPanel[,0,44,366x22,layout=java.awt.GridBagLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777219,maximumSize=,minimumSize=,preferredSize=] WatchItemPanel[,0,22,366x22,layout=java.awt.GridBagLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777219,maximumSize=,minimumSize=,preferredSize=] WatchItemPanel[,0,0,366x22,layout=java.awt.GridBagLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777219,maximumSize=,minimumSize=,preferredSize=]
Da quella colonna in più "non valido" lì nel pannello? Quando ho ridimensionare il WatchPanel
il "non valido" va via. Sembra una colonna in più, però. Non c'è alcun corrispondente valore non valido sulle altre linee. (Questo è l'output predefinito JPanel.toString()
con il nome del pacchetto rimosso.
Soluzione
Dopo aver aggiunto il componente, chiamata this.revalidate()
. Ciò fa sì che il contenitore da marcare componenti ri-layout sua. Una volta che si aggiunge questa riga di codice, funziona perfettamente.