Blog de programación, errores, soluciones

Chose Language:
Author: Admin/Publisher |not finished |not checked

Containers en Fyne

fyne containers
fyne logo

En esta entrada veremos diferentes containers de fyne, y veremos que tal se ven al ser aplicados.

Esta entrada es un poco inusual para la clase de post que estoy realizando, pero decidí realizarla, ya que me he dado contra la pared más de un a vez utilizando esta herramienta para GO(GOLANG)

En fyne puede encontrar 2 clases de containers:

  • AppTabs
  • Box
    • NewHBox()
    • NewVBox()

Al menos eso dice el tutorial oficial de su página, sobre esto no estoy tan de acuerdo, ya que si miramos el package de container vemos varias formas de realizar un container (funciones).

Importante: fyne.Container tambien es un fyne.CanvasObject

Package Container

funciones en package container.

Estas son:

  • New (return *fyne.container)
  • NewAdaptiveGrid (return *fyne.container)
  • NewBorder (return *fyne.container)
  • NewCenter (return *fyne.container)
  • NewGridWithColumns (return *fyne.container)
  • NewGridWithRows (return *fyne.container)
  • NewGridWrap (return *fyne.container)
  • NewHBox (return *fyne.container)
  • NewMax (return *fyne.container)
  • NewPadded (return *fyne.container)
  • NewVBox (return *fyne.container)
  • NewWithoutLayout (return *fyne.container)

Si me pongo a ahondar en esto posiblemente me dé que muchos de estos pertenezcan al tipo de container box y es de suponer que es de esta manera.

Todas retornan *fyne.container

types en container package

Los tipos de container también es otra cosa que te deja pensando si en realidad hay 2 clases de contaieners. Estos son:

  • AppTabs(container)
  • TabItem(no es un container, especifica un item de AppTabs container )
  • DocTabs(container)
  • Scroll(container)
  • ScrollDirection(no es un container, especifica la direccion del scroll en scroll container)
  • Split(container)
  • TabLocation(especifica donde esta el tab en AppTabs container)
Resumen

Por lo que he estado observando todas las funciones pertenecen a containers de tipo box.

Por lo que he observado en la página principal hay documentación sin terminar o desactualizada, porque habla de 2 clases de container y ahondando encontré más de 2 quedando los containers de la siguiente manera:

  • Box
  • Apptabs
  • DocTabs
  • Scroll
  • Split

Creando contenedores.

Si vas a probar el siguiente código te recomiendo instalar fyne en tu pc, es muy fácil de instalar solo sigue las instrucciones en fyne.io, en mi caso cree un nuevo proyecto que se llama fynecontainers.

Para probar los ejemplos deberas instalar fyne.io

No se deje intimidar por los … (esto es llamado ellipsis) solo indica que espera múltiples valores de ese tipo (0 o más)

En caso de que quieras ir probando agrega el siguiente código a tu main.go

main.go(imports y variables globales)
package main

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/widget"
)

var btn_New *widget.Button
var lbl1, lbl2, lbl3, lbl4, lbl5, lbl6, lbl7 *widget.Label

Además deberás agregar la siguiente función, esta creará nuestros labels que usaremos en los distintos containers

main.go(funcion labels)
func labels() {
	lbl1 = widget.NewLabel("Label 1")
	lbl2 = widget.NewLabel("Label 2")
	lbl3 = widget.NewLabel("Label 3")
	lbl4 = widget.NewLabel("this is a long label")
	lbl5 = widget.NewLabel("this is an insane very long label")
	lbl6 = widget.NewLabel("----")
	lbl7 = widget.NewLabel("----")
}

Para nuestra función main haremos lo siguiente:

main.go(funcion main)
func main() {
	a := app.New()
	w := a.NewWindow("Fyne containers")
	labels()
	fcmessage := widget.NewLabel("All fine containers, plese clic a button to see an example")
	w.SetContent(container.NewVBox(
		fcmessage,
		// button code tocreate window with the container
	))

	w.ShowAndRun()
}

