时间:2025-11-05 17:04
人气:
作者:admin
好久没做golang开发了,之前的文章一直在做cli的安全工具开发,这里了解一下gui图形化的开发,后续目前还不知道能发什么了,主要是cli和gui这些无非都是将之前学过的集成在一起而已,我个人是感觉这个合集已经差不多完成了,若是还有在看我这个合集的师傅觉得还想看什么的可以给一些意见。
这里只使用 fyne 库,其他库不讨论。
拿这个来配置的好处就是不用安装,直接下载解压,然后配置环境变量即可

go env -w CGO_ENABLED=1
# 解释
Fyne 的相关源码⽂件带有 cgo 构建标签。你如果把 CGO_ENABLED=0 关掉了,带该标签的源码会被排除,编译器要么找不到实现,要么⾛到不兼容的路径,从⽽出现“build constraints exclude all Go files” 之类的错误。
反正跟着来就行了
go env -w GOOS=windows
# 若是linux就修改linux
go mod init 项目名; go mod tidypackage main
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/widget"
)
func main() {
myApp := app.New()
myWin := myApp.NewWindow("Hello")
myWin.SetContent(widget.NewLabel("Hello Fyne!"))
myWin.Resize(fyne.NewSize(200, 200))
myWin.ShowAndRun()
}
# 再次运行代码
go run main.go
下图中我的fyne没有用v2,我后面换了,我上面代码是正确的,只是图片中我忘记切换新版本的库了

