Swing-布局管理器应用--WIN7上计算器的UI实现
学完了Swing布局管理器,为了加深理解我决定做一些UI的实现,那就从WIN7上的计算器开始吧!首先,我们来研究一下它的UI。该计算器的UI主要有3个,分别是标准型、科学型和程序员型,如下图所示。
标准型UI
科学型UI
程序员型UI
首先分析标准型UI:
标准型UI分析
该UI除菜单栏外,分两部分。考虑到它们在不同的UI中都会复用,我们将其分别使用screenPanel和standardPanel来进行实现。screenPanel没什么好说的,使用一个按钮独占整个面板,并设置按钮文字右对齐即可。为了实现按钮的充满效果,srceenPanel需要使用BorderLayout,并将按钮位置设置为CENTER。
standardPanel则是标准的GridBagLayout样式,“MC”按钮位置为(0,0),“=”按钮独占2行1列,“0”按钮独占1行2列,其余按钮各只占1行1列。可以使用一个二维数组来定义这些键位,并在for循环中添加这些按钮。
接下来分析科学型UI:
科学型UI分析
窗体的整体布局和layout不变,而且显示部分不变,复用screePanel即可。下部为一个mainPanel,它内含scitificFunctionPanel和standardNumPanel。而scitificFunctionPanel又内含一个angelPanel。mainPanel也采用GridBagLayout,位置分别位于(0,0)和(1,0)。当然也可以采用BorderLayout,这两个子面板分别放置在WEST和CENTER,那么这样有一个问题,全屏放大后缩放比例是不一样的,如下图:
使用BorderLayout时的UI放大效果图
而使用GridBagLayout就可以保证这两个子面板的缩放是完全平等的,缩放效果如下图:
使用GridBagLayout时的UI放大效果图
接下来分析程序员型UI:
程序员型UI分析
screenPanel保持不变,而mainPanel这次被划分成3部分,分别是binaryPanel、programFunctionPanel和standardNumPanel。它们分别使用GridBagLayout来实现。
bitPanel的布局分解如下:
bitPanel布局分析
整个界面可分割为32个bitPanel;其中,第0、2行的bitPanel由4个label组成(因为每一位数均具有独立的事件响应);第1、3行的bitPanel只包含1个label。
programFunctionPanel的布局分解如下:
programFunctionPanel布局分析
可见,除(0,0)和(0,3)的位置上各为1个占据3行1列的panel外,其余位置均为1个button。Panel内包含4个combobox。
好啦,到现在所有的布局都分析完毕啦。下面是最终效果图:
标准型效果
标准型放大效果
科学型效果
科学型放大效果
程序员型效果
程序员型放大效果
具体的代码:
CalculatorUI.java
import java.awt.BorderLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.SwingConstants; /* * 主UI */ public class CalculatorUI extends JFrame { JPanel contentPane; private JMenuBar menuBar = new JMenuBar();// 菜单栏 private JButton screenButton = new JButton("0");// 结果显示栏 String[] menuViewItemNames = { "标准型", "科学型", "程序员" }; String[] menuNames = { "查看", "编辑", "帮助" }; MenuItemHandler menuItemHandler = new MenuItemHandler(); public CalculatorUI() { // 设置窗体属性 setTitle("计算器"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); // 添加菜单栏和菜单 setJMenuBar(menuBar); for (String name : menuNames) { JMenu menu = new JMenu(name); menuBar.add(menu); } // “查看”菜单添加菜单项 for (String name : menuViewItemNames) { JMenuItem menuItem = new JMenuItem(name); menuItem.addActionListener(menuItemHandler); menuBar.getMenu(0).add(menuItem); } } public void setBasicPane() { System.out.println("setBasicFrame called"); // 设为窗体默认面板 contentPane = new JPanel(); contentPane.setLayout(new GridBagLayout()); setContentPane(contentPane); // 添加显示按钮 JPanel srceenPanel = new JPanel(); srceenPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); srceenPanel.setLayout(new BorderLayout()); srceenPanel.add(screenButton, BorderLayout.CENTER); screenButton.setHorizontalAlignment(SwingConstants.RIGHT);// 文字右对齐 // 添加显示面板 contentPane.add( srceenPanel, new GBC(0, 0).setFill(GridBagConstraints.BOTH).setWeight(100, 100)); } public void setStandardMode() { System.out.println("切换到标准型"); setTitle("计算机-标准型"); setBasicPane(); StandardNumPanel standardPanel = new StandardNumPanel(); getContentPane().add( standardPanel, new GBC(0, 1).setFill(GridBagConstraints.BOTH).setWeight(100, 100)); showFrame(); } public void setScitificMode() { System.out.println("切换到科学型"); setTitle("计算机-科学型"); setBasicPane(); JPanel mainPanel = new JPanel(); mainPanel.setLayout(new GridBagLayout()); ScitificFunctionPanel scitificFunctionPanel = new ScitificFunctionPanel(); StandardNumPanel standardNumPanel = new StandardNumPanel(); mainPanel.add( scitificFunctionPanel, new GBC(0, 0).setFill(GridBagConstraints.BOTH).setWeight(100, 100)); mainPanel.add( standardNumPanel, new GBC(1, 0).setFill(GridBagConstraints.BOTH).setWeight(100, 100)); getContentPane().add( mainPanel, new GBC(0, 1).setFill(GridBagConstraints.BOTH).setWeight(100, 100)); showFrame(); } public void setProgramerMode() { System.out.println("切换到程序员型"); setBasicPane(); setTitle("计算机-程序员型"); // 添加binaryPanel JPanel binaryPanel = new BinaryPanel(); getContentPane().add( binaryPanel, new GBC(0, 1).setFill(GridBagConstraints.BOTH).setWeight(100, 100).setInsets(5)); //构造mainPanel,使用ProgramFunctionPanel和StandardNumPanel填充 JPanel mainPanel = new JPanel(); mainPanel.setLayout(new GridBagLayout()); mainPanel.add(new ProgramFunctionPanel(), new GBC(0,0).setFill(GridBagConstraints.BOTH).setWeight(100, 100).setInsets(5)); mainPanel.add(new StandardNumPanel(), new GBC(1,0).setFill(GridBagConstraints.BOTH).setWeight(100, 100).setInsets(5)); //添加mainPanel getContentPane().add( mainPanel, new GBC(0, 2).setFill(GridBagConstraints.BOTH).setWeight(100, 100)); showFrame(); } public void calculateBinary() { } public void showFrame() { pack(); setVisible(true); } public static void main(String[] args) { // TODO Auto-generated method stub CalculatorUI frame = new CalculatorUI(); // frame.setScitificMode(); frame.setProgramerMode(); // frame.setStandardMode(); // frame.setSize(200, 200); // frame.setVisible(true); } class MenuItemHandler implements ActionListener { public void actionPerformed(ActionEvent e) { if (e.getSource() instanceof JMenuItem) { JMenuItem menuItem = (JMenuItem) e.getSource(); String name = menuItem.getText(); if (name != null && name.equals("标准型")) { setStandardMode(); } else if (name != null && name.equals("科学型")) { setScitificMode(); } else if (name != null && name.equals("程序员")) { setProgramerMode(); // System.out.println("切换到程序员"); } } } } class BitButtonHandler implements ActionListener { public void actionPerformed(ActionEvent e) { if (e.getSource() instanceof JButton) { JButton button = (JButton) e.getSource(); String text = button.getText(); String newText = text.equals("0") ? "1" : "0"; button.setText(newText); // 计算数值并更新显示屏 calculateBinary(); } } } }
StandardNumPanel.java
import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import javax.swing.JButton; import javax.swing.JPanel; public class StandardNumPanel extends JPanel { public StandardNumPanel() { // 设置窗体layout setLayout(new GridBagLayout()); // add buttons String[][] btnStrings = { { "MC", "MR", "MS", "M+", "M-" }, { "←", "CE", "C", "+-", "sqrt" }, { "7", "8", "9", "/", "%" }, { "4", "5", "6", "*", "1/x" }, { "1", "2", "3", "-", "=" }, { "0", "0", ".", "+", "=" } }; boolean isBtnEqualsNeedsAdded = true; boolean isBtnPlusNeedsAdded = true; for (int i = 0; i < btnStrings.length; i++) { for (int j = 0; j < btnStrings[0].length; j++) { if (btnStrings[i][j].equals("=") && isBtnEqualsNeedsAdded) { add(new JButton(btnStrings[i][j]), new GBC(j, i , 1, 2) .setFill(GridBagConstraints.BOTH).setInsets(3) .setWeight(100, 100)); isBtnEqualsNeedsAdded = false; continue; } if (btnStrings[i][j].equals("0") && isBtnPlusNeedsAdded) { add(new JButton(btnStrings[i][j]), new GBC(j, i , 2, 1) .setFill(GridBagConstraints.BOTH).setInsets(3) .setWeight(100, 100)); isBtnPlusNeedsAdded = false; continue; } add(new JButton(btnStrings[i][j]), new GBC(j, i , 1, 1) .setFill(GridBagConstraints.BOTH).setInsets(3) .setWeight(100, 100)); } } } public static void main(String[] args) { // TODO Auto-generated method stub } }
ScitificFunctionPanel.java
import java.awt.BorderLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JRadioButton; public class ScitificFunctionPanel extends JPanel { public ScitificFunctionPanel() { // 设置窗体layout setLayout(new GridBagLayout()); // 用于放置“度”、“弧度”、“梯度”这三个按钮 JPanel angelPanel = new JPanel(); BoxLayout boxLayout = new BoxLayout(angelPanel, BoxLayout.X_AXIS); angelPanel.setLayout(boxLayout); angelPanel.setBorder(BorderFactory.createEtchedBorder()); JRadioButton angelButton = new JRadioButton("度"); JRadioButton radianButton = new JRadioButton("弧度"); JRadioButton gradientButton = new JRadioButton("梯度"); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(angelButton); buttonGroup.add(radianButton); buttonGroup.add(gradientButton); angelPanel.add(angelButton); angelPanel.add(Box.createHorizontalGlue()); angelPanel.add(radianButton); angelPanel.add(Box.createHorizontalGlue()); angelPanel.add(gradientButton); // 添加角度面板 add(angelPanel, new GBC(0, 0, 5, 1).setFill(GridBagConstraints.BOTH) .setInsets(5).setWeight(100, 100)); // 添加按钮 String[][] btnStrings = { { "", "Inv", "In", "(", ")" }, { "Int", "sinh", "sin", "x^2", "n!" }, { "dms", "cosh", "cos", "x^y", "y√x" }, { "π", "tanh", "tan", "x^3", "3√x" }, { "F-E", "Exp", "Mod", "log", "10^x" } }; for (int i = 0; i < btnStrings.length; i++) { for (int j = 0; j < btnStrings[0].length; j++) { JButton button = new JButton(btnStrings[i][j]); add(button, new GBC(j, i + 1, 1, 1) .setFill(GridBagConstraints.BOTH).setInsets(5) .setWeight(100, 100)); if (i + j == 0) button.setEnabled(false); } } } public static void main(String[] args) { // TODO Auto-generated method stub } }
BinaryPanel.java
import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class BinaryPanel extends JPanel{ List<JPanel> bitPanelList = new ArrayList<JPanel>(); public BinaryPanel(){ setLayout(new GridBagLayout()); setBorder(BorderFactory.createEtchedBorder()); for (int i = 0; i < 4; i++) { for (int j = 0; j < 8; j++) { if (i == 0 || i == 2) { // 建立一个面板并设置为左对齐的flowLayout,它容纳4个label JPanel bitPanel = new JPanel(); FlowLayout flowLayout = new FlowLayout(); flowLayout.setAlignment(FlowLayout.LEFT); flowLayout.setHgap(0); bitPanel.setLayout(flowLayout); bitPanel.setName(String.valueOf(bitPanelList.size())); bitPanelList.add(bitPanel); // 添加4个label for (int k = 0; k < 4; k++) { JLabel label = createBitLabel(); String buttonName = String.valueOf(k); label.setName(buttonName); //label.setText(buttonName); bitPanel.add(label); System.out.println("add createBitButton of " + buttonName); } // 将包含4个button的小面板作为一个单元格添加到binaryPanel add(bitPanel, new GBC(j, i).setFill(GridBagConstraints.BOTH) .setWeight(100, 100).setInsets(5)); } else if (i == 1) { String[] texts = { "63", null, null, null, "47", null, null, " 32" }; for (int k = 0; k < texts.length; k++) { JLabel indexLabel = new JLabel(); if (texts[k] == null) continue; indexLabel.setText(texts[k]); add(indexLabel, new GBC(k, i).setFill(GridBagConstraints.BOTH) .setWeight(100, 100).setInsets(5)); } } else if (i == 3) { String[] texts = { "31", null, null, null, "15", null, null, " 0" }; for (int k = 0; k < texts.length; k++) { JLabel indexLabel = new JLabel(); if (texts[k] == null) continue; indexLabel.setText(texts[k]); add(indexLabel, new GBC(k, i).setFill(GridBagConstraints.BOTH) .setWeight(100, 100).setInsets(5)); } } } } } private JButton createBitButton() { JButton bitButton = new JButton(); bitButton.setText("0"); bitButton.setEnabled(false); return bitButton; } private JLabel createBitLabel() { JLabel bitLabel = new JLabel(); bitLabel.setText("0"); // bitLabel.setEnabled(false); return bitLabel; } public static void main(String[] args) { // TODO Auto-generated method stub JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new BinaryPanel()); frame.pack(); frame.setVisible(true); } }
ProgramFunctionPanel.java
import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JRadioButton; public class ProgramFunctionPanel extends JPanel{ public ProgramFunctionPanel(){ // 设置窗体layout setLayout(new GridBagLayout()); add(createRadixPanel(), new GBC(0,0, 1, 3).setWeight(100, 100).setFill(GridBagConstraints.BOTH)); add(createBytePanel(), new GBC(0,3, 1, 3).setWeight(100, 100).setFill(GridBagConstraints.BOTH)); String textString [][] = { {null, "", "Mod","A"}, {null, "(", ")","B"}, {null, "RoL", "RoR","C"}, {null, "Or", "Xor","D"}, {null, "Lsh", "Rsh","E"}, {null, "Not", "And","F"},}; for (int i = 0; i< textString.length; i++) { for (int j = 0; j< textString[i].length; j++) { String text = textString[i][j]; if(text != null){ JButton button = new JButton(text); if(text.equals("")) button.setEnabled(false); add(button, new GBC(j, i).setWeight(100, 100).setFill(GridBagConstraints.BOTH).setInsets(5)); //System.out.printf("add btn at (%d,%d)\n", j,i); } } } } private JPanel createRadixPanel() { JPanel radixPanel = new JPanel(); BoxLayout boxLayout=new BoxLayout(radixPanel, BoxLayout.Y_AXIS); radixPanel.setLayout(boxLayout); radixPanel.setBorder(BorderFactory.createEtchedBorder()); String [] radixStrings = {"十六进制", "十进制","八进制","二进制"}; ButtonGroup btnGroup = new ButtonGroup(); for (String radixString : radixStrings) { JRadioButton radioButton = new JRadioButton(radixString); //注册事件 btnGroup.add(radioButton); radixPanel.add(radioButton); } return radixPanel; } private JPanel createBytePanel() { JPanel bytePanel = new JPanel(); BoxLayout boxLayout=new BoxLayout(bytePanel, BoxLayout.Y_AXIS); bytePanel.setLayout(boxLayout); bytePanel.setBorder(BorderFactory.createEtchedBorder()); String [] byteStrings = {"四字", "双字","字","字节"}; ButtonGroup btnGroup = new ButtonGroup(); for (String byteString : byteStrings) { JRadioButton radioButton = new JRadioButton(byteString); //注册事件 btnGroup.add(radioButton); bytePanel.add(radioButton); } return bytePanel; } public static void main(String[] args) { // TODO Auto-generated method stub JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new ProgramFunctionPanel()); frame.pack(); frame.setVisible(true); } }
GBC.java
import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; /* * GBC.java,source code from java核心技术 卷1 基础知识,P381 */ public class GBC extends GridBagConstraints{ /* * constructs a GBC with a given gridx and gridy position and all other grid * bag constraint values set to the default * @param gridx the gridx position * @param gridy the gridy position */ public GBC(int gridx, int gridy){ this.gridx = gridx; this.gridy = gridy; } public GBC(int gridx, int gridy, int gridWidth, int gridHeight){ this.gridx = gridx; this.gridy = gridy; this.gridwidth = gridWidth; this.gridheight = gridHeight; } /* * sets the anchor * @param anchor the anchor style * @return this object for further modification */ public GBC setAnchor(int anchor){ this.anchor = anchor; return this; } /* * sets the fill direction * @param fill the fill direction * @return this object for further modification */ public GBC setFill(int fill){ this.fill = fill; return this; } /* * sets the cell weights * @param weightx the cell weight in x direction * @param weighty the cell weight in y direction * @return this object for further modification */ public GBC setWeight(int weightx, int weighty){ this.weightx = weightx; this.weighty = weighty; return this; } /* * sets the insets of this cell * @param insets distance ths spacing to use in all directions * @return this object for further modification */ public GBC setInsets(int distance){ this.insets = new Insets(distance, distance, distance, distance); return this; } /* * sets the insets of this cell * @param top distance ths spacing to use on top * @param bottom distance ths spacing to use on bottom * @param left distance ths spacing to use to the left * @param right distance ths spacing to use to the right * @return this object for further modification */ public GBC setInsets(int top, int left,int bottom,int right){ this.insets = new Insets(top, left, bottom, right); return this; } /* * sets the Ipad of this cell * @param Ipad distance ths spacing to use in all directions * @return this object for further modification */ public GBC setIpad(int ipadx, int ipady){ this.ipadx = ipadx; this.ipadx = ipadx; return this; } }