构建一个Markdown编辑器:Fyne综合案例

在本文中,我们将通过一个完整的案例来介绍如何使用Go语言的Fyne库来构建一个简单的Markdown编辑器。Fyne是一个易于使用的库,它允许开发者使用Go语言来创建跨平台的GUI应用程序。

1. 项目结构

首先,我们需要创建一个Go项目,并引入Fyne库。我们的项目结构如下:
在这里插入图片描述

2. 编写代码

接下来,我们将编写main.go文件,实现Markdown编辑器的基本功能。

package mainimport ("fyne.io/fyne/v2""fyne.io/fyne/v2/app""fyne.io/fyne/v2/container""fyne.io/fyne/v2/dialog""fyne.io/fyne/v2/storage""fyne.io/fyne/v2/widget""io""strings"
)// config 结构体用于存储应用程序的配置
type config struct {Edit        *widget.EntryPreview     *widget.RichTextCurrentFile fyne.URIMenuItem    *fyne.MenuItemBaseTitle   string
}var cfg config                                                      // 定义一个全局的config变量
var filter = storage.NewExtensionFileFilter([]string{".md", ".MD"}) // 定义一个文件过滤器,只允许.md文件// main 函数是程序的入口点
func main() {a := app.NewWithID("01") // 创建一个新的Fyne应用程序// 加载自定义字体,并设置为应用程序主题字体customFont := fyne.NewStaticResource("NotoSansHans.ttf", loadFont("NotoSansHans-Regular.ttf"))a.Settings().SetTheme(&myTheme{font: customFont})// 创建一个新的窗口,并设置窗口的标题w := a.NewWindow("Markdown编辑器")cfg.BaseTitle = "Markdown编辑器"// 创建UI组件,并保存到config结构体中edit, preview := cfg.makeUI()// 创建窗口的菜单,并绑定相关功能cfg.createMenu(w)// 设置窗口的内容为编辑和预览的分割布局w.SetContent(container.NewHSplit(edit, preview))// 设置窗口的初始大小,并居中显示在屏幕上w.Resize(fyne.NewSize(800, 600))w.CenterOnScreen()// 显示窗口,并启动应用程序的事件循环w.ShowAndRun()
}// makeUI 方法用于创建Markdown编辑器的UI组件
func (cfg *config) makeUI() (*widget.Entry, *widget.RichText) {// 创建一个多行输入框用于编辑Markdownedit := widget.NewMultiLineEntry()// 创建一个富文本组件用于显示Markdown预览preview := widget.NewRichTextFromMarkdown("")// 将编辑和预览组件保存到config结构体中cfg.Edit = editcfg.Preview = preview// 当编辑区域内容变化时,更新预览区域edit.OnChanged = preview.ParseMarkdownreturn edit, preview // 返回编辑和预览组件
}// createMenu 方法用于创建窗口的菜单项
func (cfg *config) createMenu(win fyne.Window) {// 创建“打开”、“保存”、“另存为”菜单项,并绑定相关功能open := fyne.NewMenuItem("打开", cfg.openFunc(win))save := fyne.NewMenuItem("保存", cfg.saveFunc(win))cfg.MenuItem = savecfg.MenuItem.Disabled = truesaveAs := fyne.NewMenuItem("另存为...", cfg.saveAsFunc(win))// 创建“文件”菜单,并包含上述菜单项fileMenu := fyne.NewMenu("文件", open, save, saveAs)// 创建窗口的主要菜单,并设置到窗口中menu := fyne.NewMainMenu(fileMenu)win.SetMainMenu(menu)
}// saveAsFunc 方法用于实现“另存为”功能的逻辑
// 参数:
//
//	win - fyne.Window类型,表示当前窗口对象
//
// 返回值:
//
//	一个func()类型的闭包函数,用于在调用时触发文件保存逻辑
func (cfg *config) saveAsFunc(win fyne.Window) func() {// 返回一个闭包函数,用于处理文件保存逻辑return func() {// 创建一个文件保存对话框,并设置相关参数saveDialog := dialog.NewFileSave(func(write fyne.URIWriteCloser, err error) {if err != nil {// 如果出现错误,显示错误对话框dialog.ShowError(err, win)return}if write == nil {// 如果用户取消保存,直接返回return}if !strings.HasSuffix(strings.ToLower(write.URI().String()), ".md") {// 确保文件具有.md扩展名,否则提示用户dialog.ShowInformation("错误", "必须是.md扩展名", win)return}// 将编辑器的内容写入文件write.Write([]uint8(cfg.Edit.Text))// 更新当前文件路径cfg.CurrentFile = write.URI()// 关闭文件写入器defer write.Close()// 更新窗口标题win.SetTitle(cfg.BaseTitle + "_" + write.URI().Name())// 禁用菜单项,防止重复保存cfg.MenuItem.Disabled = true}, win)// 设置对话框的默认文件名和过滤器saveDialog.SetFileName("未命名.md")saveDialog.SetFilter(filter)// 显示对话框saveDialog.Show()}
}// openFunc 生成一个用于打开文件的函数。
// 该函数在被调用时,会显示一个文件选择对话框,允许用户选择一个文件进行打开。
// 参数win是用于父窗口的引用,用于关联打开对话框和错误对话框。
func (cfg *config) openFunc(win fyne.Window) func() {return func() {// 创建并配置文件打开对话框openDialog := dialog.NewFileOpen(func(read fyne.URIReadCloser, err error) {if err != nil {// 如果有错误发生,显示错误对话框dialog.ShowError(err, win)return}if read == nil {// 如果用户取消了操作,read将为nil,直接返回return}// 读取文件内容data, err := io.ReadAll(read)if err != nil {// 如果读取文件时发生错误,显示错误对话框dialog.ShowError(err, win)return}// 设置编辑区域的文本为打开的文件内容cfg.Edit.SetText(string(data))// 更新当前文件的路径cfg.CurrentFile = read.URI()// 更新窗口标题为文件名win.SetTitle(cfg.BaseTitle + "-" + read.URI().Name())// 允许菜单项的操作cfg.MenuItem.Disabled = false// 确保读取器在使用后关闭defer read.Close()}, win)// 设置文件过滤器openDialog.SetFilter(filter)// 显示文件打开对话框openDialog.Show()}
}// saveFunc 生成一个用于保存配置的函数。
// 该函数接受一个 fyne.Window 参数,但实际保存操作并不依赖于窗口参数本身。
// 主要用于统一保存配置的处理逻辑,无论配置是否关联到了一个特定的文件。
// 如果配置关联到了一个文件(CurrentFile 不为 nil),则会尝试将配置内容写入该文件。
// 如果写入过程中出现错误,将通过对话框展示错误信息。
// 返回的函数无参数,无返回值。
func (cfg *config) saveFunc(win fyne.Window) func() {return func() {// 检查是否有当前文件if cfg.CurrentFile != nil {// 尝试获取当前文件的写入器write, err := storage.Writer(cfg.CurrentFile)// 如果获取写入器过程中出现错误,则展示错误信息并返回if err != nil {dialog.ShowError(err, win)return}// 写入配置文本到文件write.Write([]byte(cfg.Edit.Text))// 确保写入器关闭defer write.Close()}}
}

3. 运行应用程序

要运行我们的Markdown编辑器,我们需要在终端中执行以下命令:

go run main.go

这将启动我们的应用程序,并显示一个具有编辑和预览功能的Markdown编辑器窗口。

4. 扩展功能

虽然我们的编辑器目前只支持基本的Markdown编辑和预览功能,但Fyne库的强大功能允许我们轻松扩展更多特性,例如:

  • 支持更多的Markdown扩展语法。
  • 实现语法高亮。
  • 添加导出为PDF或其他格式的功能。
  • 实现云同步功能。

5. 结语

通过本文的案例,我们可以看到Fyne库在构建跨平台GUI应用程序方面的强大能力。Markdown编辑器只是一个起点,Fyne可以帮助我们构建更复杂的应用程序。

希望这个案例能够启发你使用Fyne来创建你自己的应用程序。如果你有任何问题或需要进一步的帮助,请随时联系我们。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/403368.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux进程间通信——SystemV共享内存

文章目录 System V共享内存创建内存共享释放共享内存命令行shmctlshmatshmdt System V共享内存 System V是一种进程间通信的标准,在这种标准之下,本地通信的方式一般由三种,内存共享、消息队列、信号量 这里我们主要介绍共享内存 创建内存…

Shell参考 - Linux Shell 训练营

出品方<Linux.cn & 阿里云开发者学堂> 一&#xff0c;Linux 可以划分为以下四个部分&#xff1a; 1. 应用软件 2. 窗口管理软件 Unity Gnome KDE 3. GNU 系统工具链 Software- GNU Project - Free Software Foundation 4. Linux 内核 二&#xff0c;什么是shell 1. L…

达梦数据库的系统视图v$database

达梦数据库的系统视图v$database 达梦数据库&#xff08;DM Database&#xff09;提供了多个系统视图&#xff0c;以便管理员能够监控和管理数据库的运行状态和性能。V$DATABASE 是其中一个关键系统视图&#xff0c;它包含有关数据库全局状态和配置的综合信息。 V$DATABASE 系…

Linux 软件编程学习第十五天

1.TCP粘包问题&#xff1a; TCP发送数据是连续的&#xff0c;两次发送的数据可能粘连成一包被接收到 1.解决粘包问题方法&#xff1a; 1.接收指定长度&#xff1a;&#xff08;不稳定&#xff09; 发送5个字节 接收5个字节 2.睡眠&#x…

Java | Leetcode Java题解之第342题4的幂

题目: 题解&#xff1a; class Solution {public boolean isPowerOfFour(int n) {return n > 0 && (n & (n - 1)) 0 && n % 3 1;} }

【数据结构算法经典题目刨析(c语言)】使用数组实现循环队列(图文详解)

&#x1f493; 博客主页&#xff1a;C-SDN花园GGbond ⏩ 文章专栏&#xff1a;数据结构经典题目刨析(c语言) 目录 一.题目描述 二.解题思路 1.循环队列的结构定义 2.队列初始化 3.判空 4.判满 5.入队列 6.出队列 7.取队首元素 8.取队尾元素 三.完整代码实…

接入谷歌支付配置

1.谷歌云创建项目 网址&#xff1a;https://console.cloud.google.com/ 按照步骤创建即可 创建好后选择项目&#xff0c;转到项目设置 选择服务账户&#xff0c;选择创建新的服务账户 名称输入好后访问权限吗账号权限都可以不用填写&#xff0c;默认就好了 然后点击电子邮…

企业高性能web服务器

目录 一.Web 服务基础介绍 1.1 Web 服务介绍 1.2.1 Apache 经典的 Web 服务端 1.2.1.1 Apache prefork 模型 1.2.1.2 Apache worker 模型 1.2.1.3 Apache event模型 1.2.2 Nginx-高性能的 Web 服务端 1.2.3 影响用户体验的因素 1.2.4 服务端 I/O 流程 1.2.4.1 磁盘 I…

【详细】linux 打包QT程序

【详细】linux 打包QT程序 一. 安装linuxdeployqt1.1 下载linuxdeployqt源码并修改如下 二. 安装patchelf三. 打包appimage四. 打包成 Debian包4.1 control文件内容4.2 postinst文件内容4.3 postrm文件内容4.4 打包命令4.4 安装命令4.5 卸载命令 一. 安装linuxdeployqt 下载地…

Gin框架接入Prometheus,grafana辅助pprof检测内存泄露

prometheus与grafana的安装 grom接入Prometheus,grafana-CSDN博客 Prometheus 动态加载 我们想给Prometheus新增监听任务新增ginapp项目只需要在原来的配置文件下面新增ginapp相关metric 在docker compose文件下面新增 执行 docker-compose up -d curl -X POST http://lo…

复现dom破坏案例和靶场

文章目录 靶场网址第一个实验步骤和原理(代码为示例要根据自己的实验修改) 第二个实验步骤和原理(代码为示例要根据自己的实验修改) 靶场网址 注册后点击 第一个实验 此实验室包含一个 DOM 破坏漏洞。注释功能允许“安全”HTML。为了解决这个实验&#xff0c;请构造一个 HT…

依赖注入+中央事件总线:Vue 3组件通信新玩法

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vue篇专栏内容:Vue-依赖注入-中央事件总线 目录 中央事件总线使用 依赖注入使用 总结 中央事件总线 依赖注入…

【TiDB】09-修改tidb客户端访问密码

目录 1、修改配置文件 2、停止tidb-server 3、以root方式启动脚本 4、修改密码 5、停止脚本重启服务 1、修改配置文件 进入tidb-server默认部署位置 #切换tidb账号 su tidb# 进入tidb-server部署路径 cd /tidb-deploy/tidb-4000# 修改配置 vim ./conf/tidb.toml添加内容…

Datawhale AI 夏令营 第四期 AIGC Task3

活动简介 活动链接&#xff1a;Datawhale AI 夏令营&#xff08;第四期&#xff09; 以及AIGC里面的本次任务说明&#xff1a;Task 3 进阶上分-实战优化 这次任务呢&#xff0c;主要是对知识的一个讲解&#xff0c;包括ComfyUI工具的使用啊&#xff0c;以及LoRA的原理啊&…

学习记录第三十天

管道&#xff1a; 无名管道&#xff1a;只能用于亲缘关系进程之间的通信&#xff1a; 有名管道&#xff1a;是一种特殊的文件&#xff0c;存在于内存中&#xff0c;在系统中有对应的名称&#xff0c;文件大小为0字节&#xff1b; 编程&#xff1a; Linux系统中&#xff0c;…

Deepin-获取屏幕缩放比例

Deepin-获取屏幕缩放比例 一、概述二、实现代码 一、概述 环境&#xff1a;UOS、Deepin 我的目的是为了获取屏幕的缩放比例值&#xff0c;就是获取如下的值 我们可以去读取当前的环境变量值&#xff0c;在Qt Creator中可以看到这个值 二、实现代码 相关的Qt接口如下&…

串口通信协议(hal库)

目录 串口通信协议 串行/并行 同步/异步 单工/半双工/全双工 DR寄存器 轮询方式 中断方式 主要中断事件&#xff1a; DMA方式 USART 模块的常用 HAL 库常用接口函数 串口通信协议 串口通信&#xff08;Serial Communication&#xff09;指的是数据通过一个串行的通道…

前端如何使用Nginx代理dist网页,代理websocket,代理后端

本文将指导您如何配置Nginx以代理前后端分离的项目&#xff0c;并特别说明了对WebSocket的代理设置。通过本教程&#xff0c;您将能够实现一次性配置&#xff0c;进而使项目能够在任意局域网服务器上部署&#xff0c;并可通过IP地址或域名访问服务。 笔者建议 先速览本文了解大…

Java、python、php版的企业单位考勤打卡管理系统的设计与实现(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

C语言-使用数组法,指针法实现将一个5X5的矩阵中最大的元素放在中心,四个角分别放四个最小的元素(顺序为从左到右,从上到下,从小到大存放),写一函数实现之。

1.题目要求&#xff1a; 将一个5X5的矩阵中最大的元素放在中心&#xff0c;四个角分别放四个最小的元素&#xff08;顺序为从左到右&#xff0c;从上到下&#xff0c;从小到大存放&#xff09;&#xff0c;写一函数实现之。 2.数组法实现 #define _CRT_SECURE_NO_WARNINGS 1…