func first_gui() {
myApp := app.New() // 创建一个app
myWin := myApp.NewWindow("Hello") // 创建一个窗口,之后就要放内容进这个窗口了,同时给这个窗口命名
myWin.SetContent(widget.NewLabel("Hello Fyne!")) //简单设置一个标签内容,然后用窗口的SetContent设置内容
myWin.Resize(fyne.NewSize(200, 200)) // 设置窗口大小
myWin.ShowAndRun() // Show显示和Run运行,这里其实是可以分开用两个函数执行,ShowAndRun就是一个命令执行了两个
}
没什么好说,直接看代码来的直接
widget.NewLabelwidget.NewButtonwidget.NewEntrySetReadOnly(true/false)设置是否只读SetPlaceHolder设置占位字符widget.NewEntry().MultiLine = true 这样设置可以多行文本widget.NewPasswordEntrywidget.NewEntry一样,只不过这里是密码的方式输入,所以输入的内容看不到NewMultiLineEntryMultiLine = true的方式进行多行输入widget.NewCheckwidget.NewRadioGroupwidget.NewRadio,v2的就用widget.NewRadioGroupwidget.NewSelectwidget.NewSliderwidget.NewProgressBarSetValue来控制进度条的滑动widget.NewProgressBarInfinitewidget.NewSeparatorwidget.NewVBoxwidget.NewCardcontainer来new一个box进行整合控件在某个容器里return即可(在basicWidgets函数中)穿插下container:container.NewVBox和 【container.NewScroll、container.NewHScroll】
container.NewVBoxcontainer.NewScrollwidget.NewSelectEntrywidget.NewAccordionwidget.NewAccordionItem来创建展开后的面板项目widget.NewForm// Form - 表单
nameEntry := widget.NewEntry()
ageEntry := widget.NewEntry()
genderRadio := widget.NewRadioGroup([]string{"男", "⼥"}, nil)
form := widget.NewForm(
widget.NewFormItem("姓名", nameEntry),
widget.NewFormItem("年龄", ageEntry),
widget.NewFormItem("性别", genderRadio),
)
form.OnSubmit = func() {
fmt.Printf("表单提交 - 姓名: %s, 年龄: %s, 性别: %s\n",
nameEntry.Text, ageEntry.Text, genderRadio.Selected)
}
form.OnCancel = func() {
fmt.Println("表单取消")
}
widget.NewTabContainerTabLocationBottom:显示在底部TabLocationLeading:显示在顶部左边TabLocationTrailing:显示在顶部右边tabs := widget.NewTabContainer(
widget.NewTabItem("Profile", profile),
widget.NewTabItem("Setting", setting),
)
myWindow.SetContent(tabs)
widget.NewToolbarNewToolbarAction创建然后第一个参数给图标,第二个参数给action动作
func fyne_toolbar() {
myApp := app.New()
myWindow := myApp.NewWindow("Toolbar")
toolbar := widget.NewToolbar(
widget.NewToolbarAction(theme.DocumentCreateIcon(), func() {
fmt.Println("New document")
}),
widget.NewToolbarSeparator(),
widget.NewToolbarAction(theme.ContentCutIcon(), func() {
fmt.Println("Cut")
}),
widget.NewToolbarAction(theme.ContentCopyIcon(), func() {
fmt.Println("Copy")
}),
widget.NewToolbarAction(theme.ContentPasteIcon(), func() {
fmt.Println("Paste")
}),
widget.NewToolbarSpacer(),
widget.NewToolbarAction(theme.HelpIcon(), func() {
log.Println("Display help")
}),
)
content := fyne.NewContainerWithLayout(
layout.NewBorderLayout(toolbar, nil, nil, nil),
toolbar, widget.NewLabel(`Lorem ipsum dolor,
sit amet consectetur adipisicing elit.
Quidem consectetur ipsam nesciunt,
quasi sint expedita minus aut,
porro iusto magnam ducimus voluptates cum vitae.
Vero adipisci earum iure consequatur quidem.`),
)
myWindow.SetContent(content)
myWindow.ShowAndRun()
}
首先我们的控件都是要放进box或者一个容器中,所以我们布局要学的东西在上面可能有看到过,只是没注意到这个是什么布局罢了
container.Newv2版本的fyne,旧版本记得是没有的container.NewVBoxcontainer.NewHBoxcontainer.NewBorderlayout.NewGridLayoutgridLayout := container.New(
layout.NewGridLayout(3), // 3列
widget.NewButton("1", nil),
widget.NewButton("2", nil),
widget.NewButton("3", nil),
widget.NewButton("4", nil),
widget.NewButton("5", nil),
widget.NewButton("6", nil),
)
container.NewGridWithColumnscontainer.NewGridWithRowscontainer.NewCentercontainer.NewMaxcontainer.NewStackcontainer.NewPaddedcontainer.NewScrollcontainer.NewWithoutLayout// 绝对定位容器
absolute := container.NewWithoutLayout(
widget.NewButton("按钮1", nil),
widget.NewButton("按钮2", nil),
widget.NewLabel("标签"),
)
// ⼿动设置位置和⼤⼩
// 容器里面的组件就按照你当初放的那样,进行一个数组访问即可
// Move移动,Resize重置大小
if len(absolute.Objects) >= 3 {
absolute.Objects[0].Move(fyne.NewPos(10, 10))
absolute.Objects[0].Resize(fyne.NewSize(100, 30))
absolute.Objects[1].Move(fyne.NewPos(120, 10))
absolute.Objects[1].Resize(fyne.NewSize(100, 30))
absolute.Objects[2].Move(fyne.NewPos(10, 50))
absolute.Objects[2].Resize(fyne.NewSize(210, 30))
}
return widget.NewCard("绝对定位布局", "", absolute)
这个就是一些遇到错误就弹框出来,或者删除保存弹出来让你确认之类的等等的一些弹框
dialog.ShowInformation(title, message, parentWindow)
dialog.ShowError(err, parentWindow)
dialog.ShowConfirm(title, message, func(confirmed bool), parentWindow)
NewCustom 与 NewCustomConfirm 的区别:
NewCustom:这个只有一个关闭按钮,NewCustomConfirm:会让你去“确认/取消”,然后拿到用户的确认或取消的结果进行一下步操作dialog.NewCustom(title, dismissText, content, parentWindow)
dialog.NewCustomConfirm(title, confirmText, dismissText, content, func(confirmed bool), parentWindow)
SetFilter(storage.NewExtensionFileFilter([]string{".txt"})) 限制可选可看到的文件后缀类型SetLocation(storage.NewFileURI(path)) 设置初始位置dialog.NewFileOpen(func(fyne.URIReadCloser, error), parentWindow)
dialog.NewFileSave(func(fyne.URIWriteCloser, error), parentWindow)
dialog.NewFolderOpen(func(fyne.ListableURI, error), parentWindow)
//限制可选可看到的文件后缀类型
SetFilter(storage.NewExtensionFileFilter([]string{".txt"}))
//设置初始位置
SetLocation(storage.NewFileURI(path))
fyne.Do去执行//通过SetValue设置进度
dialog.NewProgress(title, message, parentWindow)
//显示的是旋转,这里就不用setvalue了,没有进度大小
dialog.NewProgressInfinite(title, message, parentWindow)
在 Fyne v2.6.0 及以上版本中,如果你在 非主线程(例如在 goroutine 中)更新UI组件,必须使用 fyne.Do 或 fyne.DoAndWait 来包装这些操作
fyne.Do 与 fyne.DoAndWait:fyne.Do 会异步地将函数调度到主线程执行,不会阻塞你当前的 goroutine,适用于像更新进度条这样的场景。fyne.DoAndWait 则会同步等待函数在主线程执行完毕
如下图所示:很多测试单元函数被我注释了,想要运行哪个就自己解开,不能运行多个,只能一个一个的函数去运行,因为我没有单独把窗口app拎出来

