Swing(JComboBox)的bug?印刷尺寸

时间:2016-03-29 01:51:32

标签: java swing printing jcombobox

我正在研究JComboBox的维度(我不知道是否有其他Swing对象)。

打印尺寸时会出现问题。 这是一个错误吗?

这是我的代码:

    JPanel jpPanelOut = new JPanel();
    jpPanelOut.setBackground(new java.awt.Color(255, 255, 255));
    jpPanelOut.setLayout(new BoxLayout(jpPanelOut, BoxLayout.PAGE_AXIS));

    JPanel jpPanel = new JPanel();
    jpPanel.setPreferredSize(new Dimension(800, 26));

    Font inFont = new Font("Serif", Font.PLAIN, 10);
    JPanel jpPanel0 = new JPanel();
    jpPanel0.setLayout(new BoxLayout(jpPanel0, BoxLayout.LINE_AXIS));

    JLabel jlLabel0 = new JLabel("this is a new text");
    jlLabel0.setBorder(javax.swing.BorderFactory.createEtchedBorder());
    jlLabel0.setFont(inFont);

    JSlider jslSlider0 = new JSlider(JSlider.HORIZONTAL, 0, 1000000000, 1);
    jslSlider0.setFont(inFont);

    JSpinner jspSpinner0 = new JSpinner(new SpinnerNumberModel(1, 0, 1000000000, 1));
    jspSpinner0.setFont(inFont);

    JTextField jtfTextField0 = new JTextField("1234567890abcdef_gpqyTÑ",48);
    jtfTextField0.setFont(inFont);

    JComboBox jcbComboBox0 = new JComboBox<>(new String[] {"Average"});
    jcbComboBox0.setFont(inFont);
    ((JLabel)jcbComboBox0.getRenderer()).setHorizontalAlignment(JLabel.RIGHT);

    jpPanel0.add(jlLabel0);
    jpPanel0.add(jslSlider0);
    jpPanel0.add(jspSpinner0);
    jpPanel0.add(jtfTextField0);
    jpPanel0.add(jcbComboBox0);



    inFont = new Font("Serif", Font.PLAIN, 10);
    JPanel jpPanel1 = new JPanel();
    jpPanel1.setLayout(new BoxLayout(jpPanel1, BoxLayout.LINE_AXIS));

    JLabel jlLabel1 = new JLabel("this is a new text");
    jlLabel1.setBorder(javax.swing.BorderFactory.createEtchedBorder());
    jlLabel1.setFont(inFont);

    JSlider jslSlider1 = new JSlider(JSlider.HORIZONTAL, 0, 1000000000, 1);
    jslSlider1.setFont(inFont);

    JSpinner jspSpinner1 = new JSpinner(new SpinnerNumberModel(1, 0, 1000000000, 1));
    jspSpinner1.setFont(inFont);

    JTextField jtfTextField1 = new JTextField("1234567890abcdef_gpqyTÑ",48);
    jtfTextField1.setFont(inFont);

    JComboBox jcbComboBox1 = new JComboBox<>(new String[] {"Average"});
    jcbComboBox1.setFont(inFont);
    ((JLabel)jcbComboBox1.getRenderer()).setHorizontalAlignment(JLabel.RIGHT);

    jpPanel1.add(jlLabel1);
    jpPanel1.add(jslSlider1);
    jpPanel1.add(jspSpinner1);
    jpPanel1.add(jtfTextField1);
    jpPanel1.add(jcbComboBox1);

    System.out.println("Height:" 
        + " jtfTextField:" + jtfTextField1.getPreferredSize().getHeight() + "," 
        + jtfTextField1.getMinimumSize().getHeight()
        + " jlLabel:" + jlLabel1.getPreferredSize().getHeight() + "," 
        + jlLabel1.getMinimumSize().getHeight()
        + " jcbComboBox:" + jcbComboBox1.getPreferredSize().getHeight() + "," 
        + jcbComboBox1.getMinimumSize().getHeight()
        + " jslSlider:" + jslSlider1.getPreferredSize().getHeight() + "," 
        + jslSlider1.getMinimumSize().getHeight()
        + " jspSpinner:" + jspSpinner1.getPreferredSize().getHeight() + "," 
        + jspSpinner1.getMinimumSize().getHeight()
        );

    jpPanelOut.add(jpPanel);
    jpPanelOut.add(jpPanel0);
    jpPanelOut.add(jpPanel1);

但维度已经改变!!!

enter image description here

请看:

JTextFields的亮度(宽度)红圈

JComboBoxs 绿线

的上诉(文字)

完整代码

package myPackage;

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


public class NewJFrame extends javax.swing.JFrame {

