Wie setze ich eine harte Grenze für eine JComponent, wenn setMaximumSize () und setPreferedSize () nicht funktionieren?

Ich versuche, einen Bildverarbeitungsrahmen zu erstellen, der dem in Photoshop oder Paint Shop Pro ähnlich ist, und ich stoße auf Probleme.

Im Moment habe ich ein JFrame-Fenster mit einem JDesktopPane. Wenn ich auf eine Schaltfläche klicke, wird ein JInternalFrame mit folgenden Komponenten erstellt:

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

Mein Problem ist folgendes: Ich möchte nicht, dass sich JLabel oder JScrollPane auf die Größe von JInternalFrame ausdehnen, wenn JLabel kleiner als JInternalFrame ist.

Ich habe versucht, den Raum um das JLabel mit “leeren” JLabels aufzufüllen. Ich habe versucht, Layout-Stile der JScrollPane zu wechseln. Ich habe versucht, die bevorzugten und maximalen Größen von JLabel und JScrollPane auf die von picture.png zu setzen. Nichts davon funktioniert für das, was ich brauche. Ich möchte nicht, dass der leere “Raum” um das JLabel ein Teil von JScrollPane oder JLabel ist, so dass ich verschiedene MouseEvents verwenden kann, um das Bild selbst auszulösen, anstatt den von “gestreckten” JLabel oder JScrollPane hinterlassenen Raum Ich ändere die Größe des JInternalFrame.

Danke im Voraus.

Edit1: Hier ist ein bisschen Code, der das Problem hervorhebt.

 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); } } 

Sie müssen Ihr eigenes “test.gif” erhalten und wenn Sie den internen Rahmen größer als das Bild machen, füllt er den verbleibenden Platz mit dem Label. Wie alle mouseEvents feuern, wenn ich den internen Frame und nicht auf das Bild, wie ich will, passieren.

Edit2: Code modifiziert mit Kleopatras Vorschlägen.

 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 diesem Beispiel wird der interne Rahmen anfänglich nicht mehr als MAX_SIZE Pixel sein. Kleinere Bilder werden so skaliert, dass das Scrollen nicht erforderlich ist.

Nachtrag: Wenn Sie den Titel genauer lesen, möchten Sie vielleicht auch die maximale Größe des internen Rahmens einschränken:

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

Nachtrag: Diese Variation kann zur Klärung des Problems beitragen. Mit dem Standardlayout BorderLayout.CENTER werden die Bildlaufleisten wie gewünscht MouseListener , aber der MouseListener verhält sich nicht wie gewünscht. Mit einem Layout, das die bevorzugten Größen FlowLayout , wird der MouseListener korrekt MouseListener , aber die Bildlaufleisten werden nie MouseListener , da sich die bevorzugte Größe des Labels niemals ändert. Ich habe synthetische Bilder für die Bequemlichkeit hinzugefügt.

Bildbeschreibung hier eingeben

 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(); } }); } } 

Die Antwort auf Layoutprobleme ist der LayoutManager. Immer. Es ist nie setXXSize (obwohl nichts absolut absolut ist 🙂

Nur um sicher zu sein, verstehe ich, was Sie suchen:

  • haben Sie immer das Label in seiner Pref Größe (das ist standardmäßig die Größe des Icons)
  • scrolling zulassen, wenn der interneFrame kleiner als der Pref ist, dh wenn der Scrollpanel verkleinert wird, bleibt das Label bei seiner Pref
  • strekking von scrollPane und dessen Inhalt nicht zulassen, wenn der interne Rahmen größer als pref ist

Der wichtige LayoutManager in diesem Szenario ist derjenige, der die Größe des Scrollpanels steuert: das ist der LayoutManager des contentPane von internalFrame. Der Standardmanager ist ein BorderLayout: Größe seines Mittelpunkts auf den verfügbaren Platz. Wir müssen das durch eines ersetzen, das max respektiert und die zentrale Komponente (den Scrollpanel) einen max melden lässt (was typischerweise Short.MAX ist)

  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