package main
import (
"fmt"
"image/color"
"log"
"net/url"
"os"
"time"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget" // 导⼊扩展包
"github.com/flopp/go-findfont"
)
func fyne_test() {
myApp := app.New()
myWin := myApp.NewWindow("窗口标题")
myWin.SetContent(widget.NewLabel("label内容"))
myWin.Resize(fyne.NewSize(200, 200)) // 设置窗口大小
myWin.CenterOnScreen() // 窗口居中显示
// ---------------------------------
// 全屏
// myWin.SetFullScreen(true)
// 判断是否全屏
// isFullScrenn := myWin.FullScreen()
// fmt.Println(isFullScrenn)
// ---------------------------------
// ---------------------------------
// 主窗口设置
myWin.SetMaster()
mainMenu := fyne.NewMainMenu(
fyne.NewMenu(
"文件",
fyne.NewMenuItem("新建", func() { fmt.Println("点击了新建") }),
fyne.NewMenuItem("打开", func() { fmt.Println("点击了打开") }),
fyne.NewMenuItem("推出", func() { myApp.Quit() }),
),
)
myWin.SetMainMenu(mainMenu)
// ---------------------------------
// 拦截关闭事件
myWin.SetCloseIntercept(func() {
dialog.ShowConfirm("确认", "确定要退出吗?", func(ok bool) {
if ok {
myApp.Quit()
}
}, myWin)
})
myWin.ShowAndRun() //运行
}
// 更新时间
func time_clock() {
updateTime := func(clock *widget.Label) {
formatted := time.Now().Format("Time: 03:04:05") //获取格式化时间
clock.SetText(formatted)
}
app := app.New() // 创建应用程序实例
window := app.NewWindow("Hello world") // 创建窗口,标题为"Hello Wolrd"
clock := widget.NewLabel("")
updateTime(clock)
go func() {
for range time.Tick(time.Second) {
updateTime(clock) // 每秒更新一次时间
}
}()
window.SetContent(clock) // 往窗口中放入一个内容为"Hello world!"的标签控件
window.ShowAndRun() //展示并运行程序
}
// 基础控件
func basicWidgets() fyne.CanvasObject {
// 1. Label - ⽂本标签
label := widget.NewLabel("这是⼀个标签")
// 2. Button - 按钮
button := widget.NewButton("点击我", func() {
fmt.Println("按钮被点击")
})
// 3. Entry - 单⾏输⼊框
entry := widget.NewEntry()
entry.SetPlaceHolder("请输⼊⽂本..")
// 4. PasswordEntry - 密码输⼊框
passwordEntry := widget.NewPasswordEntry()
passwordEntry.SetPlaceHolder("输⼊密码...")
// 5. MultiLineEntry - 多⾏⽂本输⼊
multiEntry := widget.NewMultiLineEntry()
multiEntry.SetPlaceHolder("多⾏⽂本...")
multiEntry.Resize(fyne.NewSize(300, 100))
// 6. Check - 复选框
check := widget.NewCheck("同意条款", func(checked bool) {
fmt.Println("复选框状态:", checked)
})
// 7. RadioGroup - 单选按钮组
radio := widget.NewRadioGroup([]string{"选项1", "选项2", "选项3"}, func(value string) {
fmt.Println("选中:", value)
})
// 8. Select - 下拉选择框
selectWidget := widget.NewSelect([]string{"苹果", "⾹蕉", "橙⼦"}, func(value string) {
fmt.Println("选择了:", value)
})
// 9. Slider - 滑块
slider := widget.NewSlider(0, 100)
slider.OnChanged = func(value float64) {
fmt.Printf("滑块值: %.2f", value)
}
// 10. ProgressBar - 进度条
progress := widget.NewProgressBar()
progress.SetValue(0.5) // 50%
// 11. ProgressBarInfinite - ⽆限进度条
infiniteProgress := widget.NewProgressBarInfinite()
// 12. Hyperlink - 超链接
link, _ := url.Parse("https://fyne.io")
hyperlink := widget.NewHyperlink("访问 Fyne 官⽹", link)
// 13. Separator - 分隔线
separator := widget.NewSeparator()
return container.NewVBox(
widget.NewCard("基础控件", "", container.NewVBox(
label,
button,
entry,
passwordEntry,
multiEntry,
check,
radio,
selectWidget,
slider,
progress,
infiniteProgress,
hyperlink,
separator,
)),
)
}
func basicwidget_test() {
myapp := app.New()
w := myapp.NewWindow("基础控件⽰例")
widgets := basicWidgets()
w.SetContent(widgets)
w.ShowAndRun()
}
// 高级控件
func advancedWidgets() fyne.CanvasObject {
// 1. Form - 表单
nameEntry := widget.NewEntry()
ageEntry := widget.NewEntry()
genderRadio := widget.NewRadioGroup([]string{"男", "⼥"}, nil)
form := widget.NewForm(
widget.NewFormItem("姓名", nameEntry),
widget.NewFormItem("年龄", ageEntry),
widget.NewFormItem("性别", genderRadio),
)
form.OnSubmit = func() {
fmt.Printf("表单提交 - 姓名: %s, 年龄: %s, 性别: %s\n",
nameEntry.Text, ageEntry.Text, genderRadio.Selected)
}
form.OnCancel = func() {
fmt.Println("表单取消")
}
// 2. 日期选择器 - 自定义实现
selectedDateLabel := widget.NewLabel("未选择日期")
dateEntry := widget.NewEntry()
dateEntry.SetPlaceHolder("YYYY-MM-DD")
dateButton := widget.NewButton("选择今日", func() {
today := time.Now().Format("2006-01-02")
dateEntry.SetText(today)
selectedDateLabel.SetText("选中日期: " + today)
fmt.Println("选择的日期:", today)
})
dateContainer := container.NewVBox(
selectedDateLabel,
dateEntry,
dateButton,
)
// 3. SelectEntry - 可输⼊的下拉框
selectEntry := widget.NewSelectEntry([]string{"选项1", "选项2", "选项3"})
selectEntry.PlaceHolder = "输⼊或选择..."
selectEntry.OnChanged = func(value string) {
fmt.Println("选择或输⼊:", value)
}
// 4. Accordion - 折叠⾯板
accordion := widget.NewAccordion(
widget.NewAccordionItem("基本信息",
container.NewVBox(
widget.NewLabel("这是基本信息⾯板"),
widget.NewEntry(),
)),
widget.NewAccordionItem("⾼级设置",
container.NewVBox(
widget.NewLabel("这是⾼级设置⾯板"),
widget.NewCheck("启⽤⾼级功能", nil),
)),
widget.NewAccordionItem("其他选项",
container.NewVBox(
widget.NewLabel("这是其他选项⾯板"),
widget.NewSlider(0, 100),
)),
)
// //左右滑动的container
// scrollContainer := container.NewHScroll(container.NewVBox(
// widget.NewLabel("这是左滑的"),
// widget.NewLabel("这是右滑的"),
// ))
// 组合所有控件 上下滑动
return container.NewScroll(container.NewVBox(
widget.NewCard("表单控件", "", form),
widget.NewCard("⽇期选择", "", container.NewVBox(
dateContainer,
widget.NewSeparator(),
)),
widget.NewCard("可输⼊下拉框", "", selectEntry),
widget.NewCard("折叠⾯板", "", accordion),
))
}
func advancedWidgets_test() {
myapp := app.New()
w := myapp.NewWindow("高级控件⽰例")
widgets := advancedWidgets()
w.SetContent(widgets)
w.ShowAndRun()
}
// 假设你使用的是旧版本,不是v2以上的,那若你有中文的话,就需要进行中文字体设置
func packet_myfont() {
fontPath, err := findfont.Find("FontLibrary/MSYHBD.TTC") // 这个字体文件直接找自己喜欢的即可,能成功加载路径即可
if err != nil {
panic(err)
}
// load the font with the freetype library
// fontData, err := os.ReadFile(fontPath)
// if err != nil {
// panic(err)
// }
// _, err = truetype.Parse(fontData)
// if err != nil {
// panic(err)
// }
os.Setenv("FYNE_FONT", fontPath)
}
// 画布练习
func fyne_canvas() {
myApp := app.New()
myWin := myApp.NewWindow("画布测试")
myWin.Resize(fyne.NewSize(400, 300))
myWin.ShowAndRun()
}
// 工具栏练习
func fyne_toolbar() {
myApp := app.New()
myWindow := myApp.NewWindow("Toolbar")
toolbar := widget.NewToolbar(
widget.NewToolbarAction(theme.DocumentCreateIcon(), func() {
fmt.Println("New document")
}),
widget.NewToolbarSeparator(),
widget.NewToolbarAction(theme.ContentCutIcon(), func() {
fmt.Println("Cut")
}),
widget.NewToolbarAction(theme.ContentCopyIcon(), func() {
fmt.Println("Copy")
}),
widget.NewToolbarAction(theme.ContentPasteIcon(), func() {
fmt.Println("Paste")
}),
widget.NewToolbarSpacer(),
widget.NewToolbarAction(theme.HelpIcon(), func() {
log.Println("Display help")
}),
)
content := fyne.NewContainerWithLayout(
layout.NewBorderLayout(toolbar, nil, nil, nil),
toolbar, widget.NewLabel(`Lorem ipsum dolor,
sit amet consectetur adipisicing elit.
Quidem consectetur ipsam nesciunt,
quasi sint expedita minus aut,
porro iusto magnam ducimus voluptates cum vitae.
Vero adipisci earum iure consequatur quidem.`),
)
myWindow.SetContent(content)
myWindow.ShowAndRun()
}
// 相对布局练习
func fyne_Layouts() {
myApp := app.New()
myWin := myApp.NewWindow("Layouts")
// 设置窗⼝⼤⼩
myWin.Resize(fyne.NewSize(600, 700))
// 1. BoxLayout - 垂直布局
vboxLayout := container.NewVBox(
widget.NewLabel("垂直布局 - 项⽬1"),
widget.NewLabel("垂直布局 - 项⽬2"),
widget.NewButton("按钮", nil),
)
// 2. BoxLayout - ⽔平布局
hboxLayout := container.NewHBox(
widget.NewLabel("⽔平1"),
widget.NewLabel("⽔平2"),
widget.NewButton("按钮", nil),
)
// 3. BorderLayout - 边框布局
borderLayout := container.NewBorder(
widget.NewLabel("顶部"), // top
widget.NewLabel("底部"), // bottom
widget.NewLabel("左侧"), // left
widget.NewLabel("右侧"), // right
widget.NewLabel("中⼼内容"), // center
)
// 4. GridLayout - 固定列数⽹格
gridLayout := container.New(
layout.NewGridLayout(3), // 3列
widget.NewButton("1", nil),
widget.NewButton("2", nil),
widget.NewButton("3", nil),
widget.NewButton("4", nil),
widget.NewButton("5", nil),
widget.NewButton("6", nil),
)
// 5. GridWithColumns - 指定列数的⽹格
gridWithColumns := container.NewGridWithColumns(2,
widget.NewLabel("单元格 1"),
widget.NewLabel("单元格 2"),
widget.NewLabel("单元格 3"),
widget.NewLabel("单元格 4"),
)
// 6. GridWithRows - 指定⾏数的⽹格
gridWithRows := container.NewGridWithRows(3,
widget.NewLabel("⾏ 1"),
widget.NewLabel("⾏ 2"),
widget.NewLabel("⾏ 3"),
)
// 7. CenterLayout - 居中布局
centerLayout := container.NewCenter(
widget.NewLabel("居中的内容"),
)
// 8. MaxLayout - 最⼤化布局(重叠)
maxLayout := container.NewMax(
canvas.NewRectangle(color.RGBA{R: 100, G: 100, B: 100, A: 255}),
container.NewCenter(widget.NewLabel("覆盖在矩形上")),
)
// 9. StackLayout - 堆叠布局
stackLayout := container.NewStack(
canvas.NewRectangle(color.RGBA{R: 200, G: 0, B: 0, A: 100}),
container.NewCenter(widget.NewLabel("堆叠内容")),
)
// 10. PaddedLayout - 带内边距的布局
paddedLayout := container.NewPadded(
widget.NewButton("有内边距的按钮", nil),
)
w := container.NewScroll(container.NewVBox(
widget.NewCard("VBox 垂直布局", "", vboxLayout),
widget.NewCard("HBox ⽔平布局", "", hboxLayout),
widget.NewCard("Border 边框布局", "", borderLayout),
widget.NewCard("Grid ⽹格布局", "", gridLayout),
widget.NewCard("GridWithColumns", "", gridWithColumns),
widget.NewCard("GridWithRows", "", gridWithRows),
widget.NewCard("Center 居中布局", "", centerLayout),
widget.NewCard("Max 最⼤化布局", "", maxLayout),
widget.NewCard("Stack 堆叠布局", "", stackLayout),
widget.NewCard("Padded 内边距布局", "", paddedLayout),
))
myWin.SetContent(w)
myWin.ShowAndRun()
}
// 绝对布局练习
func fyne_absolute_layout() {
myApp := app.New()
myWin := myApp.NewWindow("绝对定位布局")
myWin.Resize(fyne.NewSize(300, 200))
// 绝对定位容器
absolute := container.NewWithoutLayout(
widget.NewButton("按钮1", nil),
widget.NewButton("按钮2", nil),
widget.NewLabel("标签"),
)
// ⼿动设置位置和⼤⼩
// 容器里面的组件就按照你当初放的那样,进行一个数组访问即可
// Move移动,Resize重置大小
if len(absolute.Objects) >= 3 {
absolute.Objects[0].Move(fyne.NewPos(10, 10))
absolute.Objects[0].Resize(fyne.NewSize(100, 30))
absolute.Objects[1].Move(fyne.NewPos(120, 10))
absolute.Objects[1].Resize(fyne.NewSize(100, 30))
absolute.Objects[2].Move(fyne.NewPos(10, 50))
absolute.Objects[2].Resize(fyne.NewSize(210, 30))
}
w := widget.NewCard("绝对定位布局", "", absolute)
myWin.SetContent(w)
myWin.ShowAndRun()
}
func fyne_dialog_for_NewProgess() {
myApp := app.New()
myWindow := myApp.NewWindow("Determinate Progress Example")
progressInfo := widget.NewLabel("准备开始...")
button := widget.NewButton("开始任务", func() {
// 创建进度对话框,初始进度0%
progDialog := dialog.NewProgress("处理中", "正在进行一项耗时的确定性任务...", myWindow)
progDialog.Show()
totalSteps := 100
// 使用 fyne.Do 确保初始设置在主线程执行
fyne.Do(func() {
progDialog.SetValue(0) // 确保从0开始
})
// 模拟任务进度更新
go func() {
for i := 0; i <= totalSteps; i++ {
currentI := i // 创建局部变量避免闭包问题
currentProgress := float64(currentI) / float64(totalSteps)
if currentI == totalSteps {
time.Sleep(500 * time.Millisecond) // 最后稍作停顿
// 使用 fyne.Do 包装UI更新
fyne.Do(func() {
progDialog.SetValue(1.0) // 完成时设置为1.0 (100%)
progressInfo.SetText("任务完成!")
})
time.Sleep(500 * time.Millisecond)
fyne.Do(func() {
progDialog.Hide() // 完成任务后隐藏
})
return
}
// 使用 fyne.Do 包装所有UI更新操作
fyne.Do(func() {
progDialog.SetValue(currentProgress) // 更新进度 (0.0 到 1.0)
progressInfo.SetText(fmt.Sprintf("进度: %d/%d", currentI, totalSteps))
})
time.Sleep(50 * time.Millisecond) // 模拟工作
}
}()
})
content := container.NewVBox(progressInfo, button)
myWindow.SetContent(content)
myWindow.Resize(fyne.NewSize(400, 200))
myWindow.ShowAndRun()
}
func fyne_dialog_for_NewProgessInfinite() {
myApp := app.New()
myWindow := myApp.NewWindow("Infinite Progress Example")
statusLabel := widget.NewLabel("等待操作...")
startButton := widget.NewButton("开始不确定任务", func() {
// 创建无限进度对话框
infiniteDialog := dialog.NewProgressInfinite("请等待", "正在进行一项不确定时间的任务...", myWindow)
infiniteDialog.Show()
fyne.Do(func() {
statusLabel.SetText("任务进行中...")
})
// 模拟一个耗时不确定的任务
go func() {
time.Sleep(5 * time.Second) // 模拟工作,比如网络请求
// 使用 fyne.Do 包装UI更新
fyne.Do(func() {
infiniteDialog.Hide() // 任务完成后隐藏对话框
statusLabel.SetText("不确定任务已完成!")
})
}()
})
content := container.NewVBox(statusLabel, startButton)
myWindow.SetContent(content)
myWindow.Resize(fyne.NewSize(400, 200))
myWindow.ShowAndRun()
}
func test_Progess() {
//这里是手动切换调用哪个的函数方法, 我在main中调用他这个函数即可
// fyne_dialog_for_NewProgess()
fyne_dialog_for_NewProgessInfinite()
}
func main() {
// packet_myfont() //设置中文字体,不乱码
// fyne_test()
// basicwidget_test()
// advancedWidgets_test()
// time_clock()
// fyne_canvas() //画布测试
// fyne_toolbar() // 工具栏
// fyne_Layouts() // 相对布局测试
// fyne_absolute_layout() // 绝对布局测试
test_Progess() //进度条测试
}
本文来自博客园,作者:竹等寒,转载请注明原文链接。