Lamentablemente la API Themes no tiene documentación alguna y por lo tanto no sé bien como ponerle color al container que utilizaremos.

Esto nos deja en cierta desventaja, ya que lo que pensaba hacer que la ventana se habrá al máximo o a un tamaño específico y luego utilizar un container, dentro de este poner el contendor especifico.

En pocas palabras quería que sucediera lo siguiente:

En este caso max tomaría toda el área de ventana, y el contenedor que estamos probando su área concreta de esta manera podríamos ver como seria, pero al no poder cambiarle el color al contenedor se me hace más difícil explicar cada container. Lo anterior expresado está mal vea NewMax para entender el porqué

Para satisfacer esta idea lo que hare es poner un label con texto ‘—-‘ dentro de el container MAX.

New

NewAdaptativeGrid

NewBorder

NewCenter

NewGridWithColumns

NewGridWithRows

NewGridWrap

NewHBox

NewMax

NewPadded

NewVBox

NewWithoutLayout

New

La función New espera un layout como parámetro y objetos del tipo fyne.CanvasObject como ya habíamos comentado fyne.Container también es un fyne.CanvasObject.

func New(layout fyne.Layout, objects ...fyne.CanvasObject) *fyne.Container

de valor nos retornará un *fyne.container después de todo es lo que esperamos.

Ejemplo:

Teniendo el código de la introducción creando contenedores en fyne, cree la siguiente función en main:

main.go
func create_btn_New(app fyne.App) {
	btn_New = widget.NewButton("New", func() {
		window := app.NewWindow("(contaienr)New")
		window.SetContent(
			container.NewVBox(
				lbl6,
				container.New(
					layout.NewHBoxLayout(),
					lbl1, lbl2, lbl3, lbl4, lbl5,
				),
				lbl7),
		)
		window.Resize(fyne.NewSize(300, 300))
		window.Show()
	})
}

Además de esta función deberíamos agregar el botón en las variables globales y llamar la función dentro de la función main.

main.go(función main)
create_btn_New(a)
main.go(despues de imports)
var btn_New *widget.Button

Probamos y el resultado debería ser el siguiente:

Como podemos ver el container creado con New toma el layout que le especifiquemos, en particular este container que creamos es idéntico a uno creado con NewHBox este toma todo el width del elemento que lo contiene y el height está dado por los elementos que lo conforman en este caso los labels (lbl1, lbl2, lbl3, lbl4, lbl5)

NewAdaptiveGrid

Esta función tiene como parámetro filas o columnas (rowcols) este parámetro nos dice cuantas tendrá dependiendo de la disposición que tenga eso lo veremos luego en el ejemplo. El resto de parámetros que puede tener son fyne.CanvasObjects.

func NewAdaptiveGrid(rowcols int, objects ...fyne.CanvasObject) *fyne.Container

Antes de seguir con el ejemplo recuerda que parte de lo que necesita este está en la introducción de creando contenedores.

Ahora si al ejemplo:

main.go
func create_btn_NewAdaptiveGrid(app fyne.App) {
	btn_NewAdaptiveGrid = widget.NewButton("NewAdaptiveGrid", func() {
		window := app.NewWindow("(container)NewAdaptiveGrid")
		window.SetContent(
			container.NewVBox(
				lbl6,
				container.NewAdaptiveGrid(3,
					lbl1, lbl2, lbl3, lbl4, lbl5,
				),
				lbl7),
		)
		window.Resize(fyne.NewSize(300, 300))
		window.Show()
	})
}

A nuestra función main deberemos agregarle la siguiente línea:

main.go(en función main)
create_btn_NewAdaptiveGrid(a)

Además, luego de import agregaremos la variable del botón:

main.go(despues de imports)
var btn_NewAdaptiveGrid *widget.Button

Como resultado obtendríamos el siguiente ejemplo

¿Ahora como cambiaríamos para que fueran rows?

Comming Soon

Under research, or under creation

NewBorder

Los container de tipo border son fijados a los objetos canvas que le digamos, estos son top, bottom, left, right estos son las aristas del container, recomiendo que rellenes 2 por lo menos o el resultado puede ser inesperado.

