Come posso impostare un limite rigido su un JComponent quando setMaximumSize () e setPrefferedSize () non funzionano?

Sto cercando di creare un frame per l’elaborazione di immagini simile a quello trovato in Photoshop o Paint Shop Pro e sto riscontrando problemi.

In questo momento ho una finestra JFrame con un JDesktopPane. Quando faccio clic su un pulsante, viene creato un object JInternalFrame con i seguenti componenti:

imageLabel = new JLabel("picture.png"); scrollPane.setViewPort(imageLabel); internalFrame.add(scrollPane); // I also tried with a BorderLayout() desktopPane.add(internalFrame); 

Il mio problema è questo: non voglio che JLabel o JScrollPane si estendano alla dimensione di JInternalFrame se la JLabel è più piccola di JInternalFrame.

Ho provato a riempire lo spazio intorno alla JLabel con JLabels “vuoti”. Ho provato a cambiare gli stili di layout di JScrollPane. Ho provato a impostare le dimensioni preferite e massime di JLabel e JScrollPane a quella di picture.png. Niente funziona per quello di cui ho bisogno. Non voglio che lo “spazio” vuoto attorno a JLabel faccia parte di JScrollPane o di JLabel in modo da poter utilizzare vari MouseEvent per l’triggerszione sull’immagine stessa piuttosto che lo spazio lasciato dalla JLabel o JScrollPane “allungato” ogni volta Ridimensiono il JInternalFrame.

Grazie in anticipo.

