[关闭]
@torresdyl 2017-09-14T07:10:55.000000Z 字数 48946 阅读 4892

[JAVA & Web] Snippets

java swing web snippets code


I. Java SE

A. Basic

1. Reflexion

所有reflexion方法必须通过getter来取得类中的元素。所以,如果一些元素可以通过reflexion取得, 而另外一些不行,首先要检查getter是否生成了。

2. Divide the number into 100 and keep the decimal part

If we do

  1. int number = Integer.parseInt("123456");
  2. double i = number / 100;

i will be 1234.0, not 1234.56.

To preserve the decimal part scale, you must convert the number into double first.

  1. double i = ((double)number)/100;

B. Swing & AWT

I. Swing

1. 让窗口适应所有内部元素总尺寸并居中
  1. //The order of these lines matters!!!
  2. pack();
  3. setBounds(0, 0, getSize().width, getSize().height);
  4. setLocationRelativeTo(null);
  5. //if you don't want to set the min size of window, better set this. Otherwise, when resizing, unexpected results happen.
  6. setResizable(false);
  7. setVisible(true);

最好的办法是使用MigLayout。用百分比来定义尺寸,这样每次改变窗口尺寸,内部元素都会重新自动排布。

2. JLabel wrap with proper size to hold long text:

wrap the text with <html></html>. Nothing more.

3. Z axis add order

Java Swing adds components in an nonintuitive way: the firstly added components overlap the preceding ones. If you add component A first and then component B, both in the same place, A will block B instead of B blocking A. It's very weird and not mentioned in the Oracle DOC........

4. JTabbedPane's "tab row" will block components behind them, even if it's not fully filled

Imagine a JTabbedPane with 2 tabs on the left. The row where all the tabs are placed has only the left part filled, on the right there're no tabs. But this row is not blank! It will blocked the components behind them, preventing them from user interractions. A button behind this row cannot be clicked, for example.

5. Set the line spacing of a JTextPane

First you must select the text, and then set the ParagraghAttributes. Then, if needed, get the caret to top.

  1. /**
  2. * Select all the text of a <code>JTextPane</code> first and then set the line spacing.
  3. * @param the <code>JTextPane</code> to apply the change
  4. * @param factor the factor of line spacing. For example, <code>1.0f</code>.
  5. * @param replace whether the new <code>AttributeSet</code> should replace the old set. If set to <code>false</code>, will merge with the old one.
  6. */
  7. /* Applied once, and forever changed the line spacing, even if there were no text. So do it at the beginning. */
  8. public static void changeLineSpacing(JTextPane pane, float factor, boolean replace) {
  9. pane.selectAll();
  10. MutableAttributeSet set = new SimpleAttributeSet(pane.getParagraphAttributes());
  11. StyleConstants.setLineSpacing(set, factor);
  12. txtAtributosImpresora.setParagraphAttributes(set, replace);
  13. pane.setCaretPosition(0); //scroll to the top, if it's in a JScrollPane. Usually useful because JTextPane cannot scroll.
  14. }

Better to get the already set ParagraphAttributes from the text, or set replace to false, to prevent the old attributes to be overwritten.

6. Set the line height of a JList
  1. list.setFixedCellHeight(30); //in pixeles
7. JTable custom renderer: Icon opaque to show background color

Actually it's easy. We have two styles in even and uneven lines. To show the background color in a cell where we see Icons, we must setOpaque(true) to see it. If not, the background is white.

I think that in the renderer, when creating the JLabel to render the cell, by default it occupies the whole cell, in spite that the icon image can be smaller. So the renderer as JLabel must show the pixeles behind the white part around the image.

  1. import java.awt.Color;
  2. import java.awt.Component;
  3. import java.awt.Dimension;
  4. import javax.swing.Icon;
  5. import javax.swing.ImageIcon;
  6. import javax.swing.JFrame;
  7. import javax.swing.JLabel;
  8. import javax.swing.JPanel;
  9. import javax.swing.JScrollPane;
  10. import javax.swing.JTable;
  11. import javax.swing.SwingUtilities;
  12. import javax.swing.table.DefaultTableModel;
  13. import javax.swing.table.TableCellRenderer;
  14. public class IconTableWithTwoColores extends JFrame {
  15. private static final String imgPath = "img/carpeta.png";
  16. public IconTableWithTwoColores() {
  17. begin();
  18. }
  19. private void begin() {
  20. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  21. JPanel content = new JPanel();
  22. content.setLayout(null);
  23. JTable table = new JTable();
  24. table.setFillsViewportHeight(true);
  25. table.setPreferredScrollableViewportSize(new Dimension(300, 300));
  26. ImageIcon icon1 = new ImageIcon(imgPath);
  27. table.setModel(new DefaultTableModel(new Object[][] {{icon1, "no way!"}, {icon1, "now what"}}, new String[] {"Col 1", "Col 2"}));
  28. class MyRenderer extends JLabel implements TableCellRenderer {
  29. @Override
  30. public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
  31. boolean hasFocus, int row, int column) {
  32. JLabel label = new JLabel();
  33. if (row % 2 == 0) {
  34. label.setBackground(Color.pink);
  35. } else {
  36. label.setBackground(Color.green);
  37. }
  38. if (value instanceof Icon) {
  39. label.setIcon((Icon)value);
  40. //if this line is commented, you won't see the background color of the cell
  41. label.setOpaque(true);
  42. return label;
  43. } else {
  44. label.setText(value.toString());
  45. label.setOpaque(true);
  46. return label;
  47. }
  48. }
  49. }
  50. table.setDefaultRenderer(Object.class, new MyRenderer());
  51. JScrollPane scroll = new JScrollPane(table);
  52. scroll.setVisible(true);
  53. scroll.setBounds(0, 0, 300, 300);
  54. content.add(scroll);
  55. getContentPane().add(content);
  56. pack();
  57. setVisible(true);
  58. setBounds(0, 0, 300, scroll.getHeight());
  59. setLocationRelativeTo(null);
  60. }
  61. public static void main(String[] args) {
  62. SwingUtilities.invokeLater(new Runnable() {
  63. @Override
  64. public void run() {
  65. IconTableWithTwoColores frame = new IconTableWithTwoColores();
  66. }
  67. });
  68. }
  69. }
8. 根据窗口尺寸来调整各元素的大小和位置

最好的办法是使用MigLayout。用百分比来定义尺寸,这样每次改变窗口尺寸,内部元素都会重新自动分布。

9. 在同一位置切换显示不同的Panel

使用CardLayout. 这是Swing自带的,不用加jar。

  1. JPanel parent = new JPanel(new CardLayout());
  2. parent.add(a, "panelA");
  3. parent.add(b, "panelB");
  4. JButton button1 = new JButton("Toggle A");
  5. button1.addActionListener(new ActionListener() {
  6. @Override
  7. public void actionPerformed(ActionEvent e) {
  8. CardLayout cl = (CardLayout)parent.getLayout();
  9. cl.show(parent, "panelA");
  10. }
  11. });
  12. JButton button2 = new JButton("Toggle B");
  13. button2.addActionListener(new ActionListener() {
  14. @Override
  15. public void actionPerformed(ActionEvent e) {
  16. CardLayout cl = (CardLayout)parent.getLayout();
  17. cl.show(parent, "panelB");
  18. }
  19. });