  public NewJFrame() {
    initComponents();
  }

  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
  private void initComponents() {

    jButton1 = new javax.swing.JButton();
    jPanel1 = new javax.swing.JPanel();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

    jButton1.setText("jButton1");
    jButton1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        jButton1ActionPerformed(evt);
      }
    });

    javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
    jPanel1.setLayout(jPanel1Layout);
    jPanel1Layout.setHorizontalGroup(
      jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGap(0, 0, Short.MAX_VALUE)
    );
    jPanel1Layout.setVerticalGroup(
      jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGap(0, 220, Short.MAX_VALUE)
    );

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
        .addContainerGap(739, Short.MAX_VALUE)
        .addComponent(jButton1)
        .addContainerGap())
      .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
    );
    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addComponent(jButton1)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addGap(0, 51, Short.MAX_VALUE))
    );

    pack();
  }// </editor-fold>                        

  private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    // TODO add your handling code here:
    JPanel jpPanelOut = new JPanel();
    jpPanelOut.setBackground(new Color(255, 255, 255));
    jpPanelOut.setLayout(new BoxLayout(jpPanelOut, BoxLayout.PAGE_AXIS));

    JPanel jpPanel = new JPanel();
    jpPanel.setPreferredSize(new Dimension(600, 26));

    Font inFont = new Font("Serif", Font.PLAIN, 10);
    JPanel jpPanel0 = new JPanel();
    jpPanel0.setLayout(new BoxLayout(jpPanel0, BoxLayout.LINE_AXIS));

    JLabel jlLabel0 = new JLabel("this is a new text");
    jlLabel0.setBorder(BorderFactory.createEtchedBorder());
    jlLabel0.setFont(inFont);

    JSlider jslSlider0 = new JSlider(JSlider.HORIZONTAL, 0, 1000000000, 1);
    jslSlider0.setFont(inFont);

    JSpinner jspSpinner0 = new JSpinner(new SpinnerNumberModel(1, 0, 1000000000, 1));
    jspSpinner0.setFont(inFont);

    JTextField jtfTextField0 = new JTextField("1234567890abcdef_gpqyTÑ",48);
    jtfTextField0.setFont(inFont);

    JComboBox jcbComboBox0 = new JComboBox<>(new String[] {"Average"});
    jcbComboBox0.setFont(inFont);
    ((JLabel)jcbComboBox0.getRenderer()).setHorizontalAlignment(JLabel.RIGHT);

    jpPanel0.add(jlLabel0);
    jpPanel0.add(jslSlider0);
    jpPanel0.add(jspSpinner0);
    jpPanel0.add(jtfTextField0);
    jpPanel0.add(jcbComboBox0);



    inFont = new Font("Serif", Font.PLAIN, 10);
    JPanel jpPanel1 = new JPanel();
    jpPanel1.setLayout(new BoxLayout(jpPanel1, BoxLayout.LINE_AXIS));

    JLabel jlLabel1 = new JLabel("this is a new text");
    jlLabel1.setBorder(BorderFactory.createEtchedBorder());
    jlLabel1.setFont(inFont);

    JSlider jslSlider1 = new JSlider(JSlider.HORIZONTAL, 0, 1000000000, 1);
    jslSlider1.setFont(inFont);

    JSpinner jspSpinner1 = new JSpinner(new SpinnerNumberModel(1, 0, 1000000000, 1));
    jspSpinner1.setFont(inFont);

    JTextField jtfTextField1 = new JTextField("1234567890abcdef_gpqyTÑ",48);
    jtfTextField1.setFont(inFont);

    JComboBox jcbComboBox1 = new JComboBox<>(new String[] {"Average"});
    jcbComboBox1.setFont(inFont);
    ((JLabel)jcbComboBox1.getRenderer()).setHorizontalAlignment(JLabel.RIGHT);

    jpPanel1.add(jlLabel1);
    jpPanel1.add(jslSlider1);
    jpPanel1.add(jspSpinner1);
    jpPanel1.add(jtfTextField1);
    jpPanel1.add(jcbComboBox1);

    System.out.println("Height:" 
        + " jtfTextField:" + jtfTextField1.getPreferredSize().getHeight() + "," 
        + jtfTextField1.getMinimumSize().getHeight()
        + " jlLabel:" + jlLabel1.getPreferredSize().getHeight() + "," 
        + jlLabel1.getMinimumSize().getHeight()
        + " jcbComboBox:" + jcbComboBox1.getPreferredSize().getHeight() + "," 
        + jcbComboBox1.getMinimumSize().getHeight()
        + " jslSlider:" + jslSlider1.getPreferredSize().getHeight() + "," 
        + jslSlider1.getMinimumSize().getHeight()
        + " jspSpinner:" + jspSpinner1.getPreferredSize().getHeight() + "," 
        + jspSpinner1.getMinimumSize().getHeight()
        );

    jpPanelOut.add(jpPanel);
    jpPanelOut.add(jpPanel0);
    jpPanelOut.add(jpPanel1);
    jPanel1.removeAll();
    jPanel1.setLayout(new GridLayout(1, 1));
    jPanel1.add(jpPanelOut);
  }                                        


  public static void main(String args[]) {
    /* Set the Nimbus look and feel */
    //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
    /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
     */
    try {
      for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
        if ("Nimbus".equals(info.getName())) {
          javax.swing.UIManager.setLookAndFeel(info.getClassName());
          break;
        }
      }
    } catch (ClassNotFoundException ex) {
      java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
      java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
      java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
      java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }
    //</editor-fold>

    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
        new NewJFrame().setVisible(true);
      }
    });
  }

  // Variables declaration - do not modify                     
  private javax.swing.JButton jButton1;
  private javax.swing.JPanel jPanel1;
  // End of variables declaration                   
}

