前言:
马总给我提出计算器3.0新需求:可以在页面上输入一个组件,用户的组件库里面就多一个组件,用户就可以使用
一、解决方法:
1. 新增成员变量和初始化
// 新增的输入框
private InputBox newInputBox;
// 新增的组件面板
private JPanel newComponentsPanel;
newInputBox:用于用户输入自定义组件内容(数字或运算符)的输入框。
newComponentsPanel:用于展示用户通过输入框添加的自定义组件按钮。
2. 初始化界面组件方法,新增了以下部分:
// 新增的输入组件面板JPanel newInputPanel = new JPanel();newInputPanel.setLayout(new FlowLayout(FlowLayout.LEFT));// 新增的标签JLabel newInputLabel = new JLabel("请添加组件:");newInputPanel.add(newInputLabel);// 新增的输入框newInputBox = new InputBox(inputBoxes.size() + 1);newInputPanel.add(newInputBox.getPanel());// 新增的添加组件按钮JButton addComponentButton = new JButton("添加组件");addComponentButton.addActionListener(e -> handleAddComponent());newInputPanel.add(addComponentButton);// 新增的组件标签JLabel newComponentsLabel = new JLabel("用户自定义组件:");newInputPanel.add(newComponentsLabel);// 新增的组件面板newComponentsPanel = new JPanel();newComponentsPanel.setLayout(new FlowLayout(FlowLayout.LEFT));// 为新增组件面板添加水平滚动条(当内容超出宽度时可滚动)JScrollPane scrollPane2 = new JScrollPane(newComponentsPanel);scrollPane2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);scrollPane2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); // 底部面板采用网格布局,4行1列,水平间距5,垂直间距2jp_below.setLayout(new GridLayout(4, 1,5,2));add(jp_below, BorderLayout.SOUTH);// 将按钮面板添加到底部面板第2行jp_below.add(buttonPanel);// 将新增组件面板的滚动面板添加到底部面板第3行jp_below.add(newInputPanel);jp_below.add(scrollPane2);
创建了一个新的面板newInputPanel,用于容纳所有新增组件。
添加了 “请添加组件:” 标签和自定义输入框newInputBox。
添加了 “添加组件” 按钮,点击后调用handleAddComponent()方法处理添加逻辑。
添加了 “新加的组件:” 标签和newComponentsPanel面板,用于显示用户添加的自定义组件按钮。并且为newComponentsPanel设置scrollPane2 滚动条。这样当 newComponentsPanel 中的自定义组件过多时,用户可以通过水平滚动条来查看所有组件。
新建了jp_below面板用于3行1列的布局,将按钮面板,新增组件面板,滚动条添加进来。使得不会相互覆盖,布局更美观。
3. 处理添加组件逻辑(handleAddComponent方法)
/*** 处理"添加组件"按钮的点击事件* - 验证用户输入是否为合法的数字或运算符* - 检查组件是否已存在* - 若合法且不存在则创建新按钮并添加到界面* - 若不合法或已存在则显示错误提示*/private void handleAddComponent() {// 获取用户在输入框中的内容并去除首尾空格String input = newInputBox.getText().trim();// 隐藏之前的错误提示newInputBox.hideError();// 验证输入是否为合法的数字或单个运算符if (!isNumber(input) && !isOperator(input)) {newInputBox.showError("输入数字或单个运算符");return;}// 检查组件是否已存在if (isComponentExists(input)) {newInputBox.showError("已经添加");return;}// 创建一个新按钮,文本为用户输入内容JButton newButton = new JButton(input);// 为按钮添加点击事件监听器newButton.addActionListener(e -> handleOperatorClick(input));// 设置按钮的右键菜单(支持删除功能)setupButtonContextMenu(newButton);// 将新按钮添加到"新加的组件"面板newComponentsPanel.add(newButton);// 重新验证面板布局并刷新显示newComponentsPanel.revalidate();newComponentsPanel.repaint();// 清空输入框并设置焦点newInputBox.setText("");newInputBox.requestFocus();}
获取用户在newInputBox中输入的内容,检查是否为数字或运算符。
如果是有效输入,创建一个新按钮,设置按钮文本为输入内容,并绑定点击事件(调用原有的handleOperatorClick方法)。
为按钮设置右键菜单(通过setupButtonContextMenu方法),支持删除操作。
将按钮添加到newComponentsPanel中并刷新界面。
4. 设置按钮右键菜单(setupButtonContextMenu方法)
/*** 为按钮设置右键菜单,支持删除功能*/private void setupButtonContextMenu(JButton button) {// 创建右键弹出菜单JPopupMenu popupMenu = new JPopupMenu();// 创建"删除"菜单项并添加点击事件处理JMenuItem deleteItem = new JMenuItem("删除");deleteItem.addActionListener(e -> {// 显示确认对话框,防止误操作int confirm = JOptionPane.showConfirmDialog(calculator3.this,"删除按钮 \"" + button.getText() + "\" 吗?","确认删除",JOptionPane.YES_NO_OPTION);// 用户确认后执行删除操作if (confirm == JOptionPane.YES_OPTION) {// 从面板移除按钮组件newComponentsPanel.remove(button);// 重新计算布局并刷新UInewComponentsPanel.revalidate();newComponentsPanel.repaint();}});// 将菜单项添加到弹出菜单popupMenu.add(deleteItem);// 为按钮添加鼠标监听器,处理右键触发逻辑button.addMouseListener(new MouseAdapter() {//鼠标按下事件处理:检测是否为右键触发条件@Overridepublic void mouseReleased(MouseEvent e) {if (e.isPopupTrigger()) {popupMenu.show(e.getComponent(), e.getX(), e.getY());}}});}
为自定义组件按钮创建右键菜单,包含 “删除” 选项。
点击删除时,检查是否已完成计算(避免修改已计算的表达式),并通过确认对话框验证是否删除
确认后从newComponentsPanel中移除按钮并刷新界面。
5、新增3.0版本按钮
// 创建版本3.0切换按钮JButton version3Button = new JButton("3.0");// 给版本2按钮绑定点击事件:显示3.0版本信息version3Button.addActionListener(e -> showVersionInfo(3));// 将版本按钮添加到版本面板versionPanel.add(version3Button);
//在showVersionInfo方法新增
else if (version == 3) {message = "3.0版本:\n增加用户自定义组件,";}// 显示信息对话框JOptionPane.showMessageDialog(this, message, "版本信息", JOptionPane.INFORMATION_MESSAGE);}
源码在:java实现计算器3.0源码-CSDN博客
二、小结
通过实现用户自定义功能,对JFrame有了更深的理解,在BorderLayout将容器分为五个区域,将新增组件的面板放到South区域,会覆盖原来的运算符组件面板。于是GridLayout布局管理器,可以将容器划分为规则的网格(行 × 列),便于添加面板。并且当用户自定义组件较多时,设置scrollPane 滚动条,用户可以通过水平滚动条来查看所有组件。在用户添加自定义组件时,会先检验是否为数字或者单个运算符和是否已经存在。校验合理后绑定点击事件(调用原有的handleOperatorClick方法)与原来的运算符组件有相同功能。