10. JSplitPane divider weight/percentage
  1. splitPane.setResizeWeight(0.333);

It will make the first panel sized to the half of the second panel.

11. Change table renderer without change L&F delegated background

Get the default renderer and do changes to it, and return it. Remember: now it's your responsibility to apply all the styles according to the data type/column index, etc. Only the uneven/even row background is preserved, as what we see in Nimbus L&F.

  1. public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
  2. JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
  3. //do changes to label
  4. return label;
  5. }
12. Use custom Font

You can register one font in the GraphicEnvironment and use it. It applies only to the scope of this application, and will not affect other Java applications, neither other programs, because it doesn't install something new into the system.

  1. GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
  2. Font custom1 = Font.createFont(Font.TRUETYPE_FONT, new File("resources/fonts/YaHei Consolas Hybrid 1.12.ttf"));
  3. Font custom2 = custom1.deriveFont(14f).deriveFont(Font.BOLD);
  4. ge.registerFont(custom2);

就算不register,也可以用的,但是scope就限制了。

13. JSplitPane golden rules for sizing

http://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html#rules

too much to discuss.

14. Listeners firing order

http://stackoverflow.com/questions/7613582/order-of-listeners-in-java

Listeners are NOT guaranteed to fire in certain order. Use other mecanisms to ensure it.

  1. Use one main listener to do all the things.
  2. Use some helper class to assign and determine the order. Like this.
    We have:
  1. import java.awt.event.ActionEvent;
  2. import java.awt.event.ActionListener;
  3. import java.util.ArrayList;
  4. import java.util.Iterator;
  5. import java.util.Map;
  6. import java.util.TreeMap;
  7. import java.util.TreeSet;
  8. public class CompositeActionListenerWithPriorities implements ActionListener {
  9. private Map<Integer, ArrayList<ActionListener>> listeners =
  10. new TreeMap<Integer,ArrayList<ActionListener>>();
  11. @Override
  12. public void actionPerformed(ActionEvent e) {
  13. TreeSet<Integer> t = new TreeSet<Integer>();
  14. t.addAll(listeners.keySet());
  15. Iterator<Integer> it = t.descendingIterator();
  16. while(it.hasNext()){
  17. int x = it.next();
  18. ArrayList<ActionListener> l = listeners.get(x);
  19. for(ActionListener a : l){
  20. a.actionPerformed(e);
  21. }
  22. }
  23. }
  24. public boolean deleteActionListener(ActionListener a){
  25. for(Integer x : listeners.keySet()){
  26. for(int i=0;i<listeners.get(x).size();i++){
  27. if(listeners.get(x).get(i) == a){
  28. listeners.get(x).remove(i);
  29. return true;
  30. }
  31. }
  32. }
  33. return false;
  34. }
  35. public void addActionListener(ActionListener a, int priority){
  36. deleteActionListener(a);
  37. if(!listeners.containsKey(priority)){
  38. listeners.put(priority,new ArrayList<ActionListener>());
  39. }
  40. listeners.get(priority).add(a);
  41. }
  42. }
15. Adjust column preferred width according to column's header cell text length
  1. /**
  2. * Adjust and configure the preferer size for each column of a table, according to
  3. * the length of each header cell's text. This methods does not ensure that the container
  4. * of the table can show all the text, because the panel can be too small.
  5. * @param table the table with the data model to set width
  6. * @param panel the JPanel containing the table
  7. * @param identifiers column header names
  8. */
  9. public static void configPreferredSizeForColumns(JTable table, JPanel panel, Vector<String> identifiers) {
  10. Graphics g = panel.getGraphics();
  11. int width = 0;
  12. for (int i=0; i < identifiers.size(); i++) {
  13. width = (int)g.getFontMetrics().getStringBounds(identifiers.get(i), g).getWidth();
  14. table.getColumnModel().getColumn(i).setPreferredWidth(width);
  15. }
  16. }
16. Adjust column width
  1. public void setAnchoColumnasLiq() {
  2. TableColumn columnaTabla = null;
  3. int anchoColumna = 0;
  4. for (int i = 0; i < table.getColumnCount(); i++) {
  5. columnaTabla = table.getColumnModel().getColumn(i);
  6. switch (i) {
  7. case 0:
  8. anchoColumna = 22;
  9. break;
  10. case 1:
  11. anchoColumna = 129;
  12. break;
  13. case 2:
  14. anchoColumna = 137;
  15. break;
  16. case 3: //razon social, el mas ancho
  17. anchoColumna = 215;
  18. break;
  19. case 4:
  20. anchoColumna = 97;
  21. break;
  22. case 5:
  23. anchoColumna = 40;
  24. break;
  25. case 6:
  26. anchoColumna = 111;
  27. break;
  28. default:
  29. break;
  30. }
  31. columnaTabla.setPreferredWidth(anchoColumna);
  32. columnaTabla.setResizable(false);
  33. }
  34. }

The maxisumWidth and minimumWidth are not so important. But preferredWidth is the base of resizing.

17. Remove all rows in a JTable

This is funny: you must keep removing the first row because the change is reflected inmediately in the table model. Due to the same reason, you must record the original row count, to avoid remove just half the rows. For example, the code below is not correct:

  1. /**
  2. * Clear the table model of a JTable, and call <code>fireTableDataChanged()</code>.
  3. */
  4. public static void clearJTableData(JTable table){
  5. TableModel model = table.getModel();
  6. if (model.getRowCount() > 0) {
  7. DefaultTableModel model1 = (DefaultTableModel)model;
  8. for (int i=0; i < model1.getRowCount(); i++) {
  9. model1.removeRow(i);
  10. }
  11. model1.fireTableDataChanged();
  12. }
  13. }

You must do:

  1. /**
  2. * Clear the table model of a JTable, and call <code>fireTableDataChanged()</code>.
  3. */
  4. public static void clearJTableData(JTable table){
  5. TableModel model = table.getModel();
  6. if (model.getRowCount() > 0) {
  7. DefaultTableModel model1 = (DefaultTableModel)model;
  8. //must preserve the model's vector's size, or only half of the rows will be removed.
  9. int size = model1.getRowCount();
  10. for (int i=0; i < size; i++) {
  11. model1.removeRow(0);
  12. }
  13. model1.fireTableDataChanged();
  14. }
  15. }
17. Set table header renderer

First, it's of type DefaultTableCellRenderer. There is a class sun.swing.table.TableCellHeaderRenderer, but it's not what we want.

And, to get a default renderer, you must call table.getTableHeader().getDefaultRenderer(), and pass it as parameter/use it in your inner class. It's for preserving all the border/color/etc. of default table header.

At last, use it and setText(value.toString()), or it will be blank.

Cast it to JLabel to setHorizontalAlignment(). Remember to return it and set it back to table.getTableHeader().setDefaultRenderer().

  1. final DefaultTableCellRenderer headerRenderer = (DefaultTableCellRenderer)table.getTableHeader().getDefaultRenderer();
  2. table.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer() {
  3. @Override
  4. public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
  5. DefaultTableCellRenderer r = headerRenderer;
  6. r.setFont(ARIAL_PLAIN_14);
  7. r.setText(value.toString()); //must set. Or the header is blank.
  8. switch (column) {
  9. case 0:
  10. case 2:
  11. case 3:
  12. r.setHorizontalAlignment(SwingConstants.CENTER);
  13. return r;
  14. default:
  15. r.setHorizontalAlignment(SwingConstants.LEADING);
  16. return r;
  17. }
  18. }
  19. });
