【问题标题】:How to get rid of repeating code in function?如何摆脱函数中的重复代码?
【发布时间】:2022-01-11 18:58:38
【问题描述】:

我想摆脱应用程序中的重复代码。我尝试了几种方法,但是当我这样做时,应用程序并没有像我预期的那样工作。只有将相同的代码放在一个函数中才有效果。

简而言之,在应用程序中,我可以通过两种方式删除记录,即按下按钮或指向记录并用鼠标右键删除它。按钮删除有效,但我不知道如何使鼠标删除具有相同的效果。

删除表中记录的按钮。

 deleteButton.addActionListener(event -> {
    
                String name;
                name = Name.getText();
    
                try {
                    removeSelectedRow(table1);
    
                    pst = con.prepareStatement("delete from recipe where recipe_name = ?");
                    pst.setString(1, name);
                    pst.executeUpdate();
                    JOptionPane.showMessageDialog(null, "Record deleted");
                    Name.setText("");
                    Time.setText("");
                    Difficulty.setSelectedItem("");
                    Name.requestFocus();
    
                } catch (SQLException e) {
    
                    e.printStackTrace();
                }
    
    
            });

这是一个应该用鼠标右键删除的函数,如您所见,它可以工作,但代码几乎与前面的示例相同。

 public void setDeleteButton(ActionEvent event) {


        JMenuItem menu = (JMenuItem) event.getSource();
        if (menu == menuItemRemove) {
            removeSelectedRow(table1);

        }
        String name;
        name = Name.getText();

        try {
            removeSelectedRow(table1);

            pst = con.prepareStatement("delete from recipe where recipe_name = ?");
            pst.setString(1, name);
            pst.executeUpdate();
            JOptionPane.showMessageDialog(null, "Record deleted");
            Name.setText("");
            Time.setText("");
            Difficulty.setSelectedItem("");
            Name.requestFocus();

        } catch (SQLException e) {

            e.printStackTrace();
        }
    }

指向特定记录的函数

 public void removeSelectedRow(JTable table) {

        DefaultTableModel model = (DefaultTableModel) table1.getModel();
        if (table.getSelectedRow() != -1) {
            model.removeRow(table.getSelectedRow());

        }
    }

【问题讨论】:

  • 这正是 Actions 的设计目的 - 请参阅 How to Use Actions 了解更多详情
  • 嗨@MadProgrammer 感谢链接,这确实是我正在寻找的,但我真的不知道如何将try-catch 之间的代码封装在一个变量中以便稍后调用它在 setDeleteButton 函数中?
  • 你可能需要稍微改变一下思路,Action 最好通过依赖注入来支持,这意味着一些共享状态可能需要在构造时传递给Action跨度>
  • @MadProgrammer 好的,我将不得不阅读更多关于此的内容以进一步了解这种作用机制。
  • 只有将相同的代码放在一个函数中才有效果。 - 那么为什么不这样做呢?在我看来,这是解决重复代码问题的简单、明显和通用的解决方案。

标签: java swing popup jbutton


【解决方案1】:

好的,所以这需要稍微转变心态。要使这真正灵活,您将需要支持“依赖注入”和“委托”等概念。

这样做的原因是,您的“操作”需要大量信息,但是,我们应该努力使我们的类之间具有低水平的内聚或耦合。例如,您的“操作”不应该关心“如何”删除该行,只关心在请求时应该完成。

那么,让我们从一些基本的委托开始...

public interface MutableTableSupportable {
    public void addListSelectionListener(ListSelectionListener listener);
    public void removeListSelectionListener(ListSelectionListener listener);
}

public interface TableRowDeletable extends MutableTableSupportable {
    public int getSelectedRowCount();
    public void removeSelectedRow();
}

现在,很明显,为了满足我的更多需求,我过度简化了它,但在这里我提供了一个“基本”级别的委托和更集中的委托。为什么?因为如果你想提供一个“插入”动作会发生什么?为什么它应该具有“删除”功能?相反,我们故意隔离我们想要公开的功能。

接下来,我们需要设计我们的动作......

public class DeleteRowAction extends AbstractAction {

    private TableRowDeletable delgate;

    public DeleteRowAction(TableRowDeletable delgate) {
        putValue(SHORT_DESCRIPTION, "Delete the currently selected row");
        putValue(MNEMONIC_KEY, KeyEvent.VK_D);
        putValue(NAME, "Delete Row");
        putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, KeyEvent.CTRL_DOWN_MASK));
        this.delgate = delgate;

        delgate.addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                selectionDidChange();
            }
        });
        selectionDidChange();
    }

    protected void selectionDidChange() {
        setEnabled(delgate.getSelectedRowCount() > 0);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        delgate.removeSelectedRow();
    }

}

好吧,没什么特别的,这很重要。它监视选择状态,因此我们可以启用/禁用操作,当触发时,我们调用我们的委托来完成实际工作。这将操作与实现分离,因为操作不需要知道正在使用什么类型的 TableModel 或它可能使用的数据源类型,它只是想告诉委托它应该执行一些一种操作。

