博主:命运之光

专栏:Python星辰秘典

专栏:web开发(html css js)

❤️专栏: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() {@Overridepublic 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() {@Overridepublic 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.1applyZoom();// 应用新的缩放比例}/** * 缩小文本缩放比例。 */private void zoomOut() {zoomScale -= 0.1; // 将缩放比例减少0.1applyZoom();// 应用新的缩放比例}/** * 应用当前的缩放比例到代码编辑区域的字体大小。 */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  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, "无效输入。请输入有效的字体大小。"); // 显示无效输入的错误消息对话框}}/** * 主方法,程序的入口点。在Swing事件调度线程中创建并显示代码编辑器。 * 在主方法中,使用SwingUtilities.invokeLater() 方法调度创建和显示代码编辑器的任务, * 确保在正确的线程上进行Swing组件的创建和更新操作。 */public static void main(String[] args) {/* * 使用 SwingUtilities.invokeLater() 方法 * 来确保在事件分派线程(Event Dispatch Thread)中执行代码。 * 这是因为 Swing 组件需要在事件分派线程中进行操作,以保证界面的响应性和线程安全性。 * */SwingUtilities.invokeLater(() -> {/* * SwingUtilities.invokeLater(() -> {...}) * 使用 Lambda 表达式创建一个 Runnable 对象,其中的代码会在事件分派线程中执行。*/CodeEditor editor = new CodeEditor();// 创建代码编辑器对象editor.setVisible(true);// 设置代码编辑器可见});}}

总结

在本实验中,我们实现了一个简单的文本编辑器(CodeEditor),该编辑器具有打开、保存、编译、运行代码等功能,并支持撤销、重做、缩放文本等操作。

#includeusing namespace std;int main(){cout<<"看完了点个赞再走吧,谢谢啦(●'◡'●)❤";return 0;}