18. Nimbus stripe table setting the background of blank area

The default behaviour of Nimbus stripped table is: first line white, second line light grey, but it's not good if there're less rows than the preferred size, and the area without data in a JScrollPane needs to be painted white. (If the line number is uneven, the last line is white, same as the background). But, with some changes, we can make a JTable paint a stripped table as below:

table.PNG?raw=true未知大小

We must know that:

  1. table.setBackground() will set all lines to be a color, ruining the stripped table style. It's useless in our case.
  2. The area without data in a JScrollPane belongs to the viewport, not the table. So we must set the background of pane.getViewport().setBackground(Color.WHITE);.
  3. And, setting color comes with the opacity. Only when it's opaque, it will paint the background color. So we have to set pane.getViewport().setOpaque(true).
  4. Set a renderer to the table helps to override the default behaviour of Nimbus L&F, thus getting what we want. The renderer must be present, but it can just do nothing. Reason unknown.
  5. The table must be set opaque to false. Or it will paint the white lines.
  6. setFillsViewportHeight(false/true) does not affect.
  1. package com.WindThunderStudio.JTableWithStripe;
  2. import java.awt.BorderLayout;
  3. import java.awt.Color;
  4. import java.awt.Component;
  5. import java.awt.Dimension;
  6. import javax.swing.BorderFactory;
  7. import javax.swing.JFrame;
  8. import javax.swing.JScrollPane;
  9. import javax.swing.JTable;
  10. import javax.swing.SwingUtilities;
  11. import javax.swing.UIManager;
  12. import javax.swing.table.DefaultTableCellRenderer;
  13. import javax.swing.table.DefaultTableModel;
  14. public class JTableWithStripe extends JFrame {
  15. class CustomRenderer extends DefaultTableCellRenderer {
  16. @Override
  17. public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
  18. int row, int column) {
  19. // TODO Auto-generated method stub
  20. Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
  21. return c;
  22. }
  23. }
  24. public JTableWithStripe() {
  25. begin();
  26. }
  27. private void begin() {
  28. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  29. setLayout(new BorderLayout());
  30. setBackground(Color.green);
  31. try {
  32. UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
  33. } catch (Exception e) {
  34. }
  35. JTable table = new JTable();
  36. table.setFillsViewportHeight(true);
  37. table.setOpaque(false);
  38. table.setBorder(BorderFactory.createLineBorder(Color.RED, 2));
  39. DefaultTableModel model = new DefaultTableModel();
  40. model.setColumnIdentifiers(new String[] {"Class", "Age", "Name"});
  41. model.addRow(new String[] {"A", "43", "Nostrom"});
  42. model.addRow(new String[] {"B", "24", "Alicia"});
  43. model.addRow(new String[] {"C", "28", "Sulaco"});
  44. model.addRow(new String[] {"", "", ""});
  45. model.addRow(new String[] {"", "", ""});
  46. model.addRow(new String[] {"", "", ""});
  47. model.addRow(new String[] {"", "", ""});
  48. model.addRow(new String[] {"", "", ""});
  49. table.setModel(model);
  50. // table.setBackground(Color.YELLOW);
  51. table.setDefaultRenderer(Object.class, new CustomRenderer());
  52. JScrollPane pane = new JScrollPane(table);
  53. pane.getViewport().setPreferredSize(new Dimension(500, 300));
  54. // pane.getViewport().setBackground(Color.MAGENTA);
  55. pane.getViewport().setBackground(Color.WHITE);
  56. pane.getViewport().setOpaque(true);
  57. pane.setPreferredSize(new Dimension(500, 300));
  58. pane.setOpaque(true);
  59. add(pane, BorderLayout.CENTER);
  60. pack();
  61. setLocationRelativeTo(null);
  62. setVisible(true);
  63. System.out.println(table.getBackground());
  64. System.out.println(pane.getViewport().getBackground());
  65. }
  66. public static void main(String[] args) {
  67. SwingUtilities.invokeLater(new Runnable() {
  68. @Override
  69. public void run() {
  70. JTableWithStripe frame = new JTableWithStripe();
  71. }
  72. });
  73. }
  74. }
19. ChangeListener fires when mouse enters

Although it seesm odd, a ChangeListener fires when the mouse cursor enters the component, without clicking it. Apparently, it detects mouseEntered() too, without the API mentioning it.

If you only want to detect the click, use ItemListener.

20. JFrame with L&F other than Java default Metal will increase 10 pixels if set to resizable

This is because a JFrame has a border space around it for drawing resizing handler when set to resizable. When it is not resizable, it looks like an extra border; when it is resizable, a line is drawn onto it to indicate it is draggable. It has a size of 10 pixels wide.

Java Metal L&F draws it explicitly, while all other L&F does not. What they do, is: when a JFrame is set to be resizable, it omit it and change the frame's size to accomodate to original size. That's why we see the size change. We can reproduce the bug by setting the L&F to be Metal, and setDefaultLookAndFeelDecorated(true).