另外注意,我们设置了一个键盘快捷键,可以被JMenuItem和助记符支持使用(按住AltOption键)

好的,但这确实为我们做了很多,或者是......

让我们看看删除操作可能是什么样子...

DeleteRowAction deleteRowAction = new DeleteRowAction(new TableRowDeletable() {
    @Override
    public int getSelectedRowCount() {
        return table.getSelectedRowCount();
    }

    @Override
    public void removeSelectedRow() {
        DefaultTableModel model = (DefaultTableModel) table.getModel();
        int visibleRowIndex = table.getSelectedRow();
        if (visibleRowIndex == -1) {
            return;
        }

        int modelIndex = table.convertRowIndexToModel(visibleRowIndex);
        // I'm guessing here, but if you're deleting a row, you should
        // use the row data
        String recordId = (String) model.getValueAt(modelIndex, 0);

        try (PreparedStatement pst = getConnection().prepareStatement("delete from recipe where recipe_name = ?")) {
            pst.setString(1, recordId);
            // You could check the number of rows effected by this change
            pst.executeUpdate();

            JOptionPane.showMessageDialog(TestPane.this, "Record deleted", "Success", JOptionPane.INFORMATION_MESSAGE);

            model.removeRow(modelIndex);
        } catch (SQLException ex) {
            ex.printStackTrace();
            JOptionPane.showMessageDialog(TestPane.this, "Failed to delete row from database", "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    @Override
    public void addListSelectionListener(ListSelectionListener listener) {
        table.getSelectionModel().addListSelectionListener(listener);
    }

    @Override
    public void removeListSelectionListener(ListSelectionListener listener) {
        table.getSelectionModel().removeListSelectionListener(listener);
    }
});

现在,这只是一个示例,但基本思想是,我们已经为 MutableTableSupportableTableRowDeletable 接口提供了实现(但 DeleteRowAction 并不关心“如何”)和我们已经实现了removeSelectedRow 功能以从TableModel 和数据库中删除行。

同样,DeleteRowAction 并不关心这是如何实现的,它只是委派了该责任,因此您可以拥有多个 DeleteRowActions,它们同时与不同的 TableModels 和数据源一起工作?

代表团?

好的,但是所有这些如何协同工作?嗯,其实,其实真的很容易

可运行示例...

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import java.sql.*;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JMenuBar menuBar = new JMenuBar();
                JFrame frame = new JFrame();
                frame.setJMenuBar(menuBar);
                frame.add(new TestPane(menuBar));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JTable table;

        public TestPane(JMenuBar menuBar) {
            setLayout(new BorderLayout());

            DefaultTableModel model = new DefaultTableModel(new Object[][]{new Object[]{"Test"}}, new Object[]{"Test"});
            table = new JTable(model);

            add(new JScrollPane(table));

            DeleteRowAction deleteRowAction = new DeleteRowAction(new TableRowDeletable() {
                @Override
                public int getSelectedRowCount() {
                    return table.getSelectedRowCount();
                }

                @Override
                public void removeSelectedRow() {
                    JOptionPane.showMessageDialog(TestPane.this, "Delete the row please", "Debug", JOptionPane.INFORMATION_MESSAGE);
                }

                @Override
                public void addListSelectionListener(ListSelectionListener listener) {
                    table.getSelectionModel().addListSelectionListener(listener);
                }

                @Override
                public void removeListSelectionListener(ListSelectionListener listener) {
                    table.getSelectionModel().removeListSelectionListener(listener);
                }
            });

            JMenu actionsMenu = new JMenu("Actions");
            actionsMenu.add(deleteRowAction);

            menuBar.add(actionsMenu);

            JButton deleteButton = new JButton(deleteRowAction);
            add(deleteButton, BorderLayout.SOUTH);
        }

    }

    public interface MutableTableSupportable {
        public void addListSelectionListener(ListSelectionListener listener);
        public void removeListSelectionListener(ListSelectionListener listener);
    }

    public interface TableRowDeletable extends MutableTableSupportable {
        public int getSelectedRowCount();
        public void removeSelectedRow();
    }

    public class DeleteRowAction extends AbstractAction {

        private TableRowDeletable delgate;

        public DeleteRowAction(TableRowDeletable delgate) {
            putValue(SHORT_DESCRIPTION, "Delete the currently selected row");
            putValue(MNEMONIC_KEY, KeyEvent.VK_D);
            putValue(NAME, "Delete Row");
            putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, KeyEvent.CTRL_DOWN_MASK));
            this.delgate = delgate;

            delgate.addListSelectionListener(new ListSelectionListener() {
                @Override
                public void valueChanged(ListSelectionEvent e) {
                    selectionDidChange();
                }
            });
            selectionDidChange();
        }

        protected void selectionDidChange() {
            setEnabled(delgate.getSelectedRowCount() > 0);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            delgate.removeSelectedRow();
        }

    }
}