func NewBorder(top, bottom, left, right fyne.CanvasObject, objects ...fyne.CanvasObject) *fyne.Container

Para el ejemplo crea la siguiente funcion:

main.go(funcion para newBorder)
func create_btn_NewBorder(app fyne.App) {
	btn_NewBorder = widget.NewButton("NewBorder", func() {
		window := app.NewWindow("(container)NewBorder")
		top := canvas.NewText("top bar", color.White)
		left := canvas.NewText("left", color.White)
		window.SetContent(
			container.NewVBox(
				container.NewBorder(top, nil, left, nil,
					container.NewVBox(lbl1, lbl2, lbl3, lbl4, lbl5),
				),
			),
		)
		window.Resize(fyne.NewSize(500, 300))
		window.Show()
	})
}

línea para que llame a la funcion en la funcion main:

main.go(en función main)
create_btn_NewBorder(a)

tampoco olvides agregar el boton a el container

luego de esto agrega la variable que tendra el boton:

main.go(despues de imports)
var btn_NewBorder *widget.Button

Por ultimo y lo que nos venia faltando es el resultado:

NewCenter

Crea un container que centra todos los objetos declarados dentro de el

func NewCenter(objects ...fyne.CanvasObject) *fyne.Container

He hecho el ejemplo pero lamentablemente no es lo que esperaba este amontono todos los label en el centro de el container quedando superpuestos. Si me preguntas como usarlo te dira que no utilices mas de 1 objeto dentro de el y asi por lo menos utilizarlo para alinear otro objeto.

NewGridWithColumns

esta funcion crea un container con una cantidad especfica de columnas especificada en el parametro cols, la cantidad de rows dependera de la cantidad de objetos que posea.

func NewGridWithColumns(cols int, objects ...fyne.CanvasObject) *fyne.Container

Ejemplo:

main.go
func create_btn_NewGridWithColumns(app fyne.App) {
	btn_NewGridWithColumns = widget.NewButton("NewGridWithColumns", func() {
		window := app.NewWindow("(container)NewGridWithColumns")
		window.SetContent(
			container.NewVBox(
				container.NewHBox(lbl6),
				container.NewGridWithColumns(2, lbl1, lbl2, lbl3, lbl4, lbl5),
				container.NewHBox(lbl7),
			),
		)
		window.Resize(fyne.NewSize(500, 300))
		window.Show()
	})
}

Para que el codigo anterior funcione debemos declarar el boton y tambien llamar la funcion en la funcion main

main.go(despues de imports)
var btn_NewGridWithColumns *widget.Button
main.go(llama esta funcion antes definir el w.setContent)
create_btn_NewGridWithColumns(a)

el resultado seria el siguiente:

NewGridWithRows

Ejemplo:

main.go(agrega esta funcion)
func create_btn_NewGridWithRows(app fyne.App) {
	btn_NewGridWithRows = widget.NewButton("NewGridWithRows", func() {
		window := app.NewWindow("(container)NewGridWithRows")
		window.SetContent(
			container.NewVBox(
				container.NewHBox(lbl6),
				container.NewGridWithRows(2, lbl1, lbl2, lbl3, lbl4, lbl5),
				container.NewHBox(lbl7),
			),
		)
		window.Resize(fyne.NewSize(500, 300))
		window.Show()
	})
}

Agregamos la variable que contendra el boton

main.go(add this variable)
var btn_NewGridWithRows *widget.Button

agregamos la llamada a la funcion

main.go(llama la funcion)
create_btn_NewGridWithRows(a)

El resultado que nos daria

NewGridWrap

A diferencia de las funciones que venimos viendo para crear containers wrap nos permite decirle el tamaño que tendrán los objetos que estén dentro de este (realiza un resize).

func NewGridWrap(size fyne.Size, objects ...fyne.CanvasObject) *fyne.Container

Ejemplo:

func create_btn_NewGridWrap(app fyne.App) {
	btn_NewGridWrap = widget.NewButton("NewGridWrap", func() {
		window := app.NewWindow("(container)NewGridWrap")
		window.SetContent(
			container.NewVBox(
				container.NewHBox(lbl6),
				container.NewGridWrap(fyne.NewSize(100, 40), lbl1, lbl2, lbl3, lbl4, lbl5),
				container.NewHBox(lbl7),
			),
		)
		window.Resize(fyne.NewSize(500, 300))
		window.Show()
	})
}

variable que contiene el botón

main.go(ponlo luego de import)
var btn_NewGridWrap *widget.Button

llama la funcion detro de la funcion main

main.go(put it before setContent)
create_btn_NewGridWrap(a)

tampoco te olvides de poner el botón en setcontent

Una vez termines el resultado debería ser como sigue:

como puedes observar deberás de tener cuidado de que el tamaño sea adecuado o puede haber superposicion. Algo a agregar es que este container en particular parece ser bastante responsive.

NewHBox

Cuando creamos un container con NewHBox este tomara todo el width(ancho) y la altura dependera de los objetos dentro de este(default).

func NewHBox(objects ...fyne.CanvasObject) *fyne.Container

Ejemplo:

main.go(add this function)
func create_btn_NewHBox(app fyne.App) {
	btn_NewHBox = widget.NewButton("NewHBox", func() {
		window := app.NewWindow("(container)NewHBox")
		window.SetContent(
			container.NewVBox(
				lbl6,
				container.NewHBox(lbl1, lbl2, lbl3, lbl4, lbl5),
				lbl7,
			),
		)
		window.Resize(fyne.NewSize(500, 300))
		window.Show()
	})
}

La variable que contendrá nuestro botón

main.go(add it after imports)
var btn_NewHBox *widget.Button

llamo la función

main.go(add it before calling setContent)
create_btn_NewHBox(a)

por último no olvides agregar tu botón en el set content

Cuando termines el resultado debería ser algo parecido al siguiente:

NewMax

NewMax no funciona tal como esperaba esta toma el espacio absoluto restante, lo cual puede ser algo util para poner imagenes debajo de la misma o cosas por el estilo. Si ponemos contenedores dentro compartiendo espacio con widgets puede darnos resultados indeseados.

func NewMax(objects ...fyne.CanvasObject) *fyne.Container

Ejemplo:

main.go(add this function)
func create_btn_NewMax(app fyne.App) {
	btn_NewMax = widget.NewButton("NewMax", func() {
		window := app.NewWindow("(container)NewMax")
		window.SetContent(
			container.NewVBox(
				container.NewMax(container.NewHBox(lbl1, lbl2, lbl3, lbl4, lbl5), container.NewHBox(widget.NewLabel("hi there"))),
				lbl6,
				lbl7,
			),
		)
		window.Resize(fyne.NewSize(500, 300))
		window.Show()
	})
}

Agregamos el boton:

main.go (add after imports)
var btn_NewMax *widget.Button

Llamamos la funcion en main:

main.go (call it on main)
create_btn_NewMax(a)

y agregamos el boton al setContent

El resultado de esto deberia ser algo parecido al siguiente:

Work-in-progress

The text that continues is being created and could change

NewPadded

Crea un container con los objetos que se encuentren detro de el con un padding que viene por defecto.

func NewPadded(objects ...fyne.CanvasObject) *fyne.Container

NewVBox

En caso de usar NewVBox para crear un container este tomara toda la altura(height) del objeto que lo contiene y su ancho dependera de los objetos que contenga.

func NewVBox(objects ...fyne.CanvasObject) *fyne.Container

NewWithoutLayout

func NewWithoutLayout(objects ...fyne.CanvasObject) *fyne.Container

Los container de fyne pueden ser combinados

bueno esta seccion es media obvia ya que en los ejemplos anteriores ya estabamos combinando un container MAX con otro

En esta seccion combinaremos un container HBox con 2 VBox

Work-in-progress-end

Work in progress ended keep reading without worrying

Category: go
Something wrong? If you found an error or mistake in the content you can contact me on Twitter | @luisg2249_luis.
Last 4 post in same category