Code to reproduce the case:(play with L&F to see the difference)

  1. import java.awt.BorderLayout;
  2. import java.awt.Color;
  3. import java.awt.Dimension;
  4. import java.awt.event.ActionEvent;
  5. import java.awt.event.ActionListener;
  6. import java.awt.event.ComponentEvent;
  7. import java.awt.event.ComponentListener;
  8. import javax.swing.BorderFactory;
  9. import javax.swing.JButton;
  10. import javax.swing.JFrame;
  11. import javax.swing.JTextArea;
  12. import javax.swing.SwingUtilities;
  13. import javax.swing.UIManager;
  14. import javax.swing.plaf.metal.MetalLookAndFeel;
  15. import javax.swing.plaf.nimbus.NimbusLookAndFeel;
  16. public class TitleHeightChange extends JFrame {
  17. private static final String lp = System.lineSeparator();
  18. public TitleHeightChange() {
  19. begin();
  20. }
  21. private void begin() {
  22. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  23. setDefaultLookAndFeelDecorated(true);
  24. try {
  25. // UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
  26. UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
  27. // UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
  28. // UIManager.setLookAndFeel(new MetalLookAndFeel());
  29. // UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
  30. } catch (Exception e) {
  31. }
  32. final JFrame frame1 = new JFrame();
  33. frame1.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  34. frame1.setTitle("Frame1");
  35. frame1.setLayout(new BorderLayout());
  36. final JTextArea area1 = new JTextArea();
  37. area1.setBorder(BorderFactory.createLineBorder(Color.darkGray,1));
  38. frame1.add(area1, BorderLayout.CENTER);
  39. frame1.addComponentListener(new ComponentListener() {
  40. @Override
  41. public void componentShown(ComponentEvent e) {
  42. // TODO Auto-generated method stub
  43. area1.setText("frame height: " + frame1.getBounds().height + lp
  44. + "frame width: " + frame1.getBounds().width + lp
  45. + "content pane height: " + frame1.getContentPane().getBounds().height + lp
  46. + "content pane width: " + frame1.getContentPane().getBounds().width + lp
  47. + "title bar height: " + (frame1.getBounds().height-frame1.getContentPane().getBounds().height) + lp
  48. + "isResizable() value: false");
  49. }
  50. @Override
  51. public void componentResized(ComponentEvent e) {
  52. // TODO Auto-generated method stub
  53. }
  54. @Override
  55. public void componentMoved(ComponentEvent e) {
  56. // TODO Auto-generated method stub
  57. }
  58. @Override
  59. public void componentHidden(ComponentEvent e) {
  60. // TODO Auto-generated method stub
  61. }
  62. });
  63. frame1.setResizable(false);
  64. frame1.pack();
  65. frame1.setBounds(0, 0, 300, 300);
  66. frame1.setLocationRelativeTo(null);
  67. frame1.setVisible(true);
  68. final JFrame frame2 = new JFrame();
  69. frame2.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  70. frame2.setTitle("Frame2");
  71. frame2.setLayout(new BorderLayout());
  72. final JTextArea area2 = new JTextArea();
  73. area2.setBorder(BorderFactory.createLineBorder(Color.darkGray,1));
  74. frame2.add(area2, BorderLayout.CENTER);
  75. frame2.addComponentListener(new ComponentListener() {
  76. @Override
  77. public void componentShown(ComponentEvent e) {
  78. // TODO Auto-generated method stub
  79. area2.setText("frame height: " + frame2.getBounds().height + lp
  80. + "frame width: " + frame2.getBounds().width + lp
  81. + "content pane height: " + frame2.getContentPane().getBounds().height + lp
  82. + "content pane width: " + frame2.getContentPane().getBounds().width + lp
  83. + "title bar height: " + (frame2.getBounds().height-frame2.getContentPane().getBounds().height) + lp
  84. + "isResizable() value: true");
  85. }
  86. @Override
  87. public void componentResized(ComponentEvent e) {
  88. // TODO Auto-generated method stub
  89. }
  90. @Override
  91. public void componentMoved(ComponentEvent e) {
  92. // TODO Auto-generated method stub
  93. }
  94. @Override
  95. public void componentHidden(ComponentEvent e) {
  96. // TODO Auto-generated method stub
  97. }
  98. });
  99. frame2.setResizable(true);
  100. frame2.pack();
  101. frame2.setBounds(0, 0, 300, 300);
  102. frame2.setLocationRelativeTo(null);
  103. frame2.setVisible(false);
  104. setLayout(new BorderLayout());
  105. JButton b = new JButton();
  106. b.setText("switch");
  107. b.addActionListener(new ActionListener() {
  108. @Override
  109. public void actionPerformed(ActionEvent e) {
  110. // TODO Auto-generated method stub
  111. if (frame1.isVisible()) {
  112. frame1.setVisible(false);
  113. frame2.setVisible(true);
  114. } else {
  115. frame1.setVisible(true);
  116. frame2.setVisible(false);
  117. }
  118. }
  119. });
  120. b.setPreferredSize(new Dimension(100, 30));
  121. b.setSize(new Dimension(100, 30));
  122. add(b, BorderLayout.CENTER);
  123. pack();
  124. setBounds(600, 700, 100, 30);
  125. setVisible(true);
  126. }
  127. public static void main(String[] args) {
  128. SwingUtilities.invokeLater(new Runnable() {
  129. @Override
  130. public void run() {
  131. TitleHeightChange frame = new TitleHeightChange();
  132. }
  133. });
  134. }
  135. }

The only way to fix, is to change the resizable window to be 10 pixels wider and higher to maintain the size. Cannot change the unresizable windows. Reason unknown.

21. JPanel remove() component needs revalidate() and repaint()

After removing an component already visible, we must revalidate() to tell the Layout Manager to allocate it, and repaint() to make it completely visible.

If we add another component in the same place, the same must be done to the new component, too.

22. JTree paint problem

If when adding nodes in to a JTree, we see paint problems(processing and paint are synchronizedly and new nodes are not painted, left in blank), we can add SwingUtilities.invokeAndWait() to force waiting for paint.

When inserting node, insertNodeInto will inform the listeners, so this part can be left safely.

At last, we may need to call model.reload() to repaint all nodes.

23. getText() of JTextPane adds extra blank lines if we touch its Document underneath

It is a bug I found:

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8180276

Custom class extending JTextPane to fix this problem:

  1. public class MyJTextPane extends JTextPane {
  2. /**
  3. * Append some text to this pane.
  4. * @param s
  5. */
  6. public void append(String s) {
  7. try {
  8. Document doc = this.getDocument();
  9. doc.insertString(doc.getLength(), s, this.getParagraphAttributes());
  10. } catch(BadLocationException e) {
  11. System.err.println(e);
  12. }
  13. }
  14. /**
  15. * Append some text and change line.
  16. * @param s
  17. */
  18. public void appendLine(String s) {
  19. try {
  20. Document doc = this.getDocument();
  21. doc.insertString(doc.getLength(), s + System.lineSeparator(), this.getParagraphAttributes());
  22. } catch(BadLocationException e) {
  23. System.err.println(e);
  24. }
  25. }
  26. @Override
  27. public String getText() {
  28. String string = "";
  29. try {
  30. string = this.getDocument().getText(0, this.getDocument().getLength());
  31. } catch (BadLocationException e) {
  32. System.err.println(e);
  33. }
  34. return string;
  35. }
  36. /**
  37. * Clear the text content.
  38. */
  39. public void clearText() {
  40. try {
  41. this.getDocument().remove(0, this.getDocument().getLength());
  42. } catch (BadLocationException e) {
  43. System.err.println(e);
  44. }
  45. }
  46. }
24. Customize JOptionPane dialog button text

Normally we use JOptionPane.showConfirmDialog to show a confirm/cancel dialog. But the text in the buttons are in English.

To customize them with other texts, we use:

int javax.swing.JOptionPane.showOptionDialog(Component parentComponent, Object message, String title, int optionType, int messageType, Icon icon, Object[] options, Object initialValue) throws HeadlessException

For example, to make a centered dialog with two buttons, whose text are "Good!" and "Bad...", I have:

  1. String[] options = new String[]{"Good!", "Bad..."};
  2. int status = JOptionPane.showOptionDialog(
  3. null, // parent of dialog. Can be null and is centered.
  4. "Do you want some milk?", //dialog question message
  5. "A silly question", //dialog title
  6. JOptionPane.OK_CANCEL_OPTION, //dialog type
  7. JOptionPane.QUESTION_MESSAGE, //message type
  8. null, //question mark icon, null for default question mark
  9. options, //different text in buttons
  10. options[0]); //default selected button
25. Show all installed Look&Feel

Code:

  1. for (LookAndFeelInfo lf: UIManager.getInstalledLookAndFeels()) {
  2. System.out.println(lf.getName());
  3. System.out.println(lf.getClassName());
  4. }

Result: (Windows 10 Home, Java 1.8.111):

Metal
javax.swing.plaf.metal.MetalLookAndFeel
Nimbus
javax.swing.plaf.nimbus.NimbusLookAndFeel
CDE/Motif
com.sun.java.swing.plaf.motif.MotifLookAndFeel
Windows
com.sun.java.swing.plaf.windows.WindowsLookAndFeel
Windows Classic
com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel

