其他分享
首页 > 其他分享> > fyne编写简单桌面应用

fyne编写简单桌面应用

作者:互联网

应用的效果图

fyne项目解决问题

1. 中文字体

// 设置系统环境的字体常量
os.Setenv("FYNE_FONT", path)

2. 动态绑定

//先用string切片, string中##连接属性,再分割成struct
var vmStrList binding.ExternalStringList
vmStrList = binding.BindStringList(&[]string{})

项目主要代码

main.go

package main

import (
	"image/color"
	"log"
	"os"
	"runtime"
	"strings"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/canvas"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/data/binding"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/driver/desktop"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
	"github.com/flopp/go-findfont"
	"github.com/go-vgo/robotgo"

	"ovirtClient/application"
)

var logger *log.Logger

var colorDanger = color.NRGBA{207, 19, 34, 255}
var colorSuccess = color.NRGBA{56, 158, 13, 255}
var colorFail = color.NRGBA{144, 147, 153, 255}
var colorWarning = color.NRGBA{212, 136, 6, 255}

func init() {
	// 设置中文字体
	fontPaths := findfont.List()
	for _, path := range fontPaths {
		if strings.Contains(path, "cangerw02.ttf") || strings.Contains(path, "simhei.ttf") || strings.Contains(path, "simsun.ttc") || strings.Contains(path, "simkai.ttf") {
			os.Setenv("FYNE_FONT", path)
			break
		}
	}
	// 日志文件
	file := "./vmclient" + time.Now().Format("20180102") + ".log"
	logFile, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)
	if err != nil {
		panic(err)
	}
	logger = log.New(logFile, "", log.LstdFlags)
}

