2015-09-21 138 views
0

我有一个JFrame。它使用JPanel作为其内容窗格,并且JPanel使用GridBagLayout作为其布局管理器。 JPanel包含两个项目:一个按钮和另一个JPanel。在程序启动时,使用ImageIO.read(...)将图像从文件加载到最低级JPanel中作为BufferedImage。这里是一切都会发生的地方。GridBagLayout不调整图像加载大小

图像加载正确,我可以在屏幕上看到它的一个小角落(调试器中指定的14px方块)。我无法弄清楚这将导致布局增长,并将整个图像放在屏幕上最低级别的JPanel上。调试器中的图像显示500px的正确大小。 CardImagePanel的首选大小与图像大小相同。但是除非我使用setSize(...)手动设置CardImagePanel大小,否则布局将不会考虑首选大小,我相当肯定这对GBL不应该是必需的。

我曾尝试在整个程序中对每个JFrame,JPanel,布局,网格包,图像等进行revalidate()和repaint()调用,并且找不到正确的位置或时间来调用它们让这件事情起作用。目前我一直试图让图像加载不正确,并使用按钮强制重新验证和重绘,但即使这个显式调用也没有做任何事情。

我正在失去理智,我会尽一切努力让这件事情起作用。

这里是我的整个愚蠢的事情的所有代码(减去进口和包装规格

P1s1.java:

public class P1s1 { 

    public static void main(String[] args) { 
     // TODO code application logic here 
     build(); 
    } 

    public static void build() 
    { 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(new Dimension(640, 480)); 
     frame.setContentPane(new GuiPanel(frame)); 
     frame.setVisible(true); 
    } 
} 

GuiPanel.java:

public class GuiPanel extends JPanel { 

    JFrame parentFrame; 
    JButton imageLoaderButton; 
    CardImagePanel cardImagePanel; 
    LayoutManager layout; 
    GridBagLayout gridBagLayout; 
    GridBagConstraints constraints; 

    public GuiPanel(JFrame frame) 
    { 
     parentFrame = frame; 

     constraints = new GridBagConstraints(); 
     gridBagLayout = new GridBagLayout(); 

     layout = gridBagLayout; 
     this.setLayout(layout); 

     this.setBorder(BorderFactory.createLineBorder(Color.black)); 

     setupImageLoaderButton(imageLoaderButton); 

     cardImagePanel = new CardImagePanel(); 
     this.add(cardImagePanel); 
    } 

    private void setupImageLoaderButton(JButton button) 
    { 
     button = new JButton("Click to load image!"); 
     ActionListener imageLoaderListener; 
     imageLoaderListener = new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent ae) { 
       System.out.println("Button clicked."); 

       cardImagePanel.revalidate(); 
       cardImagePanel.repaint(); 

       GuiPanel.this.revalidate(); 
       GuiPanel.this.repaint(); 

       parentFrame.revalidate(); 
       parentFrame.repaint(); 
      } 
     }; 
     button.addActionListener(imageLoaderListener); 
     this.add(button); 
    } 
} 

CardImagePanel.java :

public class CardImagePanel extends JPanel { 

    BufferedImage cardImage; 

    public CardImagePanel() 
    { 
     this.setBorder(BorderFactory.createLineBorder(Color.black)); 

     try { 
      cardImage = ImageIO.read(new File("c:\\dev\\cards\\2_of_clubs.png")); 
      this.setPreferredSize(new Dimension(cardImage.getWidth(), cardImage.getHeight())); 
     } catch (IOException ex) { 
      System.out.println("Exception trying to load image file."); 
     } 
    } 

    // The getPreferredSize() override was suggested by MadProgrammer. 
    // It did not solve the issue, but see MadProgrammer's updated, 
    // accepted answer below for the correct solution. The rest of the 
    // code reflects my original attempt to solve the issue. 
    @Override 
    public Dimension getPreferredSize() 
    { 
     return cardImage != null ? new Dimension(cardImage.getWidth(), cardImage.getHeight()) : super.getPreferredImage(); 
    } 

    @Override 
    public void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 

     g.drawImage(cardImage, 0, 0, this); 
    } 
} 

回答

3

GridBagLayout依赖于一个组件告诉它它想要的大小(以及它在缓解时的最小和最大大小)。你需要重写CardImagePanelgetPreferredSize方法,返回的大小,你想的成分是

public class CardImagePanel extends JPanel { 

    BufferedImage cardImage; 

    public CardImagePanel() { 
     this.setBorder(BorderFactory.createLineBorder(Color.black)); 

     try { 
      cardImage = ImageIO.read(new File("c:\\dev\\cards\\2_of_clubs.png")); 
     } catch (IOException ex) { 
      System.out.println("Exception trying to load image file."); 
     } 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return cardImage != null ? new Dimension(cardImage.getWidth(), cardImage.getHeight()) : super.getPreferredSize(); 
    } 

    @Override 
    public Dimension getMinimumSize() { 
     return getPreferredSize(); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 

     g.drawImage(cardImage, 0, 0, this); 
    } 
} 

看一看How to Use GridBagLayout更多细节

+0

我尝试了您的踢腿建议,但它没有效果。正如我在文章中所解释的,首选大小已经返回了预期的尺寸。我会花一些时间阅读您链接的文章以获得更多提示。 – Steverino

+0

您的代码对我来说工作正常,如果在图像对于容器的可用空间较大时发生什么情况,这可能会引起关注,这意味着它会采取最小尺寸。我还建议将'frame.setSize(new Dimension(640,480));'更改为'frame.pack()' – MadProgrammer

+0

在这种情况下,将最小尺寸手动设置为图像大小?编辑:对不起,只是看到你的代码更新。那看起来很有希望 – Steverino

3

您的CardImagePanel没有首选大小,因此布局管理器不知道如何正确处理大小。

一对夫妇的解决方案:

  1. 没有必要创建一个自定义类来显示图像。只需使用JLabel即可显示图像。 JLabel将返回图像的首选大小。
  2. 如果您确实使用了CardImagePane,那么您需要覆盖CardImagePanel的getPreferredsize()方法以返回图像的大小。
+0

肯定容易得多了'JLabel' – MadProgrammer

+0

设置手动设置JPanel的首选大小并不实际设置它?在加载图像后,当我在调试器中查看JPanel的首选大小时,我确实看到它报告了我期望的尺寸的首选大小,但我仍然会尝试此解决方案以查看它是否有帮助。 – Steverino

+0

我应该补充说这是一个学校项目。这是一个项目约束,我们扩展JPanel来创建类似于CardImagePanel的东西来容纳我们的图像。至于第2项,我尝试了这个,并没有效果。我会更新我的帖子以反映更改。 – Steverino