2016-12-28 40 views
2

我正在尝试使用Java Swing为小型电话簿应用编写代码布局。我遇到了一个我无法修复的问题。我希望筛选器(显示在搜索结果下)足够宽,以便在搜索短语短时显示整个标题。这里是什么样子:强制最小化JPanel大小

sample filters

正如你所看到的名字被缩短。姓氏带有较长的文字,并按照我的意愿显示。

过滤器类:

import javax.swing.*; 
import javax.swing.border.CompoundBorder; 
import java.awt.*; 

public class Filter 
{ 
    private JLabel label; 
    private JPanel filterPane; 

    Filter(String name) 
    { 
     // Filter text 
     label = new JLabel(); 
     label.setForeground(new Color(0xAA0000)); 

     // Closing button 
     JButton closeButton = new JButton("X"); 
     closeButton.setFont(new Font("Dialog", Font.BOLD, 20)); 
     closeButton.setMargin(new Insets(0, 0, 0, 0)); 

     filterPane = new JPanel(); 
     filterPane.setLayout(new BoxLayout(filterPane, BoxLayout.X_AXIS)); 
     // Frame with title + 50px padding on the right side for the next filter 
     filterPane.setBorder(new CompoundBorder(
       BorderFactory.createEmptyBorder(0, 0, 0, 50), 
       BorderFactory.createTitledBorder(name))); 
     filterPane.add(closeButton); 
     filterPane.add(Box.createRigidArea(new Dimension(5, 0))); 
     filterPane.add(label); 
     filterPane.setVisible(false); 
    } 

    public void setValue(String value) { 
     if (value == null || value.isEmpty()) 
      filterPane.setVisible(false); 
     else 
     { 
      this.label.setText(value); 
      filterPane.setVisible(true); 
     } 
    } 

    public JPanel getFilterPane() { 
     return filterPane; 
    } 
} 

主类:

import javax.swing.*; 
import java.awt.*; 
import java.lang.reflect.InvocationTargetException; 

public class TestWindow 
{ 
    private static void init() 
    { 
     JFrame frame = new JFrame("Stackoverflow test window"); 
     frame.setSize(new Dimension(480, 320)); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setLocationRelativeTo(null); 

     // Main panel - 20 px padding from each side 
     JPanel pane = new JPanel(); 
     pane.setLayout(new BorderLayout()); 
     pane.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); 

     // Create panel for filters 
     JPanel filterPane = new JPanel(); 
     filterPane.setLayout(new BoxLayout(filterPane, BoxLayout.X_AXIS)); 
     filterPane.setPreferredSize(new Dimension(0, 60)); 

     // Add sample filters 
     Filter filter = new Filter("name"); 
     filter.setValue("i"); 
     filter.getFilterPane().setAlignmentY(Component.BOTTOM_ALIGNMENT); 
     filterPane.add(filter.getFilterPane()); 

     filter = new Filter("surname"); 
     filter.setValue("loooooong text"); 
     filter.getFilterPane().setAlignmentY(Component.BOTTOM_ALIGNMENT); 
     filterPane.add(filter.getFilterPane()); 

     // Add everything to main panel 
     pane.add(new JTextArea("Nothing fancy here, just to fill out space"), BorderLayout.CENTER); 
     pane.add(filterPane, BorderLayout.SOUTH); 
     frame.setContentPane(pane); 
     frame.setVisible(true); 
    } 

    public static void main (String [] args) throws InterruptedException, InvocationTargetException { 
     SwingUtilities.invokeLater(TestWindow::init); 
    } 
} 

我试图setMinimumSizesetPreferredSize都在过滤器构造labelfilterPane,但它并没有帮助。请问你能帮帮我吗?

+2

你是如何加入窗格父窗口?你使用什么布局?请[编辑]问题并添加适用的代码。 – RealSkeptic

+0

谢谢,你说得对。完成。 – PKua

+2

而不是设置大小,重写类的getXxxSize。发布[mcve]。 – user1803551

回答

5

问题其实是由两个问题组成的。

  1. 当使用TitledBorder时,组件在计算其首选大小时不考虑标题的大小。
  2. 使用BoxLayout时,首选宽度将被忽略,除非在组件后面添加“水平胶合”。

因此,要解决第一个问题,您需要覆盖JPanel的getPreferredSize()方法。但为了达到此目的,您还需要通过添加胶水来绕过第二个问题。

要覆盖getPreferredSize(),您可以使用类似:

class MinSizePanel extends JPanel { 

    public Dimension getPreferredSize() { 
     Dimension original = super.getPreferredSize(); 
     TitledBorder titleBorder = (TitledBorder)((CompoundBorder)getBorder()).getInsideBorder(); 
     int width = (int)Math.max(original.getWidth(), 60 + (int)titleBorder.getMinimumSize(this).getWidth()); 
     return new Dimension(width, (int)original.getHeight()); 
    } 
} 

这从CompoundBorder得到TitledBorder,得到它的最小尺寸(这是取标题的宽度考虑的方法),增加了一些额外的空白边框和插入(你可以添加适当的计算,我做了一个快捷方式,只是使用60 ...),并使用它(如果它是超过组件的宽度原样)。

而不是

filterPane = new JPanel(); 

使用

filterPane = new MinSizePanel(); 

(你真的应该移动的面板的结构的其余所有成类为好)。

而在TestWindow类,最后

filterPane.add(filter.getFilterPane()); 

后还要添加

filterPane.add(Box.createHorizontalGlue()); 
+0

非常感谢,它解决了这个问题。所以'BoxLayout'会忽略它绑定的容器的首选宽度,除非还有胶水? – PKua

+1

@PKua它忽略了组件的首选宽度,而不是容器的首选宽度。我认为它试图使布局紧凑,就像左边有一段文字。添加胶水会导致它计算不同的最大宽度并更改其策略。还有其他方法可以达到同样的效果。 – RealSkeptic