Go语言跨平台GUI工具包tk9.0
不得不说,这名字起的.....tk9.0是一个用Go语言编写的跨平台GUI工具包,它使用Tcl/Tk作为底层图形库,无需CGo,这意味着您可以使用它来创建原生跨平台应用程序,而无需依赖于C语言编译器
优势介绍:
- 跨平台: tk9.0支持Windows、macOS、Linux和FreeBSD等多个平台,您可以轻松地将您的应用程序移植到不同的操作系统上。
- 无需CGo: tk9.0的实现完全使用Go语言编写,无需依赖于CGo,这意味着您不需要安装任何C语言编译器,可以轻松地将您的应用程序部署到不同的环境中。
- 易于使用: tk9.0提供了简洁直观的API,方便您快速上手并创建自己的GUI应用程序。
- 丰富的功能: tk9.0提供了丰富的控件,包括按钮、标签、文本框、列表框、滚动条、菜单等,可以满足您各种开发需求。
- 高度可定制: tk9.0允许您自定义控件的外观和行为,以满足您的应用程序的特定需求。
这是一些官方示例
这些示例中写的都比较简单,并没有过多的多窗口或复杂的使用,但是常用的窗体内容的展示都有了. 开始展示
项目地址 Gitlab仓库
示例1. 图片+按钮
package main
import _ "embed"
import . "modernc.org/tk9.0"
//go:embed gopher.png
var gopher []byte
func main() {
Pack(Label(Image(NewPhoto(Data(gopher)))),
TExit(),
Padx("1m"), Pady("2m"), Ipadx("1m"), Ipady("1m"))
App.Center().Wait()
}
示例2. 菜单
package main
import (
"fmt"
. "modernc.org/tk9.0"
"runtime"
)
func main() {
menubar := Menu()
fileMenu := menubar.Menu()
fileMenu.AddCommand(Lbl("New"), Underline(0), Accelerator("Ctrl+N"))
fileMenu.AddCommand(Lbl("Open..."), Underline(0), Accelerator("Ctrl+O"), Command(func() { GetOpenFile() }))
Bind(App, "<Control-o>", Command(func() { fileMenu.Invoke(1) }))
fileMenu.AddCommand(Lbl("Save"), Underline(0), Accelerator("Ctrl+S"))
fileMenu.AddCommand(Lbl("Save As..."), Underline(5))
fileMenu.AddCommand(Lbl("Close"), Underline(0), Accelerator("Crtl+W"))
fileMenu.AddSeparator()
fileMenu.AddCommand(Lbl("Exit"), Underline(1), Accelerator("Ctrl+Q"), ExitHandler())
Bind(App, "<Control-q>", Command(func() { fileMenu.Invoke(6) }))
menubar.AddCascade(Lbl("File"), Underline(0), Mnu(fileMenu))
editMenu := menubar.Menu()
editMenu.AddCommand(Lbl("Undo"))
editMenu.AddSeparator()
editMenu.AddCommand(Lbl("Cut"))
editMenu.AddCommand(Lbl("Copy"))
editMenu.AddCommand(Lbl("Paste"))
editMenu.AddCommand(Lbl("Delete"))
editMenu.AddCommand(Lbl("Select All"))
menubar.AddCascade(Lbl("Edit"), Underline(0), Mnu(editMenu))
helpMenu := menubar.Menu()
helpMenu.AddCommand(Lbl("Help Index"))
helpMenu.AddCommand(Lbl("About..."))
menubar.AddCascade(Lbl("Help"), Underline(0), Mnu(helpMenu))
App.WmTitle(fmt.Sprintf("%s on %s", App.WmTitle(""), runtime.GOOS))
App.Configure(Mnu(menubar), Width("8c"), Height("6c")).Wait()
}
苹果系统中它展示在顶部菜单栏中,并不在软件窗口里
示例3. 文本内容
package main
import . "modernc.org/tk9.0"
func main() {
var scroll *TScrollbarWidget
t := Text(Font("helvetica", 10), Yscrollcommand(func(e *Event) { e.ScrollSet(scroll) }), Setgrid(true), Wrap("word"), Padx("2m"), Pady("2m"))
scroll = TScrollbar(Command(func(e *Event) { e.Yview(t) }))
Grid(t, Sticky("news"), Pady("2m"))
Grid(scroll, Row(0), Column(1), Sticky("nes"), Pady("2m"))
GridRowConfigure(App, 0, Weight(1))
GridColumnConfigure(App, 0, Weight(1))
Grid(TExit(), Padx("1m"), Pady("2m"), Ipadx("1m"), Ipady("1m"))
t.TagConfigure("bgstipple", Background(Black), Borderwidth(0), Bgstipple(Gray12))
t.TagConfigure("big", Font("helvetica", 12, "bold"))
t.TagConfigure("bold", Font("helvetica", 10, "bold", "italic"))
t.TagConfigure("center", Justify("center"))
t.TagConfigure("color1", Background("#a0b7ce"))
t.TagConfigure("color2", Foreground(Red))
t.TagConfigure("margins", Lmargin1("12m"), Lmargin2("6m"), Rmargin("10m"))
t.TagConfigure("overstrike", Overstrike(1))
t.TagConfigure("raised", Relief("raised"), Borderwidth(1))
t.TagConfigure("right", Justify("right"))
t.TagConfigure("spacing", Spacing1("10p"), Spacing2("2p"), Lmargin1("12m"), Lmargin2("6m"), Rmargin("10m"))
t.TagConfigure("sub", Offset("-2p"), Font("helvetica", 8))
t.TagConfigure("sunken", Relief("sunken"), Borderwidth(1))
t.TagConfigure("super", Offset("4p"), Font("helvetica", 8))
t.TagConfigure("tiny", Font("times", 8, "bold"))
t.TagConfigure("underline", Underline(1))
t.TagConfigure("verybig", Font(CourierFont(), 22, "bold"))
t.InsertML(`Text widgets like this one allow you to display information in a variety of styles. Display styles are controlled
using a mechanism called <bold>tags</bold>. Tags are just textual names that you can apply to one or more ranges of characters within a
text widget. You can configure tags with various display styles. If you do this, then the tagged characters will be displayed with the
styles you chose. The available display styles are:
<br><br><big>1. Font.</big> You can choose any system font, <verybig>large</verybig> or <tiny>small</tiny>.
<br><br><big>2. Color.</big> You can change either the <color1>background</color1> or <color2>foreground</color2> color, or
<color1><color2>both</color2></color1>.
<br><br><big>3. Stippling.</big> You can cause the <bgstipple>background</bgstipple> information to be drawn with a stipple fill instead
of a solid fill.
<br><br><big>4. Underlining.</big> You can <underline>underline</underline> ranges of text.
<br><br><big>5. Overstrikes.</big> You can <overstrike>draw lines through</overstrike> ranges of text.
<br><br><big>6. 3-D effects.</big> You can arrange for the background to be drawn with a border that makes characters appear either
<raised>raised</raised> or <sunken>sunken</sunken>.
<br><br><big>7. Justification.</big> You can arrange for lines to be displayed <br>left-justified <br><right>right-justified, or</right>
<br><center>centered.</center>
<br><br><big>8. Superscripts and subscripts.</big> You can control the vertical position of text to generate superscript effects like
10<super>n</super> or subscript effects like X<sub>i</sub>.
<br><br><big>9. Margins.</big> You can control the amount of extra space left on each side of the text
<br><br><margins>This paragraph is an example of the use of margins. It consists of a single line of text that wraps around on the
screen. There are two separate left margin values, one for the first display line associated with the text line, and one for the
subsequent display lines, which occur because of wrapping. There is also a separate specification for the right margin, which is used to
choose wrap points for lines.</margins>
<br><br><big>10. Spacing.</big> You can control the spacing of lines with three separate parameters. "Spacing1" tells how much extra
space to leave above a line, "spacing3" tells how much space to leave below a line, and if a text line wraps, "spacing2" tells how much
space to leave between the display lines that make up the text line.
<br><spacing>These indented paragraphs illustrate how spacing can be used. Each paragraph is actually a single line in the text widget,
which is word-wrapped by the widget.</spacing>
<br><spacing>Spacing1 is set to 10 points for this text, which results in relatively large gaps between the paragraphs. Spacing2 is set
to 2 points, which results in just a bit of extra space within a pararaph. Spacing3 isn't used in this example.</spacing>
<br><spacing>To see where the space is, select ranges of text within these paragraphs. The selection highlight will cover the extra
space.</spacing>`)
App.Center().Wait()
}
示例4. svg图片
package main
import . "modernc.org/tk9.0"
// https://en.wikipedia.org/wiki/SVG
const svg = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="391" height="391" viewBox="-70.5 -70.5 391 391" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect fill="#fff" stroke="#000" x="-70" y="-70" width="390" height="390"/>
<g opacity="0.8">
<rect x="25" y="25" width="200" height="200" fill="lime" stroke-width="4" stroke="pink" />
<circle cx="125" cy="125" r="75" fill="orange" />
<polyline points="50,150 50,200 200,200 200,100" stroke="red" stroke-width="4" fill="none" />
<line x1="50" y1="50" x2="200" y2="200" stroke="blue" stroke-width="4" />
</g>
</svg>`
func main() {
Pack(Label(Image(NewPhoto(Data(svg)))),
TExit(),
Padx("1m"), Pady("2m"), Ipadx("1m"), Ipady("1m"))
App.Center().Wait()
}
示例5. 计算器
package main
import "github.com/expr-lang/expr"
import . "modernc.org/tk9.0"
func main() {
out := Label(Height(2), Anchor("e"), Txt("(123+232)/(123-10)"))
Grid(out, Columnspan(4), Sticky("e"))
var b *ButtonWidget
for i, c := range "C()/789*456-123+0.=" {
b = Button(Txt(string(c)),
Command(
func() {
switch c {
case 'C':
out.Configure(Txt(""))
case '=':
x, err := expr.Eval(out.Txt(), nil)
if err != nil {
MessageBox(Icon("error"), Msg(err.Error()), Title("Error"))
x = ""
}
out.Configure(Txt(x))
default:
out.Configure(Txt(out.Txt() + string(c)))
}
},
),
Width(-4))
Grid(b, Row(i/4+1), Column(i%4), Sticky("news"), Ipadx("1.5m"), Ipady("2.6m"))
}
Grid(b, Columnspan(2))
App.Configure(Padx(0), Pady(0)).Wait()
}
示例6. 字体
package main
import "fmt"
import "slices"
import . "modernc.org/tk9.0"
func main() {
var scroll *TScrollbarWidget
t := Text(Wrap("none"), Setgrid(true), Yscrollcommand(func(e *Event) { e.ScrollSet(scroll) }))
scroll = TScrollbar(Command(func(e *Event) { e.Yview(t) }))
fonts := FontFamilies()
slices.Sort(fonts)
Grid(t, Sticky("news"), Pady("2m"), Ipadx("1m"), Ipady("1m"))
Grid(scroll, Row(0), Column(1), Sticky("nes"), Pady("2m"))
GridRowConfigure(App, 0, Weight(1))
GridColumnConfigure(App, 0, Weight(1))
Grid(TExit(), Padx("1m"), Pady("2m"), Ipadx("1m"), Ipady("1m"))
m := map[string]bool{}
for i, font := range fonts {
if m[font] {
continue
}
m[font] = true
tag := fmt.Sprintf("t%v", i)
t.TagConfigure(tag, Font(NewFont(Family(font))))
t.Insert("end", font+": ", "", "Lorem ipsum dolor sit amet, consectetur adipiscing elit...\n", tag)
}
App.Center().Wait()
}
示例7. 这个示例需要安装Gnuplot 5.4+
package main
import . "modernc.org/tk9.0"
var cm = int(TkScaling()*72/2.54 + 0.5)
func main() {
Pack(Label(Image(NewPhoto(Width(20*cm), Height(15*cm)).Graph("set grid; splot x**2+y**2, x**2-y**2"))),
TExit(),
Padx("1m"), Pady("2m"), Ipadx("1m"), Ipady("1m"))
App.Center().Wait()
}
示例8 这个也需要安装 Gnuplot 5.4+
package main
import . "modernc.org/tk9.0"
// https://gnuplot.sourceforge.net/demo_5.4/hidden2.html
const script = `
set multiplot title "Interlocking Tori"
set title "PM3D surface\nno depth sorting"
set parametric
set urange [-pi:pi]
set vrange [-pi:pi]
set isosamples 50,20
set origin -0.02,0.0
set size 0.55, 0.9
unset key
unset xtics
unset ytics
unset ztics
set border 0
set view 60, 30, 1.5, 0.9
unset colorbox
set pm3d scansbackward
splot cos(u)+.5*cos(u)*cos(v),sin(u)+.5*sin(u)*cos(v),.5*sin(v) with pm3d,1+cos(u)+.5*cos(u)*cos(v),.5*sin(v),sin(u)+.5*sin(u)*cos(v) with pm3d
set title "PM3D surface\ndepth sorting"
set origin 0.40,0.0
set size 0.55, 0.9
set colorbox vertical user origin 0.9, 0.15 size 0.02, 0.50
set format cb "%.1f"
set pm3d depthorder
splot cos(u)+.5*cos(u)*cos(v),sin(u)+.5*sin(u)*cos(v),.5*sin(v) with pm3d,1+cos(u)+.5*cos(u)*cos(v),.5*sin(v),sin(u)+.5*sin(u)*cos(v) with pm3d
unset multiplot`
var cm = int(TkScaling()*72/2.54 + 0.5)
func main() {
Pack(Label(Image(NewPhoto(Width(20*cm), Height(15*cm)).Graph(script))),
TExit(),
Padx("1m"), Pady("2m"), Ipadx("1m"), Ipady("1m"))
App.Center().Wait()
}
示例9 . 依旧要安装....
package main
import . "modernc.org/tk9.0"
// https://gnuplot.sourceforge.net/demo_5.4/surface2.9.gnu
const script = `
set dummy u, v
set key bmargin center horizontal Right noreverse enhanced autotitle nobox
set parametric
set view 50, 30, 1, 1
set isosamples 50, 20
set hidden3d back offset 1 trianglepattern 3 undefined 1 altdiagonal bentover
set style data lines
set xyplane relative 0
set title "Interlocking Tori"
set grid
set urange [ -3.14159 : 3.14159 ] noreverse nowriteback
set vrange [ -3.14159 : 3.14159 ] noreverse nowriteback
set xrange [ * : * ] noreverse writeback
set x2range [ * : * ] noreverse writeback
set yrange [ * : * ] noreverse writeback
set y2range [ * : * ] noreverse writeback
set zrange [ * : * ] noreverse writeback
set cbrange [ * : * ] noreverse writeback
set rrange [ * : * ] noreverse writeback
set colorbox vertical origin screen 0.9, 0.2 size screen 0.05, 0.6 front noinvert bdefault
NO_ANIMATION = 1
splot cos(u)+.5*cos(u)*cos(v),sin(u)+.5*sin(u)*cos(v),.5*sin(v) with lines,1+cos(u)+.5*cos(u)*cos(v),.5*sin(v),sin(u)+.5*sin(u)*cos(v) with lines`
var cm = int(TkScaling()*72/2.54 + 0.5)
func main() {
Pack(Canvas(Width(20*cm), Height(15*cm), Background(White)).Graph(script),
TExit(),
Padx("1m"), Pady("2m"), Ipadx("1m"), Ipady("1m"))
App.Center().Wait()
}
示例10 公式图
package main
import . "modernc.org/tk9.0"
func main() {
tex := `$$\int _0 ^\infty {{\sin ax \sin bx}\over{x^2}}\,dx = {\pi a\over 2}$$`
Pack(Label(Relief("sunken"), Image(NewPhoto(Data(TeX(tex, 2*TkScaling()*72/600))))),
TExit(),
Padx("1m"), Pady("2m"), Ipadx("1m"), Ipady("1m"))
App.Center().Wait()
}
示例11 文本中嵌入公式等小组件
package main
import . "modernc.org/tk9.0"
import _ "embed"
//go:embed gotk.png
var icon []byte
func main() {
fontSize := int(10*TkScaling()/NativeScaling + 0.5)
font := Font("helvetica", fontSize)
var scroll *TScrollbarWidget
t := Text(font, Height(15), Yscrollcommand(func(e *Event) { e.ScrollSet(scroll) }), Setgrid(true), Wrap("word"),
Padx("4p"), Pady("12p"))
scroll = TScrollbar(Command(func(e *Event) { e.Yview(t) }))
Grid(t, Sticky("news"), Pady("2m"))
Grid(scroll, Row(0), Column(1), Sticky("nes"), Pady("2m"))
GridRowConfigure(App, 0, Weight(1))
GridColumnConfigure(App, 0, Weight(1))
Grid(Exit().Configure(font), Padx("1m"), Pady("2m"), Ipadx("1m"), Ipady("1m"))
t.TagConfigure("c", Justify("center"))
t.TagConfigure("e", Offset("-2p"))
t.TagConfigure("t", Font("times", fontSize))
sym := " <t>T<e>E</e>X</t> "
tex := `$Q(\xi) = \lambda_1 y_1^2 \sum_{i=2}^n \sum_{j=2}^n y_i b_{ij} y_j$`
t.InsertML(`<c>Hello Go + Tk`, NewPhoto(Data(icon)), Padx("4p"), `users!
<br><br>Hello Go + Tk +`, sym, tex, ` users! (\$inline math\$)
<br><br>Hello Go + Tk +`, sym, `$`+tex+`$`, ` users! (\$\$display math\$\$)</c>
<br><br>The above exemplifies embeding pictures and`, sym, `scripts. A text widget can also embed other widgets. For example,
when a`, Button(font, Txt("<Tbutton>")), Padx("4p"), Pady("2p"), Align("center"), `and
a`, Entry(font, Textvariable("<TEntry>"), Background(White), Width(8)), Padx("4p"), Pady("2p"), Align("center"), `are part of
the markup, they will reflow when their containing text widget is resized.`)
App.Center().Wait()
}
示例12 按钮
package main
import _ "embed"
import . "modernc.org/tk9.0"
//go:embed red_corner.png
var red []byte
//go:embed green_corner.png
var green []byte
func main() {
StyleThemeUse("default")
StyleElementCreate("Red.Corner.TButton.indicator", "image", NewPhoto(Data(red)))
StyleElementCreate("Green.Corner.TButton.indicator", "image", NewPhoto(Data(green)))
StyleLayout("Red.Corner.TButton",
"Button.border", Sticky("nswe"), Border(1), Children(
"Button.focus", Sticky("nswe"), Children(
"Button.padding", Sticky("nswe"), Children(
"Button.label", Sticky("nswe"),
"Red.Corner.TButton.indicator", Side("right"), Sticky("ne")))))
StyleLayout("Green.Corner.TButton",
"Button.border", Sticky("nswe"), Border(1), Children(
"Button.focus", Sticky("nswe"), Children(
"Button.padding", Sticky("nswe"), Children(
"Button.label", Sticky("nswe"),
"Green.Corner.TButton.indicator", Side("right"), Sticky("ne")))))
opts := Opts{Padx("1m"), Pady("2m"), Ipadx("1m"), Ipady("1m")}
rb := TButton(Txt("Red"))
gb := TButton(Txt("Green"))
Grid(rb, gb, opts)
Grid(TButton(Txt("Use style"), Command(func() {
rb.Configure(Style("Red.Corner.TButton"))
gb.Configure(Style("Green.Corner.TButton"))
})), TExit(), opts)
App.Wait()
}
示例13. 类似 Bootstrap 5 的主题按钮
package main
import (
. "modernc.org/tk9.0"
"modernc.org/tk9.0/b5"
)
func main() {
background := White
primary := b5.Colors{b5.ButtonText: "#fff", b5.ButtonFace: "#0d6efd", b5.ButtonFocus: "#98c1fe"}
secondary := b5.Colors{b5.ButtonText: "#fff", b5.ButtonFace: "#6c757d", b5.ButtonFocus: "#c0c4c8"}
success := b5.Colors{b5.ButtonText: "#fff", b5.ButtonFace: "#198754", b5.ButtonFocus: "#9dccb6"}
danger := b5.Colors{b5.ButtonText: "#fff", b5.ButtonFace: "#dc3545", b5.ButtonFocus: "#f0a9b0"}
warning := b5.Colors{b5.ButtonText: "#000", b5.ButtonFace: "#ffc107", b5.ButtonFocus: "#ecd182"}
info := b5.Colors{b5.ButtonText: "#000", b5.ButtonFace: "#0dcaf0", b5.ButtonFocus: "#85d5e5"}
light := b5.Colors{b5.ButtonText: "#000", b5.ButtonFace: "#f8f9fa", b5.ButtonFocus: "#e9e9ea"}
dark := b5.Colors{b5.ButtonText: "#fff", b5.ButtonFace: "#212529", b5.ButtonFocus: "#a0a2a4"}
link := b5.Colors{b5.ButtonText: "#1774fd", b5.ButtonFace: "#fff", b5.ButtonFocus: "#c2dbfe"}
StyleThemeUse("default")
opts := Opts{Padx("1m"), Pady("2m"), Ipadx("1m"), Ipady("1m")}
Grid(TButton(Txt("Primary"), Style(b5.ButtonStyle("primary.TButton", primary, background, false))),
TButton(Txt("Secondary"), Style(b5.ButtonStyle("secondary.TButton", secondary, background, false))),
TButton(Txt("Success"), Style(b5.ButtonStyle("success.TButton", success, background, false))),
opts)
Grid(TButton(Txt("Danger"), Style(b5.ButtonStyle("danger.TButton", danger, background, false))),
TButton(Txt("Warning"), Style(b5.ButtonStyle("warning.TButton", warning, background, false))),
TButton(Txt("Info"), Style(b5.ButtonStyle("info.TButton", info, background, false))),
opts)
Grid(TButton(Txt("Light"), Style(b5.ButtonStyle("light.TButton", light, background, false))),
TButton(Txt("Dark"), Style(b5.ButtonStyle("dark.TButton", dark, background, false))),
TButton(Txt("Link"), Style(b5.ButtonStyle("link.TButton", link, background, false))),
opts)
Grid(TButton(Txt("Primary"), Style(b5.ButtonStyle("focused.primary.TButton", primary, background, true))),
TButton(Txt("Secondary"), Style(b5.ButtonStyle("focused.secondary.TButton", secondary, background, true))),
TButton(Txt("Success"), Style(b5.ButtonStyle("focused.success.TButton", success, background, true))),
opts)
Grid(TButton(Txt("Danger"), Style(b5.ButtonStyle("focused.danger.TButton", danger, background, true))),
TButton(Txt("Warning"), Style(b5.ButtonStyle("focused.warning.TButton", warning, background, true))),
TButton(Txt("Info"), Style(b5.ButtonStyle("focused.info.TButton", info, background, true))),
opts)
Grid(TButton(Txt("Light"), Style(b5.ButtonStyle("focused.light.TButton", light, background, true))),
TButton(Txt("Dark"), Style(b5.ButtonStyle("focused.dark.TButton", dark, background, true))),
TButton(Txt("Link"), Style(b5.ButtonStyle("focused.link.TButton", link, background, true))),
opts)
Grid(TExit(), Columnspan(3), opts)
App.Configure(Background(background)).Wait()
}
不同系统下的效果展示
macOS下的效果
FreeBSD Xfce4
Linux Mate 1.26.0
Windows 11
版权声明:本文为原创文章,版权归 全栈开发技术博客 所有。
本文链接:https://www.lvtao.net/dev/go-gui-tk90.html
转载时须注明出处及本声明