go语言gui窗口应用之fyne框架-自定义容器实现自定义布局,更灵活的显示控件

一、自定义容器

在fyne中,所有的容器都是通过container包下的New函数定义的,先看源码:

package fyne

// 根据布局创建容器
func New(layout fyne.Layout, objects ...fyne.CanvasObject) *fyne.Container {
	return &fyne.Container{Layout: layout, Objects: objects}
}

二、自定义布局

通过上述,可以看出,要实现自定义容器,关键是自定义布局,在 fyne 中,自定义布局,只要实现fyne包下Layout接口即可,以下为Layout接口源码:

package fyne

// 布局接口
type Layout interface {
	// 通过遍历[]CanvasObject,获取每个控件,设置每个控件大小和位置
	Layout([]CanvasObject, Size)
	// 设置容器总大小(宽,高)
	MinSize(objects []CanvasObject) Size
}

三、我的自定义容器代码

  • 注意:自定义容器中控件宽、高,可能受自定义容器的外部容器影响,修改控件宽、高时,可能没有效果,需要对外部容器也要做相应操作。
  • 可以通过查看fynecontainer源码定义的布局,扩充自定义布局功能。

以下是我简易布局代码:

package main

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
)

// 自定义容器,按照控件实际大小,输入平均间隔距离
func NewMyBox(p float32, objects ...fyne.CanvasObject) *fyne.Container {
	return container.New(&myLayout{padding: p}, objects...)
}

// 自定义布局
// 注意:自定义水平布局,最大高度受外部容器影响,可能不生效
type myLayout struct {
	padding float32 // 控件间隔
}

// 设置每个控件大小和位置
func (l *myLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) {
	x := float32(0)                 // x坐标,控件距左边距离
	for _, child := range objects { // 循环遍历所有控件
		size = child.Size()                                      // 获取当前控件的设置的大小(宽、高)
		size.Height = child.Size().Height                        // 控件高度为控件的默认最小高度
		size.Width = fyne.Max(size.Width, child.MinSize().Width) // 控件的最小宽度和实际宽度取最大值
		child.Resize(size)                                       // 设置控件大小
		child.Move(fyne.NewPos(x, 0))                            // 设置控件位置
		x += size.Width + l.padding                              // 计算下一个控件位置
	}
}

// 设置容器大小(宽,高)
func (l *myLayout) MinSize(objects []fyne.CanvasObject) fyne.Size {
	size := fyne.NewSize(0, 0)      // 初始化容器大小
	for _, child := range objects { // 循环遍历每个控件
		temp := fyne.NewSize(0, 0)                           // 临时存储获取的大小
		minSize := child.MinSize()                           // 控件最小绘制大小
		mSize := child.Size()                                // 控件设置大小
		temp.Height = fyne.Max(minSize.Height, mSize.Height) // 获取当前控件默认高度和设置高度的最大值
		size.Height = fyne.Max(size.Height, temp.Height)     // 设置容器最大高度为最高控件的高度值
		temp.Width = fyne.Max(minSize.Width, mSize.Width)    // 获取当前控件默认宽度和设置宽度的最大值
		size.Width += temp.Width + l.padding                 // 容器宽度 = 每个控件宽度 + 间距
	}
	return size // 返回容器大小
}

四、使用自定义容器

package main

import (
	"fmt"
	"fyne.io/fyne/v2"                //go get fyne.io/fyne/v2@latest
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/widget"
	"github.com/flopp/go-findfont"  // go get github.com/flopp/go-findfont
	"os"
	"strconv"
	"strings"
)

func init() {
	//设置中文字体:解决fyne中文乱码问题
	fontPaths := findfont.List()      // 获取系统中所有的字体路径
	for _, path := range fontPaths {  // 判断字体是否在路径中
		if strings.Contains(path, "msyh.ttf") || strings.Contains(path, "simhei.ttf") || strings.Contains(path, "simsun.ttc") || strings.Contains(path, "simkai.ttf") || strings.Contains(path, "STHeiti Medium.ttc") || strings.Contains(path, "Songti.ttc") {
			os.Setenv("FYNE_FONT", path)  // 系统中存在的字体路径,设置为应用的字体
			break
		}
	}
}
func main() {
	myApp := app.New()                // 创建应用
	w := myApp.NewWindow("计数")      // 窗口标题
	w.Resize(fyne.NewSize(800, 400)) // 窗口大小
	w.CenterOnScreen()               // 窗口屏幕居中显示

	l1 := widget.NewLabel("设置计数:")     // 文本标签1
	l2 := widget.NewLabel("5")            // 文本标签2,默认为5
	b1 := widget.NewButton("+", func() {  // 按钮+
		v, _ := strconv.Atoi(l2.Text)     // 字符串转整型
		v++
		if v > 15 {                       // 最大值为15
			v = 15
		}
		l2.SetText(strconv.Itoa(v))      // 整型转字符串,赋值
	})
	b1.Resize(fyne.NewSize(b1.MinSize().Height, b1.MinSize().Height/3))  // 设置+按钮大小
	b2 := widget.NewButton("-", func() {
		v, _ := strconv.Atoi(l2.Text)    // 字符串转整型
		v--
		if v < 1 {                       // 最小值为1
			v = 1
		}
		l2.SetText(strconv.Itoa(v))      // 整型转字符串,赋值
	})
	b2.Resize(fyne.NewSize(b2.MinSize().Height, b2.MinSize().Height*5))  // 设置-按钮大小
	w.SetContent(NewMyBox(5, l1, l2, b1, b2))  // 使用自定义容器,控件间距设置为5
	w.ShowAndRun()                             // 显示窗口并运行应用
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值