✨博主:命运之光
🌸专栏:Python星辰秘典
❤️专栏:Java经典程序设计
☀️博主的其他文章:点击进入博主的主页
前言:在现代社会中,计算器是我们生活中不可或缺的工具之一。它们可以轻松地进行各种数值计算,从简单的加减乘除到复杂的科学运算,为我们提供了快捷准确的计算结果。但你是否曾想过,我们可以亲手打造一个属于自己的计算器应用程序,体验计算世界的奇妙之旅?本文将带领你进入计算器应用程序的开发领域。我们将使用Java编程语言和Swing图形界面库,从零开始构建一个简单但功能强大的计算器应用程序。无论你是计算机科学专业的学生,还是对编程和应用开发感兴趣的爱好者,这个实践项目都将为你提供一个宝贵的机会来深入了解应用程序开发的流程和技术。
目录
实验内容
以下是该项目的主要内容:
创建一个窗口界面,包含一个代码编辑区域、行号显示区域和按钮面板。
代码编辑区域使用JTextPane组件实现,可以进行文本编辑、撤销和重做操作。
行号显示区域使用JTextArea组件实现,显示当前代码编辑区域的行号。
按钮面板包含编译按钮和运行按钮,用于执行编译和运行操作。
提供文件操作功能,包括打开和保存文件。
提供主题设置功能,可以切换代码编辑区域和行号显示区域的背景颜色。
提供字体设置功能,包括设置字体颜色和大小。
支持缩放功能,可以通过鼠标滚轮和Ctrl键进行文本的放大和缩小。
在代码编辑区域中输入代码后,可以进行编译操作,将代码保存到文件并执行javac命令进行编译。
编译结果将显示在消息对话框中,显示编译成功或编译失败的消息。
可以运行编译后的代码,调用系统命令行执行java Main命令,并获取代码运行的输出结果。
运行结果将显示在消息对话框中。
问题描述
该项目主要解决以下问题:
代码编辑器:提供一个功能完善的代码编辑器,用于编辑和显示代码文件的内容。该编辑器具有基本的文本编辑功能,包括插入、删除、撤销和重做等操作。用户可以在编辑器中编写代码,并对代码进行格式化和调整。
文件操作:支持文件的打开和保存操作。用户可以通过打开菜单项选择要打开的文件,并将文件内容加载到代码编辑器中。用户还可以使用保存菜单项将代码编辑器中的内容保存到文件中。
编译代码:提供编译代码的功能。用户可以点击编译按钮,将代码保存到名为 "Main.java" 的文件中,并调用系统命令行执行 javac 命令对代码进行编译。编译成功后,会显示编译成功的消息对话框;编译失败则显示编译失败的消息对话框。
运行代码:支持代码的运行操作。用户可以点击运行按钮,调用系统命令行执行 java Main 命令运行编译后的代码,并获取代码运行的输出结果。运行结果会显示在消息对话框中。
行号显示:提供行号显示功能。代码编辑器的左侧会显示行号区域,显示当前编辑代码的行数。随着代码的插入、删除和换行等操作,行号会相应更新。
主题切换:支持编辑器主题的切换。用户可以通过主题菜单选择不同的主题,包括亮色主题和暗色主题,以满足个性化的显示需求。
字体设置:支持编辑器字体的设置。用户可以通过字体颜色菜单项选择编辑器的字体颜色,通过字体大小菜单项调整编辑器的字体大小。
缩放文本:支持文本缩放功能。用户可以通过按住 Ctrl 键并滚动鼠标滚轮来放大或缩小代码编辑器中的文本内容。
通过解决上述问题,该项目提供了一个功能完善的代码编辑器,方便用户编辑、保存、编译和运行代码,并提供了一些个性化的设置选项,提高了代码编写和调试的效率。
项目功能
该项目最后实现以下功能:
代码编辑功能:提供一个代码编辑器,支持基本的文本编辑操作,如插入、删除、撤销和重做等。用户可以在编辑器中编写代码,并对代码进行格式化和调整。
文件操作功能:支持打开和保存代码文件。用户可以通过打开菜单项选择要打开的文件,并将文件内容加载到代码编辑器中。用户还可以使用保存菜单项将代码编辑器中的内容保存到文件中。
代码编译功能:提供编译代码的功能。用户可以点击编译按钮,将代码保存到名为 "Main.java" 的文件中,并调用系统命令行执行 javac 命令对代码进行编译。编译成功后,会显示编译成功的消息对话框;编译失败则显示编译失败的消息对话框。
代码运行功能:支持代码的运行操作。用户可以点击运行按钮,调用系统命令行执行 java Main 命令运行编译后的代码,并获取代码运行的输出结果。运行结果会显示在消息对话框中。
行号显示功能:在代码编辑器中显示行号区域,以便用户可以轻松地跟踪和定位代码的行数。
主题切换功能:支持编辑器主题的切换。用户可以通过主题菜单选择不同的主题,包括亮色主题和暗色主题,以满足个性化的显示需求。
字体设置功能:支持编辑器字体的设置。用户可以通过字体颜色菜单项选择编辑器的字体颜色,通过字体大小菜单项调整编辑器的字体大小。
文本缩放功能:支持放大或缩小代码编辑器中的文本内容。用户可以通过按住 Ctrl 键并滚动鼠标滚轮来调整文本的大小。
通过以上功能,该项目提供了一个功能完善的代码编辑器,使用户能够方便地编辑、保存、编译和运行代码,并提供了一些个性化设置选项,以提高编码和调试的效率。
项目分析
主界面
文件打开
主题切换
文字颜色
文字大小
编译功能
运行功能
创建窗口:使用 JFrame 类创建了一个文本编译器的窗口,并设置了窗口和大小。
编辑区域:使用 JTextPane 类创建了一个代码编辑区域,支持文本编辑和代码高亮显示。
行号显示:通过在编辑区域左侧添加一个 JTextArea 来实现行号的显示,并与编辑区域进行联动。
按钮:创建了编译按钮和运行按钮,用于执行代码编译和运行操作。
文件操作:通过文件选择器实现打开和保存文件功能。
主题切换:通过菜单栏实现了切换主题的功能,包括亮色和暗色主题。
文本编辑功能:支持撤销和重做操作,支持通过鼠标滚轮和快捷键进行文本缩放。
代码编译与运行:将编辑区域的代码保存到名为 "Main.java" 的文件中,调用系统命令行执行 javac 命令进行编译。运行代码则调用系统命令行执行 "java Main" 命令运行编译后的代码,并获取代码运行的输出结果。
字体颜色和大小:通过菜单栏实现了设置字体颜色和大小的功能。
其他事件监听:注册了各种事件监听器,包括文本内容变化监听器、撤销操作监听器、鼠标滚轮监听器等。
该代码虽然实现了基本的文本编辑器和简单代码编译运行的功能,但在实际使用中可能需要进一步优化和改进
项目设计
设计流程图如下
系统实现
项目源码
package 文本编辑器;import javax.swing.*;import javax.swing.border.Border;import javax.swing.event.DocumentEvent;import javax.swing.event.DocumentListener;import javax.swing.text.AttributeSet;import javax.swing.text.SimpleAttributeSet;import javax.swing.text.StyleConstants;import javax.swing.text.StyleContext;import javax.swing.undo.UndoManager;import java.awt.*;import java.awt.event.*;import java.io.*;public class CodeEditor extends JFrame { // 声明私有成员变量 private JTextPane codePane; // 代码编辑区域 private JTextArea lineNumberArea; // 行号显示区域 private JButton compileButton; // 编译按钮 private JButton runButton; // 运行按钮 private JFileChooser fileChooser; // 文件选择器 private JMenu themeMenu; // 主题菜单 private JMenuItem lightThemeItem; // 亮色主题菜单项 private JMenuItem darkThemeItem; // 暗色主题菜单项 private JMenu editMenu; // 编辑菜单 private JMenuItem fontColorItem; // 字体颜色菜单项 private JMenuItem fontSizeItem; // 字体大小菜单项 private UndoManager undoManager; // 撤销管理器 private double zoomScale = 1.0; // 缩放比例 public CodeEditor() { setTitle("文本编译器"); // 设置窗口 setSize(800, 600); // 设置窗口大小 setDefaultCloseOperation(EXIT_ON_CLOSE); // 设置窗口关闭时的默认操作为退出应用程序 // 创建主面板 JPanel mainPanel = new JPanel(new BorderLayout()); getContentPane().add(mainPanel); codePane = new JTextPane(); // 创建代码编辑区域 lineNumberArea = new JTextArea("1"); // 创建行号显示区域 lineNumberArea.setBackground(Color.LIGHT_GRAY); lineNumberArea.setEditable(false);//lineNumberArea.setEditable(false); 将 lineNumberArea 设置为不可编辑,意味着用户无法通过键盘输入或编辑该文本区域中的内容。 lineNumberArea.setFocusable(false);//lineNumberArea.setFocusable(false); 将 lineNumberArea 设置为不可获取焦点,意味着用户无法通过点击或键盘操作将焦点聚焦在该文本区域上。 //这段代码的作用是为 lineNumberArea 文本区域设置一个带有黄色边框和内边距的边框样式。 Border border = BorderFactory.createMatteBorder(0, 0, 0, 5, Color.yellow);//创建了一个 MatteBorder 对象,该边框在右侧有5个像素的黄色边框,而其他三个边界没有边框。这个边框对象被赋值给 border 变量。 lineNumberArea.setBorder(BorderFactory.createCompoundBorder(border, BorderFactory.createEmptyBorder(0, 5, 0, 5)));//将 lineNumberArea 的边框设置为一个复合边框。这个复合边框由两个部分组成:第一个部分是之前创建的 MatteBorder 对象 border,它定义了右侧的黄色边框;第二个部分是一个空边框 BorderFactory.createEmptyBorder(0, 5, 0, 5),它在内部创建了一个没有任何边框的空白区域,其上、下、左、右各有5个像素的空白。通过将这两个边框组合在一起,实现了一个具有黄色边框和内边距的边框效果。 //创建滚动条 JScrollPane codeScrollPane = new JScrollPane(codePane);//创建了一个名为 codeScrollPane 的滚动窗格,并将 codePane 添加到其中。codePane 是一个文本区域或其他可滚动的组件,通过将其添加到滚动窗格中,可以在需要时启用滚动功能,以便在需要时浏览大量的文本内容。 JScrollPane lineNumberScrollPane = new JScrollPane(lineNumberArea);//创建了一个名为 lineNumberScrollPane 的滚动窗格,并将 lineNumberArea 添加到其中。lineNumberArea 是另一个文本区域或可滚动的组件,它可能是用于显示行号的区域。同样,将其添加到滚动窗格中可以实现在需要时滚动内容。 lineNumberScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);//设置了 lineNumberScrollPane 的垂直滚动条策略。JScrollPane.VERTICAL_SCROLLBAR_NEVER 指示不显示垂直滚动条。这意味着在 lineNumberScrollPane 中,即使内容超过可见区域,也不会显示垂直滚动条。 //显示行号 codeScrollPane.setRowHeaderView(lineNumberScrollPane);//将 lineNumberScrollPane 设置为 codeScrollPane 的行头视图,用于显示行号 mainPanel.add(codeScrollPane, BorderLayout.CENTER); // 将代码编辑区域和行号显示区域添加到主面板的中心位置 // 创建按钮面板 JPanel buttonPanel = new JPanel(); compileButton = new JButton("编译"); // 创建编译按钮 runButton = new JButton("运行"); // 创建运行按钮 buttonPanel.add(compileButton); buttonPanel.add(runButton); mainPanel.add(buttonPanel, BorderLayout.SOUTH); // 将按钮面板添加到主面板的南部位置 fileChooser = new JFileChooser(); // 创建文件选择器 //创建菜单栏 JMenuBar menuBar = new JMenuBar(); // 创建菜单栏 JMenu fileMenu = new JMenu("文件"); // 创建文件菜单 JMenuItem openItem = new JMenuItem("打开"); // 创建打开菜单项 JMenuItem saveItem = new JMenuItem("保存"); // 创建保存菜单项 fileMenu.add(openItem); fileMenu.add(saveItem); menuBar.add(fileMenu); //同上 themeMenu = new JMenu("主题"); // 创建主题菜单 lightThemeItem = new JMenuItem("白色"); // 创建亮色主题菜单项 darkThemeItem = new JMenuItem("粉色"); // 创建暗色主题菜单项 themeMenu.add(lightThemeItem); themeMenu.add(darkThemeItem); menuBar.add(themeMenu); //同上 editMenu = new JMenu("编辑"); // 创建编辑菜单 fontColorItem = new JMenuItem("文字颜色"); // 创建字体颜色菜单项 fontSizeItem = new JMenuItem("文字大小"); // 创建字体大小菜单项 editMenu.add(fontColorItem); editMenu.add(fontSizeItem); menuBar.add(editMenu); //解释:setJMenuBar(menuBar); 是一个 Swing 窗口的方法调用,用于将给定的菜单栏(menuBar)设置为窗口的菜单栏。 setJMenuBar(menuBar);// 设置菜单栏 // 注册事件监听器 //e -> openFile() 表示一个处理事件的函数或方法。当事件被触发时,该函数会被调用,并执行 openFile() 方法来处理打开文件的操作。 openItem.addActionListener(e -> openFile()); // 注册打开菜单项的点击事件监听器 saveItem.addActionListener(e -> saveFile()); // 注册保存菜单项的点击事件监听器 compileButton.addActionListener(e -> compileCode()); // 注册编译按钮的点击事件监听器 runButton.addActionListener(e -> runCode()); // 注册运行按钮的点击事件监听器 lightThemeItem.addActionListener(e -> setLightTheme()); // 注册亮色主题菜单项的点击事件监听器 darkThemeItem.addActionListener(e -> setDarkTheme()); // 注册暗色主题菜单项的点击事件监听器 fontColorItem.addActionListener(e -> setFontColor()); // 注册字体颜色菜单项的点击事件监听器 fontSizeItem.addActionListener(e -> setFontSize()); // 注册字体大小菜单项的点击事件监听器 // 注册文本内容变化监听器//显示行号的监听事件 codePane.getDocument().addDocumentListener(new DocumentListener() { public void changedUpdate(DocumentEvent e) { updateLineNumbers(); // 文本内容发生改变时更新行号显示 } public void insertUpdate(DocumentEvent e) { updateLineNumbers(); // 文本内容插入时更新行号显示 } public void removeUpdate(DocumentEvent e) { updateLineNumbers(); // 文本内容删除时更新行号显示 } }); //创建了一个 UndoManager 对象来管理撤销和恢复操作,并将其与 codePane 的文档关联起来,以便在文档发生可撤销的编辑操作时进行记录和管理。这样,用户可以通过调用 undoManager 的方法来撤销和恢复编辑操作的历史记录。 //撤销操作 undoManager = new UndoManager(); codePane.getDocument().addUndoableEditListener(e -> undoManager.addEdit(e.getEdit())); // 注册撤销操作监听器 //为 codePane 添加了一个键盘监听器,用于处理用户按键事件,并实现了对撤销和重做操作的响应。 //通过键盘进行撤销 codePane.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.isControlDown()) {//e.isControlDown() 检查用户是否按下了 Ctrl 键。 if (e.getKeyCode() == KeyEvent.VK_Z) {//通过 e.getKeyCode() 获取按下的键的键码。 if (undoManager.canUndo()) {undoManager.undo(); // Ctrl+Z 撤销操作 } } else if (e.getKeyCode() == KeyEvent.VK_Y) { if (undoManager.canRedo()) {undoManager.redo(); // Ctrl+Y 重做操作 } } } } }); //通过鼠标滑轮控制字体大小 codePane.addMouseWheelListener(new MouseAdapter() { @Override public void mouseWheelMoved(MouseWheelEvent e) { if (e.isControlDown()) {//e.isControlDown() 检查用户是否按下了 Ctrl 键。 int notches = e.getWheelRotation();//e.getWheelRotation() 获取鼠标滚轮的滚动方向,返回的值可以是正数或负数。 if (notches < 0) { zoomIn(); // Ctrl+鼠标滚轮向上缩放文本 } else { zoomOut(); // Ctrl+鼠标滚轮向下缩放文本 } e.consume(); } } }); } private void zoomIn() { zoomScale += 0.1; // 将缩放比例增加0.1 applyZoom(); // 应用新的缩放比例 } private void zoomOut() { zoomScale -= 0.1; // 将缩放比例减少0.1 applyZoom(); // 应用新的缩放比例 } private void applyZoom() { if (zoomScale < 0.1) { zoomScale = 0.1;// 缩放比例不低于0.1 } codePane.setFont(codePane.getFont().deriveFont((float) (codePane.getFont().getSize() * zoomScale))); // 根据缩放比例设置新的字体大小 } private void updateLineNumbers() { String code = codePane.getText(); // 获取当前代码编辑区域的文本内容 int lines = code.split("\n", -1).length; // 计算行数,使用换行符作为分隔符进行拆分具体解释:具体来说,code.split("\n", -1) 使用换行符 (\n) 将字符串 code 拆分成多个行,并返回一个包含拆分后的子字符串的数组。第二个参数 -1 表示在拆分过程中保留所有空行。然后,.length 方法用于获取拆分后的字符串数组的长度,即行数。因此,int lines = code.split("\n", -1).length; 将计算出字符串 code 中的行数,并将其存储在 lines 变量中。 StringBuilder lineNumbers = new StringBuilder(); // 用于存储行号内容的字符串构建器 for (int i = 1; i <= lines; i++) { lineNumbers.append(i).append("\n"); // 将行号添加到字符串构建器中,并添加换行符具体解释:lineNumbers.append(i).append("\n"); 表示将行号 i 和换行符 "\n" 连接起来,并将它们追加到字符串构建器 lineNumbers 的末尾。append() 是字符串构建器的方法,用于将指定的内容添加到构建器的末尾。在这里,lineNumbers.append(i) 将行号 i 添加到字符串构建器中,然后 append("\n") 将换行符 "\n" 添加到字符串构建器中,实现行号和换行符的连接。 } lineNumberArea.setText(lineNumbers.toString()); // 将行号内容设置到行号显示区域 } private void openFile() { int returnValue = fileChooser.showOpenDialog(this); // 显示文件选择对话框,并获取用户的操作结果 if (returnValue == JFileChooser.APPROVE_OPTION) {//如果用户选择了打开文件的操作(returnValue == JFileChooser.APPROVE_OPTION),则继续执行打开文件的操作。 File selectedFile = fileChooser.getSelectedFile(); // 获取用户选择的文件详细解释:通过 fileChooser.getSelectedFile() 获取用户选择的文件,并将其存储在 selectedFile 变量中。 try { BufferedReader reader = new BufferedReader(new FileReader(selectedFile)); // 创建文件读取器详细解释:使用 BufferedReader 类来创建一个文件读取器 (reader),并将选择的文件作为参数传递给它 StringBuilder content = new StringBuilder(); // 用于存储文件内容的字符串构建器详细解释:创建一个 StringBuilder 对象 content,用于存储文件内容。通过循环读取文件中的每一行,并将其逐行添加到 content 字符串构建器中。 String line; while ((line = reader.readLine()) != null) { content.append(line).append("\n"); // 逐行读取文件内容,并添加到字符串构建器中 } reader.close(); // 关闭文件读取器读取文件完成后,关闭文件读取器 (reader.close())。 codePane.setText(content.toString()); // 将文件内容设置到代码编辑区域中将 content.toString() 得到的文件内容字符串设置为代码编辑区域 (codePane) 的文本,即显示文件内容在代码编辑区域中。 } catch (IOException e) { e.printStackTrace(); } } } private void saveFile() { int returnValue = fileChooser.showSaveDialog(this); // 显示文件保存对话框,并获取用户的操作结果 if (returnValue == JFileChooser.APPROVE_OPTION) { File selectedFile = fileChooser.getSelectedFile(); // 获取用户选择的文件 try { FileWriter writer = new FileWriter(selectedFile); // 创建文件写入器 writer.write(codePane.getText()); // 将代码编辑区域的内容写入文件 writer.close(); // 关闭文件写入器 } catch (IOException e) { e.printStackTrace(); } } } private void compileCode() { String code = codePane.getText(); // 获取代码编辑区域的文本内容 try { File file = new File("Main.java"); // 创建名为 "Main.java" 的文件 FileWriter writer = new FileWriter(file); // 创建文件写入器 writer.write(code); // 将代码写入文件 writer.close(); // 关闭文件写入器 Process process = Runtime.getRuntime().exec("javac Main.java"); // 调用系统命令行执行 javac 命令进行编译 int exitCode = process.waitFor(); // 等待编译进程结束,并获取退出码 if (exitCode == 0) { JOptionPane.showMessageDialog(this, "编译成功!"); // 编译成功,显示编译成功的消息对话框 } else { JOptionPane.showMessageDialog(this, "编译失败!"); // 编译失败,显示编译失败的消息对话框 } } catch (Exception e) { e.printStackTrace(); } } private void runCode() { try { Process process = Runtime.getRuntime().exec("java Main"); // 调用系统命令行执行 "java Main" 命令运行编译后的代码 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); // 创建用于读取代码运行输出的字符缓冲读取器 StringBuilder output = new StringBuilder();// 用于存储代码运行输出结果的字符串构建器 String line; while ((line = reader.readLine()) != null) { output.append(line).append("\n"); // 逐行读取代码运行输出,并添加到字符串构建器中 } JOptionPane.showMessageDialog(this, "输出结果:\n" + output.toString()); // 显示运行结果的消息对话框,包含代码运行的输出结果 } catch (Exception e) { e.printStackTrace(); } } private void setLightTheme() { codePane.setBackground(Color.white); // 将代码编辑区域的背景颜色设置为白色 lineNumberArea.setBackground(Color.LIGHT_GRAY); // 将行号区域的背景颜色设置为浅灰色 } private void setDarkTheme() { codePane.setBackground(Color.pink); // 将代码编辑区域的背景颜色设置为粉色 lineNumberArea.setBackground(Color.GRAY); // 将行号区域的背景颜色设置为灰色 } private void setFontColor() { Color selectedColor = JColorChooser.showDialog(this, "选择文字颜色", codePane.getForeground()); // 打开颜色选择器对话框,获取用户选择的颜色 if (selectedColor != null) { codePane.setForeground(selectedColor); // 将选中的颜色设置为代码编辑区域的前景色 } } private void setFontSize() { String input = JOptionPane.showInputDialog(this, "请输入字体大小:", codePane.getFont().getSize()); // 打开输入对话框,获取用户输入的字体大小 //JOptionPane.showInputDialog() 方法会返回用户输入的字体大小,并将其存储在 input 变量中。 try { int fontSize = Integer.parseInt(input); // 将用户输入的字体大小转换为整数通过 Integer.parseInt(input) 将用户输入的字体大小转换为整数,并存储在 fontSize 变量中。 if (fontSize > 0) {//通过条件判断 fontSize > 0 来验证用户输入的字体大小是否有效。如果字体大小大于 0,则执行以下操作: Font currentFont = codePane.getFont();//codePane.getFont() 获取当前代码编辑区域的字体。 codePane.setFont(new Font(currentFont.getFontName(), currentFont.getStyle(), fontSize)); // 将新的字体大小应用到代码编辑区域的字体 //创建一个新的 Font 对象,并将原字体的字体名称、字体样式以及新的字体大小应用到该对象中。使用 codePane.setFont() 方法将新的字体设置为代码编辑区域的字体。 } else { //如果字体大小无效(小于等于 0),则使用 JOptionPane.showMessageDialog(this, "无效的字体大小。请输入一个正整数。") 显示一个错误消息对话框,提示用户输入一个有效的字体大小。 JOptionPane.showMessageDialog(this, "无效的字体大小。请输入一个正整数。"); // 显示无效字体大小的错误消息对话框 } } catch (NumberFormatException e) { JOptionPane.showMessageDialog(this, "无效输入。请输入有效的字体大小。"); // 显示无效输入的错误消息对话框 } } public static void main(String[] args) { SwingUtilities.invokeLater(() -> { CodeEditor editor = new CodeEditor(); // 创建代码编辑器对象 editor.setVisible(true); // 设置代码编辑器可见 }); }}
总结
在本实验中,我们实现了一个简单的文本编辑器(CodeEditor),该编辑器具有打开、保存、编译、运行代码等功能,并支持撤销、重做、缩放文本等操作。
#includeusing namespace std;int main(){ cout<<"看完了点个赞再走吧,谢谢啦(●'◡'●)❤"; return 0;}