<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Go紅隊(duì)開發(fā)—圖形化界面

      好久沒做golang開發(fā)了,之前的文章一直在做cli的安全工具開發(fā),這里了解一下gui圖形化的開發(fā),后續(xù)目前還不知道能發(fā)什么了,主要是cli和gui這些無非都是將之前學(xué)過的集成在一起而已,我個人是感覺這個合集已經(jīng)差不多完成了,若是還有在看我這個合集的師傅覺得還想看什么的可以給一些意見。

      GUi 圖形化

      這里只使用 fyne 庫,其他庫不討論。

      配置

      拿這個來配置的好處就是不用安裝,直接下載解壓,然后配置環(huán)境變量即可
      

      500

      • 運(yùn)?時,需要開啟CGO_ENABLED=1
      go env -w CGO_ENABLED=1
      # 解釋
      Fyne 的相關(guān)源碼?件帶有 cgo 構(gòu)建標(biāo)簽。你如果把 CGO_ENABLED=0 關(guān)掉了,帶該標(biāo)簽的源碼會被排除,編譯器要么找不到實(shí)現(xiàn),要么?到不兼容的路徑,從?出現(xiàn)“build constraints exclude all Go files” 之類的錯誤。
      反正跟著來就行了
      
      • 看你使用的是什么環(huán)境,我使用的windows,我要切換編譯平臺回來
      go env -w GOOS=windows 
      # 若是linux就修改linux
      
      • 編寫一個 “Hello Fyne” 簡單窗口
        • 當(dāng)然創(chuàng)建go項(xiàng)目的時候記得:
          • go mod init 項(xiàng)目名; go mod tidy
      package 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()
      }
      
      • 運(yùn)行代碼之前一定要重新打開一下你的vscode或者你的代碼編輯器或者終端,為了讓之前設(shè)置的環(huán)境變量生效
      # 再次運(yùn)行代碼
      go run main.go
      下圖中我的fyne沒有用v2,我后面換了,我上面代碼是正確的,只是圖片中我忘記切換新版本的庫了
      

      630

      第一個GUI

      func first_gui() {
      	myApp := app.New()                               // 創(chuàng)建一個app
      	myWin := myApp.NewWindow("Hello")                // 創(chuàng)建一個窗口,之后就要放內(nèi)容進(jìn)這個窗口了,同時給這個窗口命名
      	myWin.SetContent(widget.NewLabel("Hello Fyne!")) //簡單設(shè)置一個標(biāo)簽內(nèi)容,然后用窗口的SetContent設(shè)置內(nèi)容
      	myWin.Resize(fyne.NewSize(200, 200))             // 設(shè)置窗口大小
      	myWin.ShowAndRun()                               // Show顯示和Run運(yùn)行,這里其實(shí)是可以分開用兩個函數(shù)執(zhí)行,ShowAndRun就是一個命令執(zhí)行了兩個
      }
      

      沒什么好說,直接看代碼來的直接

      常用 widget 組件

      • widget.NewLabel
        標(biāo)簽組件,這個就是標(biāo)簽文本
      • widget.NewButton
        按鈕,第二個參數(shù)傳入函數(shù),表示這個按鈕被點(diǎn)擊后的action動作
      • widget.NewEntry
        組件實(shí)體,控件用于給用戶輸入簡單的文本內(nèi)容
        • SetReadOnly(true/false)設(shè)置是否只讀
        • SetPlaceHolder設(shè)置占位字符
        • widget.NewEntry().MultiLine = true 這樣設(shè)置可以多行文本
      • widget.NewPasswordEntry
        密碼輸入框,這個和widget.NewEntry一樣,只不過這里是密碼的方式輸入,所以輸入的內(nèi)容看不到
      • NewMultiLineEntry
        多行文本輸入,但其實(shí)上面也可以通過MultiLine = true的方式進(jìn)行多行輸入
      • widget.NewCheck
        復(fù)選框
      • widget.NewRadioGroup
        單選框,舊版本好像是widget.NewRadio,v2的就用widget.NewRadioGroup
      • widget.NewSelect
        下拉框
      • widget.NewSlider
        滑塊
      • widget.NewProgressBar
        進(jìn)度條,通過SetValue來控制進(jìn)度條的滑動
      • widget.NewProgressBarInfinite
        無限進(jìn)度條
      • widget.NewSeparator
        分割線
      • widget.NewVBox
        簡單的水平或垂直的容器,Box可以對放入box的控件采用布局
      • widget.NewCard
        卡片,給標(biāo)題和這個卡片的內(nèi)容
        目前可以簡單的通過containernew一個box進(jìn)行整合控件在某個容器里
        看下面的代碼案例中最后return即可(在basicWidgets函數(shù)中)

      穿插下container:container.NewVBox和 【container.NewScrollcontainer.NewHScroll

      • container.NewVBox
        這個很重要,因?yàn)槲覀兛梢源虬臻g在這個box里面,然后這個box就可以作為某個模塊插入到你想要的功能看模塊中去了,當(dāng)然這里使用的是VBox,V表示垂直的布局,后面會學(xué)到HBox,表示水平布局
      • container.NewScroll
        這個是整合box的時候,container作為上下滑動還是左右滑動,通過傳入VBox還是HBox來判斷左右還是上下滑動,一般都是VBox上下滑動,因?yàn)槲覀兞?xí)慣就是這樣,比較好看。

      • widget.NewSelectEntry
        可輸入的下拉框
      • widget.NewAccordion
        父:折疊面板
        子:通過widget.NewAccordionItem來創(chuàng)建展開后的面板項(xiàng)目
      • widget.NewForm
        表單,這里看代碼吧,涉及到提交和取消函數(shù)
      // 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.NewTabContainer
        標(biāo)簽容器,這個可以理解為像瀏覽器不同窗口之間切換的樣子
        這個顯示的標(biāo)簽可以修改位置:平時瀏覽器的窗口都是顯示在上方,這里修改的位置就是窗口的那個位置
        • TabLocationBottom:顯示在底部
        • TabLocationLeading:顯示在頂部左邊
        • TabLocationTrailing:顯示在頂部右邊
          直接看一段簡單的偽代碼:
      tabs := widget.NewTabContainer(
          widget.NewTabItem("Profile", profile),
          widget.NewTabItem("Setting", setting),
      )
      myWindow.SetContent(tabs)
      
      • widget.NewToolbar
        工具欄,很簡單的用法,就是NewToolbarAction創(chuàng)建然后第一個參數(shù)給圖標(biāo),第二個參數(shù)給action動作
        直接看下面的代碼:
        500
      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()
      }
      

      Layout 布局

      首先我們的控件都是要放進(jìn)box或者一個容器中,所以我們布局要學(xué)的東西在上面可能有看到過,只是沒注意到這個是什么布局罷了

      • container.New
        沒有布局,要v2版本的fyne,舊版本記得是沒有的
      • container.NewVBox
        V表示垂直布局
      • container.NewHBox
        H表示水平布局
      • container.NewBorder
        邊框布局
      • layout.NewGridLayout
        固定列數(shù)?格,這個要用一個空的container然后再傳入布局
      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),
      )
      
      • container.NewGridWithColumns
        指定列數(shù)的?格
      • container.NewGridWithRows
        指定?數(shù)的?格
      • container.NewCenter
        居中布局
      • container.NewMax
        最大化布局
      • container.NewStack
        堆疊布局
      • container.NewPadded
        帶內(nèi)邊距的布局
      • container.NewScroll
        這個是垂直的滾動

      絕對布局

      • container.NewWithoutLayout
        創(chuàng)建一個沒有布局的容器,然后自己來一個個放組件進(jìn)去,定位也自己寫
        直接看代碼:
      // 絕對定位容器
      absolute := container.NewWithoutLayout(
      	widget.NewButton("按鈕1", nil), 
      	widget.NewButton("按鈕2", nil),
      	widget.NewLabel("標(biāo)簽"),
      )
      
      // ?動設(shè)置位置和??
      // 容器里面的組件就按照你當(dāng)初放的那樣,進(jìn)行一個數(shù)組訪問即可
      // 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彈框

      這個就是一些遇到錯誤就彈框出來,或者刪除保存彈出來讓你確認(rèn)之類的等等的一些彈框

      注意事項(xiàng)

      • 你這個彈框?qū)?yīng)的父窗口一定要看清楚了
        比如你是在A窗口彈框的,那就傳A的這個窗口進(jìn)去作為參數(shù)給到該彈框,告訴他應(yīng)該在A窗口中進(jìn)行彈框
        否則可能會出現(xiàn)看不到或者被覆蓋等等未知情況

      類別

      • 信息彈框
        這個就是簡單一個彈框提示
      dialog.ShowInformation(title, message, parentWindow)
      
      • 錯誤彈框
        需要傳入錯誤類型,將你這個錯誤信息彈出來
      dialog.ShowError(err, parentWindow)
      
      • 確認(rèn)彈框
        “確定/取消”,回調(diào)接收布爾值,使用該bool來判斷用戶是確定還是取消接著下一步操作
      dialog.ShowConfirm(title, message, func(confirmed bool), parentWindow)
      
      • 自定義彈框
        這個其實(shí)就是一套娃,點(diǎn)擊某個功能后,你希望彈出什么內(nèi)容都可以,嵌入該對話框中,比如你點(diǎn)擊后彈出的框是另外一個功能更多的程序都可以,但是這樣你的這個彈框就有點(diǎn)大了,這個還是看具體情況具體分析。
        NewCustomNewCustomConfirm 的區(qū)別:
        • NewCustom:這個只有一個關(guān)閉按鈕,
        • NewCustomConfirm:會讓你去“確認(rèn)/取消”,然后拿到用戶的確認(rèn)或取消的結(jié)果進(jìn)行一下步操作
      dialog.NewCustom(title, dismissText, content, parentWindow)
      dialog.NewCustomConfirm(title, confirmText, dismissText, content, func(confirmed bool), parentWindow)
      
      • 打開文件/文件夾窗口
        • 能夠?qū)Υ蜷_文件夾后做的一些限制:
          • SetFilter(storage.NewExtensionFileFilter([]string{".txt"})) 限制可選可看到的文件后綴類型
          • SetLocation(storage.NewFileURI(path)) 設(shè)置初始位置
        • 回調(diào)參數(shù)為 nil 表示用戶取消
      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"}))
      //設(shè)置初始位置
      SetLocation(storage.NewFileURI(path))
      
      • 進(jìn)度彈框
        舉例:點(diǎn)擊開始掃描,然后彈進(jìn)度條框/旋轉(zhuǎn)等待任務(wù)完成,這種就很常見
        • 需要配合fyne.Do去執(zhí)行
      //通過SetValue設(shè)置進(jìn)度
      dialog.NewProgress(title, message, parentWindow)
      
      //顯示的是旋轉(zhuǎn),這里就不用setvalue了,沒有進(jìn)度大小
      dialog.NewProgressInfinite(title, message, parentWindow)
      

      在 Fyne v2.6.0 及以上版本中,如果你在 非主線程(例如在 goroutine 中)更新UI組件,必須使用 fyne.Do 或 fyne.DoAndWait 來包裝這些操作
      fyne.Do 與 fyne.DoAndWaitfyne.Do 會異步地將函數(shù)調(diào)度到主線程執(zhí)行,不會阻塞你當(dāng)前的 goroutine,適用于像更新進(jìn)度條這樣的場景。fyne.DoAndWait 則會同步等待函數(shù)在主線程執(zhí)行完畢

      案例demo所有代碼

      如下圖所示:很多測試單元函數(shù)被我注釋了,想要運(yùn)行哪個就自己解開,不能運(yùn)行多個,只能一個一個的函數(shù)去運(yùn)行,因?yàn)槲覜]有單獨(dú)把窗口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" // 導(dǎo)?擴(kuò)展包
      	"github.com/flopp/go-findfont"
      )
      
      func fyne_test() {
      	myApp := app.New()
      	myWin := myApp.NewWindow("窗口標(biāo)題")
      	myWin.SetContent(widget.NewLabel("label內(nèi)容"))
      	myWin.Resize(fyne.NewSize(200, 200)) // 設(shè)置窗口大小
      	myWin.CenterOnScreen()               // 窗口居中顯示
      
      	// ---------------------------------
      	// 全屏
      	// myWin.SetFullScreen(true)
      	// 判斷是否全屏
      	// isFullScrenn := myWin.FullScreen()
      	// fmt.Println(isFullScrenn)
      	// ---------------------------------
      
      	// ---------------------------------
      	// 主窗口設(shè)置
      	myWin.SetMaster()
      	mainMenu := fyne.NewMainMenu(
      		fyne.NewMenu(
      			"文件",
      			fyne.NewMenuItem("新建", func() { fmt.Println("點(diǎn)擊了新建") }),
      			fyne.NewMenuItem("打開", func() { fmt.Println("點(diǎn)擊了打開") }),
      			fyne.NewMenuItem("推出", func() { myApp.Quit() }),
      		),
      	)
      	myWin.SetMainMenu(mainMenu)
      	// ---------------------------------
      
      	// 攔截關(guān)閉事件
      	myWin.SetCloseIntercept(func() {
      		dialog.ShowConfirm("確認(rèn)", "確定要退出嗎?", func(ok bool) {
      			if ok {
      				myApp.Quit()
      			}
      		}, myWin)
      	})
      	myWin.ShowAndRun() //運(yùn)行
      }
      
      // 更新時間
      func time_clock() {
      	updateTime := func(clock *widget.Label) {
      		formatted := time.Now().Format("Time: 03:04:05") //獲取格式化時間
      		clock.SetText(formatted)
      	}
      	app := app.New()                       // 創(chuàng)建應(yīng)用程序?qū)嵗?	window := app.NewWindow("Hello world") // 創(chuàng)建窗口,標(biāo)題為"Hello Wolrd"
      
      	clock := widget.NewLabel("")
      	updateTime(clock)
      	go func() {
      		for range time.Tick(time.Second) {
      			updateTime(clock) // 每秒更新一次時間
      		}
      	}()
      
      	window.SetContent(clock) // 往窗口中放入一個內(nèi)容為"Hello world!"的標(biāo)簽控件
      	window.ShowAndRun()      //展示并運(yùn)行程序
      }
      
      // 基礎(chǔ)控件
      func basicWidgets() fyne.CanvasObject {
      	// 1. Label - ?本標(biāo)簽
      	label := widget.NewLabel("這是?個標(biāo)簽")
      	// 2. Button - 按鈕
      	button := widget.NewButton("點(diǎn)擊我", func() {
      		fmt.Println("按鈕被點(diǎn)擊")
      
      	})
      	// 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 - 復(fù)選框
      	check := widget.NewCheck("同意條款", func(checked bool) {
      		fmt.Println("復(fù)選框狀態(tài):", checked)
      	})
      	// 7. RadioGroup - 單選按鈕組
      	radio := widget.NewRadioGroup([]string{"選項(xiàng)1", "選項(xiàng)2", "選項(xiàng)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 - 進(jìn)度條
      	progress := widget.NewProgressBar()
      	progress.SetValue(0.5) // 50%
      	// 11. ProgressBarInfinite - ?限進(jìn)度條
      	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("基礎(chǔ)控件", "", container.NewVBox(
      			label,
      			button,
      			entry,
      			passwordEntry,
      			multiEntry,
      			check,
      			radio,
      			selectWidget,
      			slider,
      			progress,
      			infiniteProgress,
      			hyperlink,
      			separator,
      		)),
      	)
      }
      func basicwidget_test() {
      	myapp := app.New()
      	w := myapp.NewWindow("基礎(chǔ)控件?例")
      	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. 日期選擇器 - 自定義實(shí)現(xiàn)
      	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{"選項(xiàng)1", "選項(xiàng)2", "選項(xiàng)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("?級設(shè)置",
      			container.NewVBox(
      				widget.NewLabel("這是?級設(shè)置?板"),
      				widget.NewCheck("啟??級功能", nil),
      			)),
      		widget.NewAccordionItem("其他選項(xiàng)",
      			container.NewVBox(
      				widget.NewLabel("這是其他選項(xiàng)?板"),
      				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()
      }
      
      // 假設(shè)你使用的是舊版本,不是v2以上的,那若你有中文的話,就需要進(jìn)行中文字體設(shè)置
      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)
      
      }
      
      // 畫布練習(xí)
      func fyne_canvas() {
      	myApp := app.New()
      	myWin := myApp.NewWindow("畫布測試")
      	myWin.Resize(fyne.NewSize(400, 300))
      	myWin.ShowAndRun()
      }
      
      // 工具欄練習(xí)
      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()
      
      }
      
      // 相對布局練習(xí)
      func fyne_Layouts() {
      	myApp := app.New()
      	myWin := myApp.NewWindow("Layouts")
      
      	// 設(shè)置窗???
      	myWin.Resize(fyne.NewSize(600, 700))
      	// 1. BoxLayout - 垂直布局
      	vboxLayout := container.NewVBox(
      		widget.NewLabel("垂直布局 - 項(xiàng)?1"),
      		widget.NewLabel("垂直布局 - 項(xiàng)?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("左側(cè)"),   // left
      		widget.NewLabel("右側(cè)"),   // right
      		widget.NewLabel("中?內(nèi)容"), // center
      	)
      	// 4. GridLayout - 固定列數(shù)?格
      	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 - 指定列數(shù)的?格
      	gridWithColumns := container.NewGridWithColumns(2,
      		widget.NewLabel("單元格 1"),
      		widget.NewLabel("單元格 2"),
      		widget.NewLabel("單元格 3"),
      		widget.NewLabel("單元格 4"),
      	)
      	// 6. GridWithRows - 指定?數(shù)的?格
      	gridWithRows := container.NewGridWithRows(3,
      		widget.NewLabel("? 1"),
      		widget.NewLabel("? 2"),
      		widget.NewLabel("? 3"),
      	)
      	// 7. CenterLayout - 居中布局
      	centerLayout := container.NewCenter(
      		widget.NewLabel("居中的內(nèi)容"),
      	)
      	// 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("堆疊內(nèi)容")),
      	)
      	// 10. PaddedLayout - 帶內(nèi)邊距的布局
      	paddedLayout := container.NewPadded(
      		widget.NewButton("有內(nèi)邊距的按鈕", 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 內(nèi)邊距布局", "", paddedLayout),
      	))
      	myWin.SetContent(w)
      	myWin.ShowAndRun()
      }
      
      // 絕對布局練習(xí)
      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("標(biāo)簽"),
      	)
      
      	// ?動設(shè)置位置和??
      	// 容器里面的組件就按照你當(dāng)初放的那樣,進(jìn)行一個數(shù)組訪問即可
      	// 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("準(zhǔn)備開始...")
      	button := widget.NewButton("開始任務(wù)", func() {
      		// 創(chuàng)建進(jìn)度對話框,初始進(jìn)度0%
      		progDialog := dialog.NewProgress("處理中", "正在進(jìn)行一項(xiàng)耗時的確定性任務(wù)...", myWindow)
      		progDialog.Show()
      
      		totalSteps := 100
      
      		// 使用 fyne.Do 確保初始設(shè)置在主線程執(zhí)行
      		fyne.Do(func() {
      			progDialog.SetValue(0) // 確保從0開始
      		})
      
      		// 模擬任務(wù)進(jìn)度更新
      		go func() {
      			for i := 0; i <= totalSteps; i++ {
      				currentI := i // 創(chuàng)建局部變量避免閉包問題
      				currentProgress := float64(currentI) / float64(totalSteps)
      
      				if currentI == totalSteps {
      					time.Sleep(500 * time.Millisecond) // 最后稍作停頓
      
      					// 使用 fyne.Do 包裝UI更新
      					fyne.Do(func() {
      						progDialog.SetValue(1.0) // 完成時設(shè)置為1.0 (100%)
      						progressInfo.SetText("任務(wù)完成!")
      					})
      
      					time.Sleep(500 * time.Millisecond)
      
      					fyne.Do(func() {
      						progDialog.Hide() // 完成任務(wù)后隱藏
      					})
      					return
      				}
      
      				// 使用 fyne.Do 包裝所有UI更新操作
      				fyne.Do(func() {
      					progDialog.SetValue(currentProgress) // 更新進(jìn)度 (0.0 到 1.0)
      					progressInfo.SetText(fmt.Sprintf("進(jìn)度: %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("開始不確定任務(wù)", func() {
      		// 創(chuàng)建無限進(jìn)度對話框
      		infiniteDialog := dialog.NewProgressInfinite("請等待", "正在進(jìn)行一項(xiàng)不確定時間的任務(wù)...", myWindow)
      		infiniteDialog.Show()
      
      		fyne.Do(func() {
      			statusLabel.SetText("任務(wù)進(jìn)行中...")
      		})
      
      		// 模擬一個耗時不確定的任務(wù)
      		go func() {
      			time.Sleep(5 * time.Second) // 模擬工作,比如網(wǎng)絡(luò)請求
      
      			// 使用 fyne.Do 包裝UI更新
      			fyne.Do(func() {
      				infiniteDialog.Hide() // 任務(wù)完成后隱藏對話框
      				statusLabel.SetText("不確定任務(wù)已完成!")
      			})
      		}()
      	})
      
      	content := container.NewVBox(statusLabel, startButton)
      	myWindow.SetContent(content)
      	myWindow.Resize(fyne.NewSize(400, 200))
      	myWindow.ShowAndRun()
      }
      
      func test_Progess() {
      	//這里是手動切換調(diào)用哪個的函數(shù)方法, 我在main中調(diào)用他這個函數(shù)即可
      	// fyne_dialog_for_NewProgess()
      	fyne_dialog_for_NewProgessInfinite()
      }
      func main() {
      	// packet_myfont() //設(shè)置中文字體,不亂碼
      	// fyne_test()
      	// basicwidget_test()
      	// advancedWidgets_test()
      	// time_clock()
      	// fyne_canvas() //畫布測試
      	// fyne_toolbar() // 工具欄
      	// fyne_Layouts() // 相對布局測試
      	// fyne_absolute_layout() // 絕對布局測試
      	test_Progess() //進(jìn)度條測試
      }
      
      posted @ 2025-11-05 17:04  竹等寒  閱讀(24)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 欧美激情肉欲高潮视频| 国产成人亚洲精品自产在线| 四虎精品永久在线视频| 亚洲日韩性欧美中文字幕| 中美日韩在线一区黄色大片| 午夜成人性爽爽免费视频| 国产一区二区三区导航| 中文字幕亚洲国产精品| 亚洲一区二区精品动漫| 人成午夜大片免费视频77777| 久久精品国产精品亚洲| 在线国产精品中文字幕| 亚洲国产成人综合精品| 黑人巨大精品欧美一区二区| 国产av寂寞骚妇| 免费人成网站免费看视频| 军事| 国产免费性感美女被插视频| 亚洲第一精品一二三区| 欧美不卡一区二区三区| AV无码免费不卡在线观看 | 在厨房拨开内裤进入在线视频| 中文字幕av一区| 色欲综合久久中文字幕网| 内乡县| 五月天国产成人av免费观看| 人人妻人人添人人爽日韩欧美 | 性欧美VIDEOFREE高清大喷水| 桃花岛亚洲成在人线AV| 国产99视频精品免费视频6| 五月天国产成人AV免费观看| 亚洲天堂一区二区成人在线| 国产精品高清一区二区三区| 国产人妻精品午夜福利免费| 观塘区| 免费午夜无码片在线观看影院| 久久中精品中文字幕入口| 亚洲av成人无码精品电影在线| 国产精品涩涩涩视频网站| 永久免费的av在线电影网| 国产精品亚洲二区在线播放|