Append some text to a MultiLineEntry in fyne - user-interface

I want to append some text to this MultiLineEntry as a button event. I know how to set a text but couldn't find any example for appending some text. Is there any other widget available for this purpose? This is my code so far:
package main
import (
"fmt"
"fyne.io/fyne/app"
"fyne.io/fyne/container"
"fyne.io/fyne/widget"
)
func main() {
a := app.New()
w := a.NewWindow("Hello")
largeText := widget.NewMultiLineEntry()
largeText.SetText("Lorem ipsum ...")
largeText.SetPlaceHolder("Type here")
form := &widget.Form{
Items: []*widget.FormItem{
},
OnCancel: func() {
fmt.Println("Cancelled")
},
OnSubmit: func() {
fmt.Println("Form submitted")
// EVENT TO APPEND TO MULTILINE
},
}
w.SetContent(container.NewVBox(form,largeText))
w.ShowAndRun()
}

You can first get then set:
largeText := widget.NewMultiLineEntry()
largeText.SetText("Lorem ipsum ...")
originalText := largeText.Text
fmt.Println(originalText)
newText := originalText + "appending new text"
largeText.SetText(newText)

Related

GO problem with positioning in fyne.io - Move method doesn't work

I am making a simple application with fyne, but I have a problem with text placement.
As you can see from the image, I managed to position the form components with an edge from the window, but I can't do the same with the underlying components (the Move method doesn't work).
Here the main file:
package main
import (
"fmt"
"weather-app/ui"
"weather-app/utils"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
)
func main() {
prova, err := utils.MakeRequest("palermo", "it")
if err != nil {
panic(err)
} else {
fmt.Println(prova.Weather[0])
fmt.Println(prova.Main)
fmt.Println(prova.Sys)
fmt.Println(prova.Dt)
}
app := app.New()
window := app.NewWindow("Current Weather")
customForm := ui.GenerateCustomForm()
apiResults := ui.ShowApiResults("Cinisi", "20 °C")
wrapper := container.NewGridWithRows(
2,
customForm,
apiResults,
)
window.Resize(fyne.NewSize(445, 400))
window.SetContent(wrapper)
window.ShowAndRun()
}
The ui:
package ui
import (
"fmt"
"image/color"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/widget"
)
func onSubmitFunc(city, country string) {
fmt.Println("submit")
}
func GenerateCustomForm() *fyne.Container {
//creating widgets
cityEntry := widget.NewEntry()
countrEntry := widget.NewEntry()
button := widget.NewButton("Search", func() { onSubmitFunc(cityEntry.Text, countrEntry.Text) })
//set placeholder in text input
cityEntry.SetPlaceHolder("City")
countrEntry.SetPlaceHolder("Country (optional)")
//setting size
cityEntry.Resize(fyne.NewSize(250, 40))
countrEntry.Resize(fyne.NewSize(150, 40))
button.Resize(fyne.NewSize(160, 40))
//positioning
cityEntry.Move(fyne.NewPos(10, 10))
countrEntry.Move(fyne.NewPos(cityEntry.Size().Width+25, 10))
button.Move(fyne.NewPos(10, 25))
customForm := container.New(
layout.NewVBoxLayout(),
container.NewWithoutLayout(
cityEntry,
countrEntry,
),
container.NewWithoutLayout(
button,
),
)
return customForm
}
func ShowApiResults(city, temp string) *fyne.Container {
text := canvas.NewText("Current weather in "+city, color.White)
text.TextSize = 18
temperature := canvas.NewText(temp, color.White)
temperature.TextSize = 50
//sample image
r, _ := fyne.LoadResourceFromURLString("http://openweathermap.org/img/wn/09d#2x.png")
image := canvas.NewImageFromResource(r)
image.FillMode = canvas.ImageFillContain
image.Resize(fyne.NewSize(100, 100))
//wrap the components to have them on the same line
tempAndImg := container.New(
layout.NewGridLayout(2),
temperature,
image,
)
tempAndImg.Move(fyne.NewPos(20, 0)) //DOESN'T WORK
apiResults := container.New(
layout.NewVBoxLayout(),
text,
tempAndImg,
)
//i tried also this:
//apiResults.Move(fyne.NewPos(20, 0)) --- but nothing
return apiResults
}
I am still in the basics of fyne, I thank in advance anyone who can help me out.
Move method should work with container.NewWithoutLayout
tempAndImg := container.New(layout.NewGridLayout(2), container.NewWithoutLayout(temperature),container.NewWithoutLayout(image) ) temperature.Move(40, 0) image.Move(40,0) apiResults := container.New(layout.NewVBoxLayout(),container.NewWithoutLayout(text),tempAndImg) text.Move(40, 0)

