Entwicklung

Erstellen einer Markdown-Konverter-GUI mit Fyne in Go

01.03.2024

Erstellen einer Markdown-Konverter-GUI mit Fyne in Go

6min. Lesezeit

6min. Lesezeit

6min. Lesezeit

Im heutigen Blogbeitrag werde ich Sie durch den Prozess der Erstellung einer einfachen grafischen Benutzeroberfläche (GUI) in Go führen, die mit Fyne normalen Text in Markdown konvertiert. Fyne ist ein leichtes und benutzerfreundliches GUI-Toolkit für Go, das sich perfekt für die Erstellung plattformübergreifender Anwendungen mit schönen Benutzeroberflächen eignet.

Einführung in Fyne

Fyne ist ein Go-basiertes Framework zum Erstellen grafischer Benutzeroberflächen auf verschiedenen Plattformen, einschließlich Desktop und Mobilgeräten. Es bietet einen umfangreichen Satz an Widgets und Tools zum Erstellen reaktionsfähiger und attraktiver Anwendungen mit minimalem Code.

Einrichtung der Umgebung

Stellen Sie zunächst sicher, dass Go auf Ihrem System installiert ist. Sie können Fyne mit dem folgenden Befehl installieren:

go get fyne.io/fyne/v2

Erstellen der Anwendung

Lassen Sie uns in den Code eintauchen und sehen, wie wir mit Fyne unsere Markdown-Konverter-GUI erstellen können:

package main

import (
	"io"
	"strings"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/storage"
	"fyne.io/fyne/v2/widget"
)

type config struct {
	EditWidget    *widget.Entry
	PreviewWidget *widget.RichText
	CurrentFile   fyne.URI
	SaveMenuItem  *fyne.MenuItem
}

var cfg config

func main() {
	// Create a Fyne application
	a := app.New()

	// Create a window for the app
	win := a.NewWindow("Go Markdown")

	// Get the user interface
	edit, preview := cfg.makeUI()
	cfg.createMenuItems(win)

	// Set the content of the window
	win.SetContent(container.NewHSplit(edit, preview))

	// Show window and run app
	win.Resize(fyne.Size{Width: 800, Height: 500})
	win.CenterOnScreen()
	win.ShowAndRun()
}

func (app *config) makeUI() (*widget.Entry, *widget.RichText) {
	edit := widget.NewMultiLineEntry()
	preview := widget.NewRichTextFromMarkdown("")
	app.EditWidget = edit
	app.PreviewWidget = preview

	edit.OnChanged = preview.ParseMarkdown

	return edit, preview
}

func (app *config) createMenuItems(win fyne.Window) {
	// Define menu items
	openMenuItem := fyne.NewMenuItem("Open...", app.openFunc(win))
	saveMenuItem := fyne.NewMenuItem("Save", app.saveFunc(win))
	app.SaveMenuItem = saveMenuItem
	app.SaveMenuItem.Disabled = true
	saveAsMenuItem := fyne.NewMenuItem("Save As...", app.saveAsFunc(win))
	quit := fyne.NewMenuItem("Quit", nil)
	quit.IsQuit = true

	// Create file menu
	fileMenu := fyne.NewMenu("File", openMenuItem, saveMenuItem, saveAsMenuItem, quit)
	menu := fyne.NewMainMenu(fileMenu)
	win.SetMainMenu(menu)
}

// Define file filter for Markdown files
var filter = storage.NewExtensionFileFilter([]string{".md", ".MD"})

func (app *config) saveFunc(win fyne.Window) func() {
	return func() {
		if app.CurrentFile != nil {
			write, err := storage.Writer(app.CurrentFile)
			if err != nil {
				dialog.ShowError(err, win)
				return
			}

			write.Write([]byte(app.EditWidget.Text))
			dialog.ShowInformation("File saved", "You have successfully saved the file!", win)
			defer write.Close()
		}
	}
}

func (app *config) openFunc(win fyne.Window) func() {
	return func() {
		openDialog := dialog.NewFileOpen(func(read fyne.URIReadCloser, err error) {
			if err != nil {
				dialog.ShowError(err, win)
				return
			}

			if read == nil {
				return
			}

			defer read.Close()

			data, err := io.ReadAll(read)
			if err != nil {
				dialog.ShowError(err, win)
				return
			}

			app.EditWidget.SetText(string(data))

			app.CurrentFile = read.URI()

			win.SetTitle(win.Title() + " - " + read.URI().Name())
			app.SaveMenuItem.Disabled = false
		}, win)

		openDialog.SetFilter(filter)
		openDialog.Show()
	}
}

func (app *config) saveAsFunc(win fyne.Window) func() {
	return func() {
		saveDialog := dialog.NewFileSave(func(write fyne.URIWriteCloser, err error) {
			if err != nil {
				dialog.ShowError(err, win)
				return
			}

			if write == nil {
				// User canceled
				return
			}

			if !strings.HasSuffix(strings.ToLower(write.URI().String()), ".md") {
				dialog.ShowInformation("Error", "Please name the file with a .md extension", win)
				return
			}

			// Save file
			write.Write([]byte(app.EditWidget.Text))
			app.CurrentFile = write.URI()

			defer write.Close()

			win.SetTitle(win.Title() + " - " + write.URI().Name())
			app.SaveMenuItem.Disabled = false
		}, win)

		saveDialog.SetFileName("untitled.md")
		saveDialog.SetFilter(filter)
		saveDialog.Show()
	}
}

Lassen Sie uns nun den Code untersuchen und jede Funktion verstehen:

main()

Die Funktion main() ist der Einstiegspunkt des Programms. Hier erstellen wir eine Fyne-Anwendungsinstanz, erstellen ein neues Fenster für die App, richten die Benutzeroberfläche ein, erstellen Menüelemente und zeigen das Fenster an.

makeUI()

Die Methode makeUI() ist eine Methode der Konfigurationsstruktur, die die Benutzeroberfläche (UI) der Anwendung erstellt. Es erstellt ein widget.Entry-Widget für die Texteingabe und ein widget.RichText-Widget für die Markdown-Vorschau.

createMenuItems()

Die Methode createMenuItems() ist eine Methode der Konfigurationsstruktur, die die Menüelemente für das Dateimenü erstellt. Es erstellt Menüpunkte für „Öffnen…“, „Speichern“, „Speichern unter…“ und „Beenden“ und weist ihnen Funktionen zu, die bei Auswahl ausgeführt werden sollen.

saveFunc()

Die Methode saveFunc() ist eine Methode der Konfigurationsstruktur, die die Funktion zum Speichern des aktuellen Dokuments implementiert. Wenn eine Datei bereits gespeichert ist, schreibt es den Inhalt des Texteingabefelds in die Datei.

openFunc()

Die Methode openFunc() ist eine Methode der Konfigurationsstruktur, die die Funktion zum Öffnen einer Datei implementiert. Es öffnet sich ein Dialogfeld, in dem der Benutzer eine Datei auswählen kann und dann den Inhalt der ausgewählten Datei in das Texteingabefeld einliest.

saveAsFunc()

Die Methode saveAsFunc() ist eine Methode der Konfigurationsstruktur, die die Funktion implementiert, das aktuelle Dokument unter einem neuen Dateinamen zu speichern. Es öffnet sich ein Dialogfeld, in dem der Benutzer einen Dateinamen und einen Speicherort auswählen kann, und speichert dann den Inhalt des Texteingabefelds in der ausgewählten Datei.

Follow Along
#buildInPublic

All rights Reserved 2023

All rights Reserved 2023

All rights Reserved 2023