Edit1: Ecco un po ‘di codice che evidenzia il problema.

 import java.awt.*; import java.awt.event.*; class fooFrame extends JFrame implements MouseListener { private static fooFrame frame; JLabel fooLabel; public fooFrame() { JDesktopPane background = new JDesktopPane(); JInternalFrame internalFrame = new JInternalFrame("Internal Frame", true, true, true, true); internalFrame.setSize(500, 500); internalFrame.setLocation(20, 20); internalFrame.setVisible(true); Image image = Toolkit.getDefaultToolkit().getImage("test.gif"); fooLabel = new JLabel(new ImageIcon("test.gif")); fooLabel.setPreferredSize(new Dimension(image.getWidth(null), image.getHeight(null))); JScrollPane fooScrollPane = new JScrollPane(fooLabel, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); fooScrollPane.setPreferredSize(new Dimension(fooLabel.getWidth(), fooLabel.getHeight())); fooScrollPane.setViewportView(fooLabel); // add JLabel to JScrollPane internalFrame.add(fooScrollPane); // add JScrollPane to JInternalFrame background.add(internalFrame); // add JInternalFrame to JDesktopPanel this.setContentPane(background); // add JDesktopPanel to JFrame fooLabel.addMouseListener(this); } public void mouseClicked(MouseEvent me) { if (me.getSource() == fooLabel) System.out.println("Clicked the picture."); } public void mouseEntered(MouseEvent me) { if (me.getSource() == fooLabel) System.out.println("Entered the picture."); } public void mouseExited(MouseEvent me) { if (me.getSource() == fooLabel) System.out.println("Exited the picture."); } public void mousePressed(MouseEvent me){} public void mouseReleased(MouseEvent me){} public static void createAndShowGUI() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { } frame = new fooFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setTitle("foo"); frame.setSize(800,600); frame.setLocationRelativeTo(null); frame.setVisible(true); } } 

Dovrai ottenere il tuo “test.gif” e se rendi il frame interno più grande dell’immagine, riempie lo spazio rimanente con l’etichetta. Come tutti i mouseEventi sparano quando incrocio la struttura interna anziché sull’immagine, come se volessi accadere.

Modifica2: codice modificato con i suggerimenti di Kleopatra.

 import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.LineBorder; public class a1 { public static void main(String[] args) { fooFrame.createAndShowGUI(); } } class fooFrame extends JFrame implements MouseListener { private static fooFrame frame; JLabel fooLabel; public fooFrame() { JDesktopPane background = new JDesktopPane(); JInternalFrame internalFrame = new JInternalFrame("Internal Frame", true, true, true, true); internalFrame.setLocation(20, 20); internalFrame.setVisible(true); internalFrame.pack(); Image image = Toolkit.getDefaultToolkit().getImage("test.gif"); fooLabel = new JLabel(new ImageIcon(image)); fooLabel.setBorder(new LineBorder(Color.PINK)); JScrollPane fooScrollPane = new JScrollPane((fooLabel), JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); internalFrame.setLayout(new BoxLayout(internalFrame.getContentPane(), BoxLayout.LINE_AXIS)); fooScrollPane.setViewportView(fooLabel); // add JLabel to JScrollPane internalFrame.add(fooScrollPane); // add JScrollPane to JInternalFrame background.add(internalFrame); // add JInternalFrame to JDesktopPanel this.setContentPane(background); // add JDesktopPanel to JFrame fooLabel.addMouseListener(this); } public void mouseClicked(MouseEvent me) { if (me.getSource() == fooLabel) System.out.println("Clicked the picture."); } public void mouseEntered(MouseEvent me) { if (me.getSource() == fooLabel) System.out.println("Entered the picture."); } public void mouseExited(MouseEvent me) { if (me.getSource() == fooLabel) System.out.println("Exited the picture."); } public void mousePressed(MouseEvent me) { } public void mouseReleased(MouseEvent me) { } @Override public Dimension getMaximumSize() { return getPreferredSize(); } public static void createAndShowGUI() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { } frame = new fooFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setTitle("foo"); frame.setSize(800, 600); frame.setLocationRelativeTo(null); frame.setVisible(true); } } 

In questo esempio, il frame interno inizialmente non sarà più di MAX_SIZE pixel. Le foto più piccole verranno ridimensionate in modo che lo scorrimento non sia necessario.

Addendum: leggendo il titolo più da vicino, potresti anche voler limitare la dimensione massima del frame interno:

 internalFrame.setMaximumSize(new Dimension(fooLabel.getPreferredSize())); 

Addendum: questa variazione può aiutare a chiarire il problema. Con il layout predefinito, BorderLayout.CENTER , le barre di scorrimento vengono visualizzate come richiesto, ma MouseListener non si comporta come desiderato. Con un layout che rispetta le dimensioni preferite, FlowLayout , MouseListener riporta correttamente, ma le barre di scorrimento non vengono mai visualizzate, poiché la dimensione preferita dell’etichetta non cambia mai. Ho aggiunto immagini sintetiche per comodità.

inserisci la descrizione dell'immagine qui

 import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import javax.swing.*; class PictureFrame extends JFrame { private static final String NAME = "image.jpg"; public PictureFrame() { JDesktopPane dtp = new JDesktopPane(); dtp.add(new MyFrame("Large", FauxImage.create(300, 500), 50)); dtp.add(new MyFrame("Small", FauxImage.create(200, 200), 25)); this.add(dtp); } private static class MyFrame extends JInternalFrame { private static final int MAX_SIZE = 256; public MyFrame(String title, Image image, int offset) { super(title, true, true, true, true); //this.setLayout(new FlowLayout()); final JLabel label = new JLabel(new ImageIcon(image)); this.add(new JScrollPane(label)); this.pack(); int w = Math.min(MAX_SIZE, image.getWidth(null)); int h = Math.min(MAX_SIZE, image.getHeight(null)); Insets i = this.getInsets(); this.setSize(w + i.left + i.right, h + i.top + i.bottom); this.setLocation(offset, offset); this.setVisible(true); label.addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent me) { if (me.getSource() == label) { System.out.println("Entered."); } } @Override public void mouseExited(MouseEvent me) { if (me.getSource() == label) { System.out.println("Exited."); } } }); } } private static class FauxImage { static public Image create(int w, int h) { BufferedImage bi = new BufferedImage( w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = bi.createGraphics(); g2d.setPaint(Color.lightGray); g2d.fillRect(0, 0, w, h); g2d.setColor(Color.black); String s = w + "\u00D7" + h; int x = (w - g2d.getFontMetrics().stringWidth(s)) / 2; g2d.drawString(s, x, 24); g2d.dispose(); return bi; } } public static void createAndShowGUI() { PictureFrame frame = new PictureFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setTitle("PictureFrame"); frame.setSize(640, 400); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { createAndShowGUI(); } }); } } 

La risposta ai problemi di layout è LayoutManager. Sempre. Non è mai impostatoXXSize (anche se nulla è assolutamente assoluto 🙂

Solo per essere sicuro di capire cosa stai cercando:

  • sempre l’etichetta alla sua dimensione pref (che di default è la dimensione della sua icona)
  • consentire lo scorrimento se il frame interno è più piccolo del pref, ovvero lo scrollmap viene ridimensionato a più piccolo, l’etichetta rimane al suo pref
  • non consentire lo striscio dello scrollPane e il suo contenuto se il frame interno è più grande di pref

L’importante LayoutManager in questo scenario è quello che controlla la dimensione dello scrollpane: questo è il LayoutManager del contentPane di theFrame interno. Il gestore predefinito è BorderLayout: dimensiona il suo centro in qualsiasi spazio disponibile. Dobbiamo sostituirlo con uno che rispetta il massimo e rendere il componente centrale (lo scrollmap) un valore massimo (che in genere è Short.MAX)

  internalFrame.setLayout(new BoxLayout(internalFrame.getContentPane(), BoxLayout.LINE_AXIS)); Image image = Toolkit.getDefaultToolkit().getImage("test.gif"); fooLabel = new JLabel(new ImageIcon(image)); JScrollPane fooScrollPane = new JScrollPane(fooLabel), JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER) { @Override public Dimension getMaximumSize() { return getPreferredSize(); } }; internalFrame.add(fooScrollPane); // add JScrollPane to JInternalFrame