2 个答案:

答案 0 :(得分:1)

我能够通过简化actionListener代码来更轻松地演示导致问题的组件,从而创建更好的SSCCE。 SSCCE应该只包含证明问题的相关代码。

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
    JPanel jpPanelOut = new JPanel();
    jpPanelOut.setBackground(new Color(255, 255, 255));
    jpPanelOut.setLayout(new BoxLayout(jpPanelOut, BoxLayout.PAGE_AXIS));

    JPanel jpPanel0 = new JPanel();
    JComboBox jcbComboBox0 = new JComboBox<>(new String[] {"Average"});
    jpPanel0.add(jcbComboBox0);

    JPanel jpPanel1 = new JPanel();
    JComboBox jcbComboBox1 = new JComboBox<>(new String[] {"Average"});
    jpPanel1.add(jcbComboBox1);

    SwingUtilities.invokeLater(new Runnable()
    {
        public void run()
        {
            System.out.println("Height:"
                + " jcbComboBox:" + jcbComboBox1.getPreferredSize().getHeight() + ","
            );
        }
    });

    jpPanelOut.add(jpPanel0);
    jpPanelOut.add(jpPanel1);
    jPanel1.removeAll();
    jPanel1.setLayout(new GridLayout(1, 1));
    jPanel1.add(jpPanelOut);
}

所以基本上问题是System.out.println(...)在单独的Thread上执行。应该在Event Dispatch Thread上执行对Swing组件的所有更新。因此,组合框上的getPreferredSize()方法导致EDT之外的组合框发生变化,这在某种程度上导致了问题。

一种解决方案是将代码包装在SwingUtilities.invokeLater中。另一种解决方案是将System.out.println(...)语句移动到方法的末尾。这两种解决方案都允许在打印高度之前在EDT上正确实现组合框。

答案 1 :(得分:0)

也许这个问题只发生在Nimbus(Synth)LookAndFeel

  

<强> SynthArrowButtonUI

public Dimension getPreferredSize(JComponent c) {
  SynthContext context = getContext(c);
  Dimension dim = null;
  if (context.getComponent().getName() == "ScrollBar.button") {
    //...
  }
  if (dim == null) {
    // For all other cases (including Spinner, ComboBox), we will
    // fall back on the single ArrowButton.size value to create
    // a square return value
    int size = context.getStyle().getInt(context, "ArrowButton.size", 16);
      dim = new Dimension(size, size);
    }
//...

<强> NimbusComboBoxSizeTest

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

public class NimbusComboBoxSizeTest {
  public JComponent makeUI() {
    String[] model = {"Average"};

    JPanel p0 = new JPanel();
    JComboBox<String> combo0 = new JComboBox<>(model);
    p0.add(combo0);

    JPanel p1 = new JPanel();
    JComboBox<String> combo1 = new JComboBox<>(model);
    p1.add(combo1);

    Box box = Box.createVerticalBox();
    box.add(p0);
    box.add(p1);

    EventQueue.invokeLater(() -> System.out.println("combo0: " + combo0.getPreferredSize()));
    System.out.println("combo1: " + combo1.getPreferredSize());

    JPanel p = new JPanel(new BorderLayout());
    p.add(box, BorderLayout.NORTH);

    return p;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      try {
        for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
          if ("Nimbus".equals(laf.getName())) {
            UIManager.setLookAndFeel(laf.getClassName());
            UIDefaults d = UIManager.getLookAndFeelDefaults();
            System.out.println("ArrowButton.size: " + d.getInt("ArrowButton.size"));
            System.out.println("ComboBox.arrowButton.size: " + d.getInt("ComboBox:\"ComboBox.arrowButton\".size"));
            d.put("ArrowButton.size", 19);
            //or: d.put("ComboBox:\"ComboBox.arrowButton\".size", 16);
          }
        }
      } catch (Exception ex) {
        ex.printStackTrace();
      }
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new NimbusComboBoxSizeTest().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}
  • ArrowButton.size: 16
  • ComboBox.arrowButton.size: 19
  • combo1: java.awt.Dimension[width=74,height=26]
  • combo0: java.awt.Dimension[width=77,height=26]