If you just want the complete code snippet, here is it.

package main

import (
"github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/gtk"
)

func main() {
    gtk.Init(nil)
    win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
    win.SetTitle("sample app")
    win.Connect("destroy", func() {
        gtk.MainQuit()
    })
    grid, _ := gtk.GridNew()
    win.Add(grid)
    imgview, _ := gtk.ImageNew()
    pbuf, _ := gdk.PixbufNewFromFileAtScale("./img/default.png", 400, 400, true)
    imgview.SetFromPixbuf(pbuf)
    grid.Attach(imgview, 0, 0, 1, 1)
    textentry, _ := gtk.EntryNew()
    grid.AttachNextTo(textentry, imgview, gtk.POS_BOTTOM, 1, 1)
    btnChoose, _ := gtk.ButtonNewWithLabel("Choose An Image")
    grid.AttachNextTo(btnChoose, textentry, gtk.POS_BOTTOM, 1, 1)
    btnChoose.Connect("clicked", func() {
        dlg, _ := gtk.FileChooserDialogNewWith2Buttons(
            "choose an image", nil, gtk.FILE_CHOOSER_ACTION_OPEN,
            "Open", gtk.RESPONSE_OK, "Cancel", gtk.RESPONSE_CANCEL,
        )
        dlg.SetDefaultResponse(gtk.RESPONSE_OK)
        filter, _ := gtk.FileFilterNew()
        filter.SetName("images")
        filter.AddMimeType("image/png")
        filter.AddMimeType("image/jpeg")
        filter.AddPattern("*.png")
        filter.AddPattern("*.jpg")
        filter.AddPattern("*.jpeg")
        dlg.SetFilter(filter)
        response := dlg.Run()
        if response == gtk.RESPONSE_OK {
            filename := dlg.GetFilename()
            // imgview.SetFromFile(filename)
            pixbuf, _ := gdk.PixbufNewFromFileAtScale(filename, 400, 400, true)
            imgview.SetFromPixbuf(pixbuf)
        }
        dlg.Destroy()
    })
    win.SetDefaultSize(800, 600)
    win.ShowAll()
    gtk.Main()
}

I used this code in my opensource OCR application for all desktop computers which runs Mac, Linux or Windows.

Here is a breakdown of the code.

First of all we download the Gtk3 wrapper for Go programming language (which is gotk3) using this command.

go get -u github.com/gotk3/gotk3

After that we start our Go application as usual. And start by initializing Gtk by this code.

gtk.Init(nil)

Then creating a new Gtk window for our program, and give it a title and tell it how to exit.

win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
win.SetTitle("sample app")
win.Connect("destroy", func() {
    gtk.MainQuit()
})

Then we create a grid and put it on the program window, and create image container and text container and a button and put them on the grid.

imgview, _ := gtk.ImageNew()
grid.Attach(imgview, 0, 0, 1, 1)
textentry, _ := gtk.EntryNew()
grid.AttachNextTo(textentry, imgview, gtk.POS_BOTTOM, 1, 1)
btnChoose, _ := gtk.ButtonNewWithLabel("Choose An Image")
grid.AttachNextTo(btnChoose, textentry, gtk.POS_BOTTOM, 1, 1)

We can put a default image in the image widget like this.

pbuf, _ := gdk.PixbufNewFromFileAtScale("./img/default.png", 400, 400, true)
imgview.SetFromPixbuf(pbuf)

or like this.

imgview.SetFromFile(filename)

But I used the pixbuf code because I can resize the image to fit the image container (or image widget).

We can set a default window size for our program like this.

win.SetDefaultSize(800, 600)

Then we must use this code snippet to ensure that the Gtk widgets are shown on the window and the graphics main loop is handling its thing.

win.ShowAll()
gtk.Main()

And here we reach the main task.. the file chooser dialog window. We start by using the clicked signal of the button.

btnChoose.Connect("clicked", func() {
    // the code here will be executed whenever the button clicked
})

Then we add the code inside that function. The code will be executed when the button is clicked. We want to choose the file chooser dialog when the user click that button. So we add this code snippet.

Creating the file chooser dialog like this.

dlg, _ := gtk.FileChooserDialogNewWith2Buttons(
    "choose an image", nil, gtk.FILE_CHOOSER_ACTION_OPEN,
    "Open", gtk.RESPONSE_OK, "Cancel", gtk.RESPONSE_CANCEL,
)

then set the default response, so we can double click on the image or press enter to choose the image in the dialog.

dlg.SetDefaultResponse(gtk.RESPONSE_OK)

Adding a filter for the permitted file types to choose from. In this example I chose the png and jpg image file formats to be allowed.

filter, _ := gtk.FileFilterNew()
filter.SetName("images")
filter.AddMimeType("image/png")
filter.AddMimeType("image/jpeg")
filter.AddPattern("*.png")
filter.AddPattern("*.jpg")
filter.AddPattern("*.jpeg")
dlg.SetFilter(filter)

And know let the file chooser dialog to run and show up on the screen, then get the response.

response := dlg.Run()

We can handle the response. If the response is OK then the image is chosen successfully. But if the response is CANCEL so the user did not chose an image (s/he clicked cancel button).

If the user chose an image and the response is OK, we should get the image and start viewing it or do our goal with it.

if response == gtk.RESPONSE_OK {
    filename := dlg.GetFilename()
    // imgview.SetFromFile(filename)
    pixbuf, _ := gdk.PixbufNewFromFileAtScale(filename, 400, 400, true)
    imgview.SetFromPixbuf(pixbuf)
}

After handling everything about the file chooser dialog, we must destroy the object of it to free the memory allocations and be a good citizen in the operating system.

dlg.Destroy()

That’s it. We are done. Do you recommend reading this blog post? share it!