how to loop over fyne.CanvasObject in fyne in golang

the question is. i have NewVScroll in the NewVScroll i have NewVBoxLayout in NewVBoxLayout i have NewButton . the problem is when i press the NewButton it should loop over NewVScroll and then loop over NewVBoxLayout to find NewButton . but i don't know how to do it in fyne because i can't loop over var v1 fyne.CanvasObject
the error is : cannot range over v1 (variable of type fyne.CanvasObject)
this is the code
package main
import (
"fmt"
"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 cEntries *fyne.Container
func FindObject(object fyne.CanvasObject, objects []fyne.CanvasObject) (int, bool) {
for k1, v1 := range objects {
for _, v2 := range v1 {// the problem is here. i can't loop over fyne.CanvasObject
if v2 == object {
return k1, true
}
}
}
return 0, false
}
func w1() *fyne.Container {
wb := widget.NewButton("", nil)
wb.OnTapped = func() {
index, isin := FindObject(wb, cEntries.Objects)
fmt.Println(index, isin)
}
return container.New(layout.NewVBoxLayout(), wb)
}
func main() {
a := app.New()
w := a.NewWindow("")
wbAdd := widget.NewButton("+", nil)
cEntries = container.New(layout.NewVBoxLayout(), wbAdd, w1())
wbAdd.OnTapped = func() {
cEntries.Add(w1())
}
wsEntries := container.NewVScroll(cEntries)
w.SetContent(wsEntries)
w.ShowAndRun()
}
The object is a container, so in general you could iterate v1.(*fyne.Container).Objects.
However it looks like you could avoid looping in your code because the button always refers to an index that is set when the button is added - so you could pass the current index (length) to w1 and then increment it.
you don't need to loop over NewVBoxLayout because it is fyne.CanvasObject then if you want to know the index of the layout that contain this widget NewButton you can do it by just search for NewVBoxLayout in NewVScroll
this is the code
package main
import (
"fmt"
"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 cEntries *fyne.Container
func FindObject(object fyne.CanvasObject, objects []fyne.CanvasObject) (int, bool) {
for k1, v1 := range objects {
if v1 == object {
return k1, true
}
}
return 0, false
}
func w1() *fyne.Container {
wb := widget.NewButton("", nil)
c := container.New(layout.NewVBoxLayout(), wb)
wb.OnTapped = func() {
index, isin := FindObject(c, cEntries.Objects)
fmt.Println(index, isin)
}
return c
}
func main() {
a := app.New()
w := a.NewWindow("")
wbAdd := widget.NewButton("+", nil)
cEntries = container.New(layout.NewVBoxLayout(), wbAdd, w1())
wbAdd.OnTapped = func() {
cEntries.Add(w1())
}
wsEntries := container.NewVScroll(cEntries)
w.SetContent(wsEntries)
w.ShowAndRun()
}
see in this code you make the container that handle the button and then you search for the container that contain this button

main () not waiting for update of file dialog in golang using fyne for file dialog

I would like to use a file dialog to select a directory for further use in Go. To select the directory i am using a Fyne file dialog as the rest of the application uses Fyne as well. I managed to create a simple test application:
package main
import (
"fmt"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/widget"
)
var save_dir string = "NoPathYet!"
func chooseDirectory(w fyne.Window) string {
dialog.ShowFolderOpen(func(dir fyne.ListableURI, err error) {
if err != nil {
dialog.ShowError(err, w)
return
}
if dir != nil {
fmt.Println(dir.Path())
save_dir = dir.Path() // here value of save_dir shall be updated!
}
fmt.Println(save_dir)
}, w)
return save_dir
}
func main() {
a := app.New()
w := a.NewWindow("FileDialogTest")
hello := widget.NewLabel("Hello Fyne!")
w.SetContent(container.NewVBox(
hello,
widget.NewButton("Go Get Directory!", func() {
hello.SetText(chooseDirectory(w)) // Text of hello updated by return value
}),
))
w.Resize(fyne.NewSize(500, 500))
w.ShowAndRun()
}
It does not work properly, the label hello is updated prior to the return of the value, somehow...
When the button "Go Get Directory!" is clicked the function chooseDirectory should called and the return value should be set as text in the hello-Label.
I am a Golang-Newbie, so my question may be silly for more experienced Go programmers. In any case I would appreciate help!
Thanks in advance,
Vinz
Remember the point of callback function is not to wait. In your code the chooseDirectory(w) is always returned before the user selects any folder. So, you should directly update hello label text within the callback of ShowFolderOpen.
Here is working code as expected.
package main
import (
"fmt"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/widget"
)
func chooseDirectory(w fyne.Window, h *widget.Label) {
dialog.ShowFolderOpen(func(dir fyne.ListableURI, err error) {
save_dir := "NoPathYet!"
if err != nil {
dialog.ShowError(err, w)
return
}
if dir != nil {
fmt.Println(dir.Path())
save_dir = dir.Path() // here value of save_dir shall be updated!
}
fmt.Println(save_dir)
h.SetText(save_dir)
}, w)
}
func main() {
a := app.New()
w := a.NewWindow("FileDialogTest")
hello := widget.NewLabel("Hello Fyne!")
w.SetContent(container.NewVBox(
hello,
widget.NewButton("Go Get Directory!", func() {
chooseDirectory(w, hello) // Text of hello updated by return value
}),
))
w.Resize(fyne.NewSize(500, 500))
w.ShowAndRun()
}

go text/template with tabwriter

I try to have a pretty table with text/template but the columns are not aligned.
text/tabwriter work but text/template make a cleaner code.
How can I use text/template with text/tabwriter?
This is my test :
package main
import (
"os"
"text/template"
)
type a struct {
Title string
Items []items
}
type items struct {
Title string
Body string
}
const templ = `{{.Title}}{{range .Items}}
{{.Title}} {{.Body}}{{end}}
`
func main() {
data := a{
Title: "title1",
Items: []items{
{"item1", "body1"},
{"item2", "body2"},
{"verylongitem3", "body3"}},
}
t := template.New("test")
t, _ = t.Parse(templ)
t.Execute(os.Stdout, data)
}
Output :
title1
item1 body1
item2 body2
verylongitem3 body3
Replace
t.Execute(os.Stdout, data)
with
w := tabwriter.NewWriter(os.Stdout, 8, 8, 8, ' ', 0)
if err := t.Execute(w, data); err != nil {
// handle error
}
w.Flush()
Also, add tabs to the template where you want the column breaks.
playground example

Go: How to use the func() bool arguments in go?

This is a sample code from the Go blackfriday package:
package main
import (
"bytes"
"fmt"
"github.com/russross/blackfriday"
)
func main() {
input := []byte(`##Title
- another paragragh
This is a being rendered in a custom way.
`)
htmlFlags := 0
renderer := &renderer{Html: blackfriday.HtmlRenderer(htmlFlags, "", "").(*blackfriday.Html)}
extensions := 0
unsanitized := blackfriday.Markdown(input, renderer, extensions)
os.Stdout.Write(unsanitized)
}
// renderer implements blackfriday.Renderer and reuses blackfriday.Html for the most part,
// except overriding Link rendering.
type renderer struct {
*blackfriday.Html
}
func (options *renderer) Header(out *bytes.Buffer, text func() bool, level int, id string) {
fmt.Fprintf(out, "<custom link %q to %q>", content, link)
}
The purpose of the code is to customize the link attributes of the output HTML.
I tried to do the same but with p tags:
func (options *renderer) Paragraph(out *bytes.Buffer, text func() bool) {
fmt.Fprintf(out, "<p class='custom'>%q</p>", text)
}
But the output was this:
<h1>Title</h1>
<ul>
<li>another paragragh</li>
</ul>
<p class='custom'>%!q(func() bool=0x80a15d0)</p>
So I have no idea how to output the actual text (This is a being rendered in a custom way.). Any ideas?
This is the source code of the function:
func (options *Html) Paragraph(out *bytes.Buffer, text func() bool) {
marker := out.Len()
doubleSpace(out)
out.WriteString("<p>")
if !text() {
out.Truncate(marker)
return
}
out.WriteString("</p>\n")
}
I think your usage of function is wrong.
Take a look at Html.Paragraph and override this.
Maybe it would look like:
func (options *renderer) Paragraph(out *bytes.Buffer, text func() bool) {
marker := out.Len()
doubleSpace(out)
out.WriteString("<p class='custom'>")
if !text() {
out.Truncate(marker)
return
}
out.WriteString("</p>\n")
}
I believe all you need to do is call text
func (options *renderer) Paragraph(out *bytes.Buffer, text func() bool) {
fmt.Fprintf(out, "<p class='custom'>%q</p>\n", text())
}

Resources