nb:此示例删除了数据库支持,因为我没有,而是显示一条消息

好的,让我们快速浏览一下这里的一些有趣的东西......

首先...

JMenuBar menuBar = new JMenuBar();
JFrame frame = new JFrame();
frame.setJMenuBar(menuBar);
frame.add(new TestPane(menuBar));

我们将菜单栏注入到面板中。这样做是为了让面板可以根据需要配置菜单栏。我们可以在这里使用一种类型的工厂或其他委托,但我会留给您自己解决。

下一步...

JMenu actionsMenu = new JMenu("Actions");
actionsMenu.add(deleteRowAction);

menuBar.add(actionsMenu);

JButton deleteButton = new JButton(deleteRowAction);
add(deleteButton, BorderLayout.SOUTH);

我们构建JMenu 并添加删除行操作并创建JButton,使用相同的Action ... 对于五行代码,我们实际上已经做了很多。我们已经能够设置每个组件显示的文本、工具提示文本、加速键和助记符......尝试手动设置,然后需要在轨道上进行更改?(想要支持本地化 - 需要在一个位置进行更改)

但是等等,我们可以做得更多!! ?

如果我们添加...

InputMap inputMap = table.getInputMap(WHEN_FOCUSED);
ActionMap actionMap = table.getActionMap();

inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), "deleteRow");
actionMap.put("deleteRow", deleteRowAction);

到构造函数的最后,我们可以提供一个键绑定给用户,这样当JTable有键盘焦点并且点击他们Delete/Backspace kbd> 键,它也会触发动作!!!

现在我们有四种触发动作的方法:

  1. 按下按钮
  2. 打开并触发菜单项
  3. 使用菜单键盘“加速器”键绑定
  4. 点击删除

行动?

键绑定可运行示例...

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JMenuBar menuBar = new JMenuBar();
                JFrame frame = new JFrame();
                frame.setJMenuBar(menuBar);
                frame.add(new TestPane(menuBar));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JTable table;

        public TestPane(JMenuBar menuBar) {
            setLayout(new BorderLayout());

            DefaultTableModel model = new DefaultTableModel(new Object[][]{new Object[]{"Test"}}, new Object[]{"Test"});
            table = new JTable(model);

            add(new JScrollPane(table));

            DeleteRowAction deleteRowAction = new DeleteRowAction(new TableRowDeletable() {
                @Override
                public int getSelectedRowCount() {
                    return table.getSelectedRowCount();
                }

                @Override
                public void removeSelectedRow() {
                    JOptionPane.showMessageDialog(TestPane.this, "Delete the row please", "Debug", JOptionPane.INFORMATION_MESSAGE);
                }

                @Override
                public void addListSelectionListener(ListSelectionListener listener) {
                    table.getSelectionModel().addListSelectionListener(listener);
                }

                @Override
                public void removeListSelectionListener(ListSelectionListener listener) {
                    table.getSelectionModel().removeListSelectionListener(listener);
                }
            });

            JMenu actionsMenu = new JMenu("Actions");
            actionsMenu.add(deleteRowAction);

            menuBar.add(actionsMenu);

            JButton deleteButton = new JButton(deleteRowAction);
            add(deleteButton, BorderLayout.SOUTH);

            InputMap inputMap = table.getInputMap(WHEN_FOCUSED);
            ActionMap actionMap = table.getActionMap();

            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), "deleteRow");
            actionMap.put("deleteRow", deleteRowAction);
        }

    }

    public interface MutableTableSupportable {
        public void addListSelectionListener(ListSelectionListener listener);
        public void removeListSelectionListener(ListSelectionListener listener);
    }

    public interface TableRowDeletable extends MutableTableSupportable {
        public int getSelectedRowCount();
        public void removeSelectedRow();
    }

    public class DeleteRowAction extends AbstractAction {

        private TableRowDeletable delgate;

        public DeleteRowAction(TableRowDeletable delgate) {
            putValue(SHORT_DESCRIPTION, "Delete the currently selected row");
            putValue(MNEMONIC_KEY, KeyEvent.VK_D);
            putValue(NAME, "Delete Row");
            putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, KeyEvent.CTRL_DOWN_MASK));
            this.delgate = delgate;

            delgate.addListSelectionListener(new ListSelectionListener() {
                @Override
                public void valueChanged(ListSelectionEvent e) {
                    selectionDidChange();
                }
            });
            selectionDidChange();
        }

        protected void selectionDidChange() {
            setEnabled(delgate.getSelectedRowCount() > 0);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            delgate.removeSelectedRow();
        }

    }
}

但这还不是全部!我们还可以为JToolBar 添加一个按钮,因为,为什么不呢!?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-04
    • 2023-03-31
    • 2013-07-24
    • 1970-01-01
    • 2020-03-25
    • 2016-01-08
    • 2011-01-06
    相关资源
    最近更新 更多