To set a l&f:

  1. try {
  2. UIManager.setLookAndFeel(new MetalLookAndFeel());
  3. } catch (UnsupportedLookAndFeelException e) {
  4. log.error("Look&Feel not found: ", e);
  5. }

Some Look and feel exists as class, like Nimbus and Metal. For Windows L&F, we need class name.

  1. try {
  2. UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
  3. } catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
  4. log.error("Look&Feel not found: ", e);
  5. }
26. Set scaled icon
ImageIcon icon = new ImageIcon(Constantes.ICONO_RENDER_SEGURIDAD_SOCIAL);
lblSegSocial.setIcon(new ImageIcon(icon.getImage().getScaledInstance(113, 35, Image.SCALE_SMOOTH)));
27. Change JTabbedPane tab font and text

Use setFont() on the JTabbedPane to change layer title font. Not on layers.


II. MigLayout

1. debug

red line: cells
blue line: components
green line: preferred size (??)

2. width/height too large:

It depends on the biggest component it holds. Please, check if there're some big components, not just check one line/one column, but also somewhere else. **In JTabbedPane, some big tab will increase the size of other tabs. And in CardLayout, also. Some card will increase the total size of the container. **

3. add cell constraints:

"cell 0 1", first col, then row.
"cell 0 1 2 3", col, row, width, height.

4. button right alig:

Don't do anything about alignment in col/row constraint. "align left" not working. Instead, when adding the component, add gapleft push. There must be a gap on the left, though. But setting insets will do it.

If, we have more then 1 button in a row, even if we specify the size of every cell width, and only add component cons like gapleft push, will fail: the row will be divided into cells with equal width to allocate elements. We must add []push[] in the column constraint.

5. refresh the total size of all components:
  1. Don't touch the contentPane. Add things to it.
  2. Avoid hardcoding sizes in the col/row constraint. But you can add size in component constraints(when adding them). Do it only when there's JTable/JTabbedPane/JTextfield, etc.(Components that don't have fixed size. ) JLabel will be shrink to the text size. JButton also. But JScrollPane will need a size(when adding them or in col/row constraints), and JTabbedPane also. JTextfield needs a width.
  3. After adding all the components, if not necessary, don't setBounds(). Let MigLayout handle it. If necessary, just assign a fixed width and compact the height:
  1. setBounds(0, 0, 1000, getSize().height);
  2. //this will prevent the elements shrink to 0 width, but pack them with proper height.

The reason why we do this, is that the textfields usually must extend horizontally even without content, but the height of tables cannot extend to maximum. Using this, all component will extend horizontally and shrink vertically, table will be their preffered height.

6. split and alignment

split 2 will divide a cell into 2, with equal width, default align (left). If adding comps into the first cell with grow, the first cell will be larger than needed, larger than the half size, and the second will be pushed to the far right side. If you want the first cell shrink to proper size and the two components sticking together, don't use grow.

7. add comps with relative position

To add an element with relative position, we have pos x y [x2] [y2] comp constraints.

  1. add(btnGuardarConfig, "pos (tabsPane.x+tabsPane.w-120) (tabsPane.y), grow");
  2. //add it to the right top corner above. 120 is inset to right.
  3. //if x2 and y2 are not present, they will be taken as null and the comp will be preferred size.

When to assign bounds to components, is decided by the manager layout. In MigLayout, this is done after pack() I guess. So, when adding elements, pack() is not done, and they will have a size of 0*0. So, the relative positioning like this will not work without an actual size of the comps with id tabsPane. What we can do is add a size to the tabsPane when adding it:

  1. add(tpConfiguracion, "cell 0 1, grow, id tabsPane, w :" + frameWidth + ":, h :" + frameHeight + ":");
  2. //note the ':' part. Here we only set the preferred size. "min:pref:max"
8. Auto resizing and percentages in constraints

If you want to change col/row size when resizing, you must specify the percentage of column width or row height when defining the layout. Also, no ComponentListener implementing ComponentResized() should be added.

And, when calculating the percentages, make sure not to make the sum 100%. Leave some spaces for insets.

Add fill, grow in the column/row constraint to make some column/row occupy the extra space when the window resizes, especially when maximized.

9. Cell alignment and grow

If we add two components in a cell like:

  1. panel.add(label, "align 10%");
  2. panel.add(textField, "grow");

The field will grow and the label will not have space on the left. It just will be pushed to the left. So we must define the left gap and the push priority group (the gap higher and the textField lower.) Or, just make the left gap push, and textfield with some fixed width.

10. MigLayout handles the maximize behaviour, if set properly