func main() {

	app := app.New()
	// 自定义主题
	// app.Settings().SetTheme(&ThemeDefault{})
	themeDiy := theme.LightTheme()
	app.Settings().SetTheme(themeDiy)

	// 窗口设置
	var window fyne.Window
	if runtime.GOOS == "linux" {
		drv, _ := app.Driver().(desktop.Driver)
		window = drv.CreateSplashWindow()
		window.SetTitle("ovirtClient-v1.0.0")
		// 屏幕最大值
		width, height := robotgo.GetScreenSize()
		window.Resize(fyne.NewSize(float32(width), float32(height-1)))
	} else {
		window = app.NewWindow("ovirtClient-v1.0.0")
	}
	window.SetIcon(resourceStaticAppPng)

	// 数据预处理
	// 获取本地登录信息
	strUsername := binding.NewString()
	strPassword := binding.NewString()
	strDatacenter := binding.NewString()
	resultLoginInfo := application.LoginInfoGet()
	// ######################虚拟机选择#######################
	var vmStrList binding.ExternalStringList
	vmStrList = binding.BindStringList(&[]string{})
	// 用户自动登录
	if resultLoginInfo.ErrorCode <= 0 && resultLoginInfo.Info.Username != "" {
		vmListResult := application.VmList()
		logger.Println("自动登录vmList=", vmListResult.VmList)
		vmStrList.Set([]string{})
		for _, vmInfo := range vmListResult.VmList {
			vmStrList.Append(vmInfo.Name + "##" + vmInfo.System + "##" + vmInfo.Status + "##" + vmInfo.Description)
		}
	} else {
		vmStrList.Append("##" + "##no_login##")
	}

	// 系统icon
	// imgWin7 := canvas.NewImageFromResource(resourceWindows7Png)
	// imgWin7.FillMode = canvas.ImageFillContain
	// imgWin7.SetMinSize(fyne.NewSize(26, 26))
	// imgWin10 := canvas.NewImageFromResource(resourceWindows10Png)
	// imgWin10.FillMode = canvas.ImageFillContain
	// imgWin10.SetMinSize(fyne.NewSize(26, 26))
	// vmList
	vmListDiv := widget.NewListWithData(vmStrList,
		func() fyne.CanvasObject {
			return container.New(layout.NewGridLayout(5),
				widget.NewLabelWithStyle("主机名", fyne.TextAlignCenter, fyne.TextStyle{}),
				widget.NewLabelWithStyle("系统", fyne.TextAlignCenter, fyne.TextStyle{}),
				canvas.NewText("状态", nil),
				container.NewHBox(
					widget.NewButton("重启", nil),
					widget.NewButton("关机", nil),
					widget.NewButton("开机", nil)),
				container.NewCenter(
					widget.NewButton("登录主机", nil)),
			)
		},
		func(item binding.DataItem, obj fyne.CanvasObject) {
			vmStr, _ := item.(binding.String).Get()
			vmArr := strings.Split(vmStr, "##")
			// 主机名
			labelHostName := obj.(*fyne.Container).Objects[0].(*widget.Label)
			if len(vmArr[0]) > 14 {
				nameRune := []rune(vmArr[0])
				labelHostName.SetText(string(nameRune[:14]))
			} else {
				labelHostName.SetText(vmArr[0])
			}
			// 系统
			obj.(*fyne.Container).Objects[1].(*widget.Label).SetText(vmArr[1])
			// 状态
			labelVmStatus := obj.(*fyne.Container).Objects[2].(*canvas.Text)
			labelVmStatus.TextSize = 16
			labelVmStatus.TextStyle = fyne.TextStyle{
				Bold: true,
			}
			var vmStatus string
			switch vmArr[2] {
			case "up":
				vmStatus = "已开机"
				labelVmStatus.Color = colorSuccess
			case "down":
				vmStatus = "已关机"
				labelVmStatus.Color = colorFail
			case "wait_for_launch":
				vmStatus = "准备中..."
				labelVmStatus.Color = colorWarning
			case "powering_up":
				vmStatus = "开机中..."
				labelVmStatus.Color = colorDanger
			case "reboot_in_progress":
				vmStatus = "重启中..."
				labelVmStatus.Color = colorDanger
			case "no_vm":
				vmStatus = "没有主机记录"
				labelVmStatus.Color = colorWarning
			case "no_login":
				vmStatus = "请先登录账号"
			}
			labelVmStatus.Text = vmStatus
			// 操作按钮
			btnReboot := obj.(*fyne.Container).Objects[3].(*fyne.Container).Objects[0].(*widget.Button)
			btnShutdown := obj.(*fyne.Container).Objects[3].(*fyne.Container).Objects[1].(*widget.Button)
			btnStart := obj.(*fyne.Container).Objects[3].(*fyne.Container).Objects[2].(*widget.Button)
			btnConnect := obj.(*fyne.Container).Objects[4].(*fyne.Container).Objects[0].(*widget.Button)
			if vmArr[2] == "down" {
				btnReboot.Show()
				btnShutdown.Show()
				btnStart.Show()
				btnConnect.Show()

				btnReboot.Disable()
				btnShutdown.Disable()
				btnConnect.Disable()
				// 开机
				btnStart.Enable()
				btnStart.OnTapped = func() {
					startResult := application.VmStart(vmArr[0])
					dialog.ShowInformation("", startResult.Message, window)
					if startResult.ErrorCode <= 0 {
						go application.TimerTask(5*time.Second, 20, func() {
							vmListRes := application.VmList()
							vmStrList.Set([]string{})
							for _, vmInfo := range vmListRes.VmList {
								vmStrList.Append(vmInfo.Name + "##" + vmInfo.System + "##" + vmInfo.Status + "##" + vmInfo.Description)
							}
							// logger.Println("定时刷新vmlist=", vmListRes.VmList)
						})
					}
				}
			} else if vmArr[2] == "up" {
				btnReboot.Show()
				btnShutdown.Show()
				btnStart.Show()
				btnConnect.Show()
				btnStart.Disable()
				// 重启
				btnReboot := obj.(*fyne.Container).Objects[3].(*fyne.Container).Objects[0].(*widget.Button)
				btnReboot.Enable()
				btnReboot.OnTapped = func() {
					cnf := dialog.NewConfirm("", "确认重启吗?", func(b bool) {
						if b != true {
							return
						}
						rebootResult := application.VmReboot(vmArr[0])
						dialog.ShowInformation("", rebootResult.Message, window)
						if rebootResult.ErrorCode <= 0 {
							go application.TimerTask(5*time.Second, 20, func() {
								vmListRes := application.VmList()
								vmStrList.Set([]string{})
								for _, vmInfo := range vmListRes.VmList {
									vmStrList.Append(vmInfo.Name + "##" + vmInfo.System + "##" + vmInfo.Status + "##" + vmInfo.Description)
								}
								// logger.Println("定时刷新vmlist=", vmListRes.VmList)
							})
						}
					}, window)
					cnf.SetDismissText("取消")
					cnf.SetConfirmText("确认")
					cnf.Show()
				}
				btnShutdown.Enable()
				btnShutdown.OnTapped = func() {
					cnf := dialog.NewConfirm("", "确认关机吗?", func(b bool) {
						rebootResult := application.VmShutdown(vmArr[0])
						dialog.ShowInformation("", rebootResult.Message, window)
						if rebootResult.ErrorCode <= 0 {
							go application.TimerTask(5*time.Second, 20, func() {
								vmListRes := application.VmList()
								vmStrList.Set([]string{})
								for _, vmInfo := range vmListRes.VmList {
									vmStrList.Append(vmInfo.Name + "##" + vmInfo.System + "##" + vmInfo.Status + "##" + vmInfo.Description)
								}
								// logger.Println("定时刷新vmlist=", vmListRes.VmList)
							})
						}
					}, window)
					cnf.SetDismissText("取消")
					cnf.SetConfirmText("确认")
					cnf.Show()
				}
				// 登录
				btnConnect := obj.(*fyne.Container).Objects[4].(*fyne.Container).Objects[0].(*widget.Button)
				btnConnect.Enable()
				btnConnect.OnTapped = func() {
					// dialog.ShowInformation("", "登录中...", window)
					connectResult := application.VmConnect(vmArr[0])
					if connectResult.ErrorCode > 0 {
						dialog.ShowInformation("", connectResult.Message, window)
					}
				}
			} else if vmArr[2] == "no_login" || vmArr[2] == "no_vm" {
				btnReboot.Hide()
				btnShutdown.Hide()
				btnStart.Hide()
				btnConnect.Hide()
			} else {
				btnReboot.Show()
				btnShutdown.Show()
				btnStart.Show()
				btnConnect.Show()
				btnReboot.Disable()
				btnShutdown.Disable()
				btnStart.Disable()
				btnConnect.Disable()
			}

		})
	vmListDivContain := container.New(layout.NewGridWrapLayout(fyne.NewSize(800, 560)), vmListDiv)

	vmListTopBtn := widget.NewButton("刷新", func() {
		vmListResult := application.VmList()
		logger.Println("手动刷新vmlistResult=", vmListResult)
		if vmListResult.ErrorCode > 0 {
			dialog.ShowInformation("", vmListResult.Message, window)
			return
		}
		vmStrList.Set([]string{})
		for _, vmInfo := range vmListResult.VmList {
			vmStrList.Append(vmInfo.Name + "##" + vmInfo.System + "##" + vmInfo.Status + "##" + vmInfo.Description)
		}
		logger.Println("手动刷新vmlist=", vmListResult.VmList)
	})

	vmListTopContain := container.New(layout.NewHBoxLayout(), layout.NewSpacer(), widget.NewLabel("主机列表"), vmListTopBtn, layout.NewSpacer())

	vmListTitleContain := container.New(layout.NewGridLayout(5),
		widget.NewLabelWithStyle("主机名", fyne.TextAlignCenter, fyne.TextStyle{Bold: true}),
		widget.NewLabelWithStyle("系统", fyne.TextAlignCenter, fyne.TextStyle{Bold: true}),
		widget.NewLabelWithStyle("状态", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
		widget.NewLabelWithStyle("操作", fyne.TextAlignCenter, fyne.TextStyle{Bold: true}),
		widget.NewLabelWithStyle("登录", fyne.TextAlignCenter, fyne.TextStyle{Bold: true}),
	)
	vmListWrap := container.New(layout.NewVBoxLayout(), vmListTopContain, vmListTitleContain, vmListDivContain)
	// tabs.Append(container.NewTabItemWithIcon("主机", theme.ComputerIcon(), vmListWrap))
	// ######################登录页面#######################
	// 自动填充
	if resultLoginInfo.ErrorCode <= 0 && resultLoginInfo.Info.Username != "" {
		strUsername.Set(resultLoginInfo.Info.Username)
		strPassword.Set(resultLoginInfo.Info.Password)
		strDatacenter.Set(resultLoginInfo.Info.Datacenter)
	}
	entryUsername := widget.NewEntryWithData(strUsername)
	entryUsername.SetPlaceHolder("请输入账号")
	entryPassword := widget.NewEntryWithData(strPassword)
	entryPassword.SetPlaceHolder("请输入密码")
	entryDatacenter := widget.NewEntryWithData(strDatacenter)
	entryDatacenter.SetPlaceHolder("请输入地址,如192.168.0.246:443")

	formLogin := &widget.Form{
		BaseWidget: widget.BaseWidget{},
		Items: []*widget.FormItem{
			{Text: "登录账号: ", Widget: entryUsername},
			{Text: "登录密码: ", Widget: entryPassword},
			{Text: "平台地址: ", Widget: entryDatacenter},
		},
		OnSubmit: func() { // optional, handle form submission
			// 检查
			if len(entryUsername.Text) == 0 || len(entryPassword.Text) == 0 {
				dialog.ShowInformation("", "请输入账号和密码", window)
				return
			}
			if len(entryDatacenter.Text) == 0 {
				dialog.ShowInformation("", "请输入平台地址", window)
				return
			}

			loginResult := application.Login(entryUsername.Text, entryPassword.Text, entryDatacenter.Text)
			logger.Println("首次登录loginResult=", loginResult)
			dialog.ShowInformation("", loginResult.Message, window)
			if loginResult.ErrorCode > 0 {
				return
			}
			vmListResult := application.VmList()
			logger.Println("首次登录vmList=", vmListResult.VmList)
			vmStrList.Set([]string{})
			for _, vmInfo := range vmListResult.VmList {
				vmStrList.Append(vmInfo.Name + "##" + vmInfo.System + "##" + vmInfo.Status + "##" + vmInfo.Description)
			}

		},
		OnCancel:   nil,
		SubmitText: "保存登录账号",
		CancelText: "",
	}
	// 测试平台
	entryIp := widget.NewEntry()
	entryIp.SetPlaceHolder("请输入IP, 如192.168.0.246")
	entryPort := widget.NewEntry()
	entryPort.SetPlaceHolder("请输入端口号, 默认443")
	formDatacenter := &widget.Form{
		Items: []*widget.FormItem{
			{Text: "平台的IP: ", Widget: entryIp},
			{Text: "平台端口: ", Widget: entryPort},
		},
		SubmitText: "连接平台测试",
		OnSubmit: func() { // optional, handle form submission
			addResult := application.DatacenterTest(entryIp.Text, entryPort.Text)
			dialog.ShowInformation("", addResult.Message, window)
		},
	}
	datacenterTopContain := container.New(layout.NewHBoxLayout(), layout.NewSpacer(), widget.NewLabel("平台连接测试"), layout.NewSpacer())
	datacenterAddDiv := container.New(layout.NewGridWrapLayout(fyne.NewSize(380, 100)), formDatacenter)
	datacenterWrap := container.New(layout.NewHBoxLayout(), layout.NewSpacer(), datacenterAddDiv, layout.NewSpacer())

	formLoginDiv := container.New(layout.NewGridWrapLayout(fyne.NewSize(380, 230)), formLogin)
	formLoginWrap := container.New(layout.NewHBoxLayout(), layout.NewSpacer(), formLoginDiv, layout.NewSpacer())
	loginTopContain := container.New(layout.NewHBoxLayout(), layout.NewSpacer(), widget.NewLabel("登录账号设置"), layout.NewSpacer())
	loginWrap := container.New(layout.NewVBoxLayout(), loginTopContain, formLoginWrap, datacenterTopContain, datacenterWrap)
	// tabs.Append(container.NewTabItemWithIcon("登录", theme.AccountIcon(), loginWrap))
	// ######################设置#######################
	// settingTopContain := container.New(layout.NewHBoxLayout(), layout.NewSpacer(), widget.NewLabel("设置"), layout.NewSpacer())
	// settingWrap := container.New(layout.NewVBoxLayout(), settingTopContain)
	// tabs.Append(container.NewTabItemWithIcon("设置", theme.SettingsIcon(), settingWrap))
	// ######################关于#######################
	aboutDiv := container.New(layout.NewHBoxLayout(), widget.NewLabel("适用于oVirt4.x"), widget.NewLabel("版本: v1.0.0-20220707"), widget.NewLabel("微信: timeispower7"))
	aboutTopContain := container.New(layout.NewHBoxLayout(), layout.NewSpacer(), widget.NewLabel("关于"), layout.NewSpacer())
	aboutWrap := container.New(layout.NewVBoxLayout(), aboutTopContain, aboutDiv)

	// 窗口内容
	// 选项卡
	tabs := container.NewAppTabs(
		container.NewTabItemWithIcon("主机", theme.ComputerIcon(), vmListWrap),
		container.NewTabItemWithIcon("登录", theme.AccountIcon(), loginWrap),
		container.NewTabItemWithIcon("关于", theme.DocumentIcon(), aboutWrap),
	)
	if resultLoginInfo.ErrorCode > 0 {
		tabs.SelectTabIndex(1)
	}

	tabs.SetTabLocation(container.TabLocationLeading)
	tabsWithBorder := container.NewBorder(application.MakeCell(10), application.MakeCell(10), application.MakeCell(10), application.MakeCell(10), tabs)

	tabsWithBg := container.New(layout.NewMaxLayout(), canvas.NewRectangle(&color.NRGBA{255, 255, 255, 255}), tabsWithBorder)
	tabsWrap := container.NewCenter(tabsWithBg)

	windowBgImg := canvas.NewImageFromResource(resourceStaticAppbgJpg)
	windowContent := container.New(layout.NewMaxLayout(), windowBgImg, tabsWrap)
	window.SetContent(windowContent)
	// window.SetFullScreen(true)
	window.ShowAndRun()
}

标签:widget,桌面,New,fyne,NewSpacer,编写,container,layout
来源: https://www.cnblogs.com/sentangle/p/16497726.html