In the new CEL in the WinCreta HEAD and in the branch UNI_BUZ, the CEL can handle the location and size of all elements when the windows is maximized: ocupy the whole width, table increases its size while other panels doesn't change the height. Here is the code:

  1. /**
  2. * Clase de Panel para mostrar informaciones detalladas del nuevo tipo de
  3. * XML: CEL.
  4. *
  5. * @author 99GU6879
  6. *
  7. */
  8. public class PanelConsultaEstadoLiquidacion extends JFrame {
  9. public PanelConsultaEstadoLiquidacion(File f) {
  10. xmlFile = f;
  11. initialize();
  12. }
  13. public void initialize() {
  14. primeraBusqueda = true;
  15. PanelImagen panelImagen = new PanelImagen();
  16. panelImagen.setLayout(new MigLayout("insets 0 0 0 0, fillx, debug", "[center]", "[]5[]5[300:400:800, grow, fill]5[]5[::30]"));
  17. getContentPane().add(panelImagen);
  18. setPreferredSize(new Dimension(panelWidth,panelHeight));
  19. if (Gestor_Interface.contenedorLiquidacionDirecta != null) {
  20. setBounds(Gestor_Interface.getContenedorLiquidacionDirecta().getX(), Gestor_Interface.getContenedorLiquidacionDirecta().getY(), 1190, 600);
  21. } else {
  22. setBounds(Gestor_Interface.getContenedorCRETA().getX(), Gestor_Interface.getContenedorCRETA().getY(), 1190, 600);
  23. }
  24. // pane de cabecera, linea 0, para tabla de resumen.
  25. panelCabecera = new JPanel();
  26. panelCabecera.setLayout(new MigLayout("insets 2 2 2 2, fillx, debug",
  27. "[15%, grow]5push[20%, grow]5push[15%, grow]5push[40%, grow]5[10%, center]",
  28. "[20!]5[25!]5[25!]"));
  29. panelCabecera.setBorder(null);
  30. lblInfoConsultas = new JLabel("Consulta Estado de Liquidaciones");
  31. panelCabecera.add(lblInfoConsultas, "cell 0 0, span 5, grow");
  32. // Tabla de resumen de las liquidaciones, la superior
  33. panelCabecera.add(setUnifiedStyle(Constantes.LABEL_TITLE, "lblResumenAuto", "Autorizado: "), "cell 0 1, grow");
  34. panelCabecera.add(setUnifiedStyle(Constantes.LABEL_CONTENT, "lblResumenAutoResult", ""), "cell 1 1, grow");
  35. panelCabecera.add(setUnifiedStyle(Constantes.LABEL_TITLE, "lblResumenRazonSocial", "Raz\u00F3n Social: "), "cell 2 1, grow");
  36. panelCabecera.add(setUnifiedStyle(Constantes.LABEL_CONTENT, "lblResumenRazonSocialResult", ""), "cell 3 1, grow");
  37. panelCabecera.add(setUnifiedStyle(Constantes.LABEL_TITLE, "lblResumenPeriodo", "Periodo Presentaci\u00F3n: "), "cell 0 2, grow");
  38. panelCabecera.add(setUnifiedStyle(Constantes.LABEL_CONTENT, "lblResumenPeriodoResult", ""), "cell 1 2, grow");
  39. panelCabecera.add(setUnifiedStyle(Constantes.LABEL_TITLE, "lblResumenFechaHora", "<html>Fecha y Hora <br> de Generaci\u00F3n: </html>"), "cell 2 2, grow");
  40. panelCabecera.add(setUnifiedStyle(Constantes.LABEL_CONTENT, "lblResumenFechaHoraResult", ""), "cell 3 2, grow");
  41. btnLimpiar = new JButton();
  42. btnLimpiar.setBounds(900, 30, 60, 30);
  43. panelCabecera.add(btnLimpiar, "cell 4 1 1 2, center");
  44. panelImagen.add(panelCabecera, "cell 0 0, grow, h 90!");
  45. Object[][] filtroData = new Object[1][7];
  46. DefaultTableModel model = new DefaultTableModel(filtroData,
  47. cabeceraTablaParcial);
  48. tbFiltro = new JTable(model);
  49. tbFiltro.setBounds(5, 90, 970, 40);
  50. tbFiltro.setPreferredSize(new Dimension(970,40));
  51. tbFiltro.setPreferredScrollableViewportSize(tbFiltro.getPreferredSize());
  52. spFiltro = new JScrollPane(tbFiltro, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
  53. spFiltro.setViewportView(tbFiltro);
  54. spFiltro.setBackground(new Color(0, 0, 0, 0));
  55. spFiltro.getViewport().setOpaque(false);
  56. spFiltro.setBorder(null);
  57. spFiltro.setBounds(5, 95, 970, 40);
  58. panelImagen.add(spFiltro, "cell 0 1, grow, h 50!");
  59. Object[][] filtroData2 = new Object[1][14];
  60. tbDetalleLiqs = new JTable(model2);
  61. tbDetalleLiqs.setSize(new Dimension(1000, 420));
  62. tbDetalleLiqs.setPreferredScrollableViewportSize(new Dimension(1000, 420));
  63. tbDetalleLiqs.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
  64. // Panel que contiene la tabla de los detalles de las liquidaciones
  65. spDetalleLiqs = new JScrollPane();
  66. spDetalleLiqs.setBounds(5, 155, 970, 400);
  67. spDetalleLiqs.setViewportView(tbDetalleLiqs);
  68. spDetalleLiqs.getViewport().setOpaque(false);
  69. panelImagen.add(spDetalleLiqs, "cell 0 2, grow");
  70. // Pane totalizador
  71. panelTotalizador = new JPanel();
  72. panelTotalizador.setOpaque(false);
  73. panelTotalizador.setBounds(5, 560, 970, 65);
  74. panelTotalizador.setLayout(new MigLayout("insets 2 2 2 2, fill, debug", "[15%]3[15%]push[15%]3[15%]push[15%]3[15%]", "[]2[]" ));
  75. // Totalizadores
  76. panelTotalizador.add(setUnifiedStyle(Constantes.LABEL_TITLE, "lblTotalCCC", "Total CCC: "), "cell 0 0, grow");
  77. panelTotalizador.add(setUnifiedStyle(Constantes.LABEL_CONTENT, "lblTotalCCCResult", ""), "cell 1 0, grow");
  78. panelTotalizador.add(setUnifiedStyle(Constantes.LABEL_TITLE, "lblTotalLiqs", "Tot. Liquidaciones: "), "cell 2 0, grow");
  79. panelTotalizador.add(setUnifiedStyle(Constantes.LABEL_CONTENT, "lblTotalLiqsResult", ""), "cell 3 0, grow");
  80. panelTotalizador.add(setUnifiedStyle(Constantes.LABEL_TITLE, "lblTotalImporte", "Tot. Importe: "), "cell 4 0, grow");
  81. panelTotalizador.add(setUnifiedStyle(Constantes.LABEL_CONTENT, "lblTotalImporteResult", ""), "cell 5 0, grow");
  82. panelTotalizador.add(setUnifiedStyle(Constantes.LABEL_TITLE, "lblTotalTramos", "Tot. Tramos: "), "cell 0 1, grow");
  83. panelTotalizador.add(setUnifiedStyle(Constantes.LABEL_CONTENT, "lblTotalTramosResult", ""), "cell 1 1, grow");
  84. panelTotalizador.add(setUnifiedStyle(Constantes.LABEL_TITLE, "lblTotalTramoCal", "Tot. Tramos Cal: "), "cell 2 1, grow");
  85. panelTotalizador.add(setUnifiedStyle(Constantes.LABEL_CONTENT, "lblTotalTramoCalResult", ""), "cell 3 1, grow");
  86. panelTotalizador.add(setUnifiedStyle(Constantes.LABEL_TITLE, "lblTotalTramoNoCal", "Tot. Tramos No Cal: "), "cell 4 1, grow");
  87. panelTotalizador.add(setUnifiedStyle(Constantes.LABEL_CONTENT, "lblTotalTramoNoCalResult", ""), "cell 5 1, grow");
  88. panelImagen.add(panelTotalizador, "cell 0 3, grow, h 65!");
  89. btnSalir = new JButton("");
  90. panelImagen.add(btnSalir, "cell 0 4, gapleft push, w 130!");
  91. setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  92. setLocationByPlatform(true);
  93. setResizable(true);
  94. pack();
  95. setBounds(0, 0, 1000, getSize().height);
  96. setLocationRelativeTo(null);
  97. //to show the content and then show the windows
  98. showCEL(xmlFile);
  99. setVisible(true);
  100. }
11. MigLayout and JSplitPane

If we don't specify any size when adding the components and the two panels, the first panel (on the left/top) will be bigger than it should be and the total size of windows will increase.

To avoid this, we must specify the height of top panel/the width of left panel. For example, in Siltra I have set the width of all buttons/textfields of PanelConsultaLiquidaciones to give the left panel a fixed width, and the windows goes back to normal. If not, it's wider than it should be. No extra setBounds() setSize() is used.

12. Make some column/row ocupy the extra space if the window is maximized

In the row/column constraint, we add fill, grow. Both.

If some panel has failed, and is a Card, check if the panel with CardLayout has done this. The container panel control the total size of extra space all the children can ocupy.

13. JLabel with html text always occupy the whole cell length

MigLayout has problem calculating the length if a JTextPane enables text wrapping, or a JLabel has html text in it to enable inside-label wrapping. You can specify width when adding. w 200! and w :200: both do the trick.

14. JFrame maximized and cannot return to original size

In Siltra, when you maximized the frame and return to original size, the width is correct but some buttons are hidden at the bottom. Clicking at the border to adjust a little and all is good. (Panels are almost with MigLayout, those without it has a smaller preferred size and the frame has ComponentListener. JTabbedPane's tabs too.)

I suspect it to be a MigLayout problem: when returning to normal size, all the panels decrease and no time to calculate the proper preferred size for all. Some panels stay behind and have a larger size. But setting all the panels a smaller preferred size doesn't work. (Overriding the getPreferredSize())

So I override the frame's preferred size, add 80 pixels to the height and all good. Reason unknown.

15. If some panel is too big and cut off, don't panic

In PanelMensajesInforme, the panelFiltro is too high/long and the first time the panel is shown, the split pane containing it has no bottom border (cut off). I changed some rows' gap to be 0 in the panelFiltro and the split pane is no longer too high. Just check every panel's bounds in a container. If some rows/columns are defined like:

  1. [][][]

the gap is not 0. It's 2 or something. To set it to 0 you must set it explicitly.

  1. []0[]0[]

And, defining line height/column width with percentages and pixels(mixing these two) may also be a problem. In the layout constraints, define them with pixeles only. [7%]::10:push[25!] will cause problem. Just use [25!]::10:push[25!].

16. JTextArea with line wrap will grow to maximum size if added with grow

JTextArea will reset its minimum size every time its container changes size. It causes problems because it will increase size every time its container's size changes if is added with grow. But without grow, it will shrink.

To make it occupy all extra space and respect container's size control, e.g., to ocuppy only 50% of total width, we must add wmin 0 to prevent minimum size change.

https://stackoverflow.com/questions/2475787/miglayout-jtextarea-is-not-shrinking-when-used-with-linewrap-true/6022219#6022219


III. AWT

IV. Misc

1. JTextField with mask
  1. package gui.paneles.elementos;
  2. import java.awt.Color;
  3. import java.awt.event.FocusEvent;
  4. import java.awt.event.FocusListener;
  5. import javax.swing.JFormattedTextField;
  6. import org.apache.commons.lang.StringUtils;
  7. /**
  8. * The subclass of <code>JFormattedTextField</code> for passing a <code>String</code>
  9. * as the colored format hint.
  10. *
  11. * @author 99GU6879
  12. *
  13. */
  14. public class FormattedTextFieldWithHint extends JFormattedTextField {
  15. /**
  16. *
  17. */
  18. private static final long serialVersionUID = 1L;
  19. public static final Color hintGrey = new Color(195,195,195);
  20. public static final Color textBlack = Color.BLACK;
  21. public static final String hint_mmaaaa = "mm/aaaa";
  22. private String hint;
  23. public String getHint() {
  24. return hint;
  25. }
  26. public void setHint(String hint) {
  27. this.hint = hint;
  28. }
  29. public FormattedTextFieldWithHint() {
  30. super();
  31. this.addFocusListener(new FocusListenerForHint());
  32. }
  33. public FormattedTextFieldWithHint(String hint) {
  34. this(); //will add focusListener as well.
  35. this.hint = hint;
  36. this.setText(hint);
  37. resetPlaceholder();
  38. }
  39. public void resetPlaceholder(){
  40. if (this.getText().equals(hint)){
  41. this.setForeground(hintGrey);
  42. } else {
  43. this.setForeground(textBlack);
  44. }
  45. }
  46. public void readyForInput(){
  47. this.selectAll();
  48. this.setForeground(textBlack);
  49. }
  50. /**
  51. * Abstract ancestor for all the focus listeners that
  52. * want to manipulate the behaviours about the hints.
  53. */
  54. public class FocusListenerForHint implements FocusListener {
  55. @Override
  56. public void focusGained(FocusEvent e) {
  57. if (e.getSource() instanceof JFormattedTextField) {
  58. JFormattedTextField field = (JFormattedTextField) e.getSource();
  59. field.setForeground(textBlack);
  60. if (field.getText().trim().equals(hint)) {
  61. field.setText(""); //if only hint is present, make it dissapear.
  62. } else {
  63. readyForInput();//if some other text is present.
  64. }
  65. }
  66. }
  67. @Override
  68. public void focusLost(FocusEvent e) {
  69. if (e.getSource() instanceof JFormattedTextField) {
  70. JFormattedTextField field = (JFormattedTextField) e.getSource();
  71. if (StringUtils.isBlank(field.getText())) {
  72. field.setForeground(hintGrey); //change color back to grey.
  73. field.setText(hint); //if blank, make it back to hint.
  74. }
  75. }
  76. }
  77. }
  78. }
2. grow 30 vs grow 30%

grow 30 is different from grow, 30%.

According to http://stackoverflow.com/questions/23001696/miglayout-column-constraint#answer-23028022, the former is about eagerness of occupying the space left out of the component(will occupy 30% of the blank space between two components), while grow, 30% means "occupy all the space which is left, and this col/row is 30% of the total width/height".

C. I/O

1. Java File path starting point, and relative/absolute path

When talking about Java File path, there are relative ones and absolute ones.
Absolute ones are those begining with drive (in Windows) and / (in Linux). So below are two absolute paths:

C:\Windows\system32\test.txt
\home\usr\myDir\result.txt

Relative paths are those starting from the working directory, represented by .. It is often the root path of your Java project. So new File("test.txt") is the same as new File(".\\test.txt");.

From Javadoc:

By default the classes in the java.io package always resolve relative pathnames against the current user directory. This directory is named by the system property user.dir, and is typically the directory in which the Java virtual machine was invoked.

If you have a Maven project like this:

MyProject
    └ src
       └ main
           └ java
               └ com.package.Clazz
           └ resources
                 └ settings.properties

You can access settings.properties by this line:

File f = new File("src\main\resources\settings.properties");

2. Get all files recursively with Java 7 NIO

Old ways in Java

D. String

1. split(str) cut off trailing empty elements

If we have dd/dd///, and we use str.split("/"), we will have:

  1. {"dd", "dd"};

instead of

  1. {"dd", "dd", "", "", ""}

Because split(s) will cut off all the empty elements at last.

If we want to keep them, use str.split("/", -1). (-1can be any negative value).

http://stackoverflow.com/questions/14602062/java-string-split-removed-empty-values

E. Date

1. Leap year is best detected with regex and SimpleDateFormat

The SimpleDateFormat takes into consideration the time the Gregorian calendar is introduced (year 1582). Before that, a year divided into 4 is a leap year. So, year 1000 is a leap year, but 1700 is not.

So, for SimpleDateFormat, 29/02/1400 is a valid date, while 29/02/1700 is not. (if setLenient(false). If this is false, the formatter will not convert 32 of January into 1 of February)

With regex, we can refine the pattern. To test if a String matched the pattern ##/##/#### (# for a number):

  1. Pattern p = Pattern.compile("\\d{2}/\\d{2}/\\d{4}");
  2. Matcher m = p.matcher(string);
  3. if (m.matches()) {
  4. return true;
  5. }

For more information about greedy, reluctant and prossessive quantifier, see here.

F. Number

1. Parse a String to Integer/Long: too big

The max value of an Integer is , 2147483647 and min value is , -2147483648. If we don't know if the String parsed is in this range:

  1. try {
  2. Integer i = Integer.parseInt(s);
  3. result = f.format(i / 100);
  4. } catch (NumberFormatException e) {
  5. Long l = Long.parseLong(s);
  6. result = f.format(l / 100);
  7. }

2. NumberFormat

With only NumberFormat we can format the number, if the Locale, group divider, etc. are set. But, if we want to keep the fraction part, we must take care to convert the number first into double, then divide to 100. See the basic part.

  1. /**
  2. * Formatear el literal en formato de numeros segun el Locale de Espana.
  3. *
  4. * @param s el literal a parsear
  5. * @param isInteger si se parsea el valor como Integer. Si no, lo parsea como double de dos digitos de decimal.
  6. * @return el numero parseado. "1234567" -> "1.234.567". "1234.56" -> "1.234,56".
  7. */
  8. private String formatWithLocale(String s, boolean isInteger) {
  9. String result = "";
  10. try {
  11. NumberFormat f = NumberFormat.getInstance(new Locale("es", "ES"));
  12. f.setGroupingUsed(true);
  13. if (isInteger) {
  14. f.setMaximumFractionDigits(0);
  15. f.setMinimumFractionDigits(0);
  16. f.setParseIntegerOnly(true);
  17. try {
  18. Integer i = Integer.parseInt(s);
  19. result = f.format(i);
  20. } catch (NumberFormatException e) {
  21. Long l = Long.parseLong(s);
  22. result = f.format(l);
  23. }
  24. } else { //para double. El parametro ya tiene dos decimales.
  25. f.setMaximumFractionDigits(2);
  26. f.setMinimumFractionDigits(2);
  27. f.setParseIntegerOnly(false);
  28. try {
  29. Double i = Double.parseDouble(s);
  30. result = f.format(i);
  31. } catch (NumberFormatException e) {
  32. Long l = Long.parseLong(s);
  33. result = f.format(l);
  34. }
  35. }
  36. } catch (Exception e) {
  37. throw new RuntimeException(e);
  38. }
  39. return result;
  40. }

II. Java EE

A. Maven

1. 下载Maven并安装到本地,取代Eclipse内部自带的Maven

解压,并把Maven根目录下的bin添加到路径。

2. 下载m2e插件,集成Eclipse自带的maven

在marketplace里面搜索m2e插件,下载并安装。我装了两个:

安装后重启。并在Maven的run configuration里面,在Maven Runtime里选择新装的Maven作为compiler,代替Embedded。

3. 新建一个Maven工程,而不是把现有项目转换为Maven工程

否则在pom.xml里面的<build>部分会出错。如果找不到maven-compiler-plugin,删除<build>部分。

4. 解决-source-target和目前的代码的运行时不相符问题

比如,使用switch-case时,用String作key直到1.7才支持,但Mavenmaven-compiler-plugin的设置默认支持1.5。显示为用-X开关得到的debug信息中,含有-source 1.7 -target 1.7的字样。

错误信息为:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project SystemTrayAlarm: Compilation failure
[ERROR] /D:/desarrollo/workspace_NEW/SystemTrayAlarm/src/main/java/com/windthunderstudio/logic/util/I18N_Manager.java:[27,20] strings in switch are not supported in -source 1.5
[ERROR]   (use -source 7 or higher to enable strings in switch)
[ERROR] -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project SystemTrayAlarm: Compilation failure
/D:/desarrollo/workspace_NEW/SystemTrayAlarm/src/main/java/com/windthunderstudio/logic/util/I18N_Manager.java:[27,20] strings in switch are not supported in -source 1.5

解决方法是:

https://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html

pom.xml加入:

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.apache.maven.plugins</groupId>
  5. <artifactId>maven-compiler-plugin</artifactId>
  6. <version>3.6.1</version>
  7. <configuration>
  8. <source>1.7</source>
  9. <target>1.7</target>
  10. </configuration>
  11. </plugin>
  12. </plugins>
  13. </build>

5. Force project encoding

如果不指定Encoding,则会有警告:

[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!

解决方法是:

https://maven.apache.org/general.html#encoding-warning

pom.xml中加入:

  1. <properties>
  2. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  3. </properties>

6. Use Maven only to download jars

We should use maven-dependancy-plugin. Add these lines to pom.xml:

  1. <plugin>
  2. <groupId>org.apache.maven.plugins</groupId>
  3. <artifactId>maven-dependency-plugin</artifactId>
  4. <configuration>
  5. <outputDirectory>
  6. [some-path]
  7. </outputDirectory>
  8. </configuration>
  9. </plugin>

Here, [some-path] can be absolute, like C:\mydir, or relative to usr.dir (project root), like main\java\resources\libs, or some placeholder, like ${project.build.directory}.

And run Maven task:

dependency:copy-dependencies

And all the jars will be downloaded and copied to the directory.

7. Solve "Maven dependencies" library not shown error

Normally, convert the project into Maven project, and run "Maven - update project" is good enough. If that does not work, you should try this:

Open the .classpath file, you will find something like this:

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
    <classpathentry kind="src" path="core/src/main/java"/>
    ......
    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
        <attributes>
            <attribute name="maven.pomderived" value="true"/>
        </attributes>
    </classpathentry>
    <classpathentry kind="output" path="bin"/>
    <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
        <attributes>
            <attribute name="maven.pomderived" value="true"/>
        </attributes>
    </classpathentry> 
</classpath>

In every <classpathentry> either of type src or con, make sure this paragragh is present:

<attributes>
    <attribute name="maven.pomderived" value="true"/>
</attributes>

The good, healthy .classpath file may contain something like <attribute name="optional" value="true"/>, that is not important. Don't forget to change <classpathentry /> to <classpathentry>xxx</classpathentry>, because now it has children.

After doing this, recompile with maven and clean/rebuild the project. You should be fine.

8. Fix multiple modules Maven project "cannot find symbol" maven compile error

In a multiply module Maven project, some modules may depend on code in another module. In this case, the build order of modules in the principal pom.xml does not matter, but in every module's pom.xml, you should add as dependency the other modules, and install the depended modules as jar in the local repo first.

For example, I have a project of 3 modules, A, B and C. B and C has their own pom.xml, so as A. The project also has a pom.xml. When I run clean compile in the project pom.xml, the compilation succeeds in B and C, but fails in A with errors like:

cannot find symbol, class: xxxxx (some class in B)
cannot find symbol, class: xxxxx (some class in C)

So, what we can do is:

  1. clean compile install on B.
  2. clean compile install on C.
  3. Add modules B and C in the pom.xml in A, like:
  1. <dependency>
  2. <groupId>com.company</groupId>
  3. <artifactId>B</artifactId>
  4. <version>1.0-SNAPSHOT</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.company</groupId>
  8. <artifactId>C</artifactId>
  9. <version>1.0-SNAPSHOT</version>
  10. </dependency>

and then clean compile install on A.
4. clean compile on the whole project.
Now all is good. Maven seems only goes to the local repo to find the jar as dependency, so install of B and C is necessary. Very bad idea, though, because I think it should detect the dependency even though no JAR is installed.

9. Cannot find main class when execute on the main class java file

Must change the output folder to target/classes. If there is not this folder, create it and then change the class location. If a project is a maven project, when running the main class, it will not find it under bin, but target/classes. This is Maven convention, but not pre-set when the project is converted to Maven project.

III. Web

A. HTML

  1. 居中对齐
  1. <p align="center">Some Text</p>
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注