我使用GTK才用了几天,因为我的围棋程序需要一个图形用户界面,所以这是一个新手问题.作为新手,我 Select 了我能找到的最简单的方法来开始,并使用Cambalache生成了一个.UI文件,然后在我的Go应用程序中调用了该文件.
我在.UI文件中放置了ApplicationWindow以下的所有内容,并让它加载并与gkt4-builder-至ol正常工作,但在我的go应用程序中,我在GUI中没有事件.查看示例代码时,我突然想到,我需要将ApplicationWindow附加到在go程序中实例化的GTK应用程序中,我通过将ApplicationWindow更改为一个窗口来验证这一点,它工作得很好,因为我可以将普通窗口添加到GTK应用程序中.
问题是我找不到一种方法来附加一个ApplicationWindow到应用程序后,从UI文件中提取它.将windows附加到应用程序的唯一方法是app.AddWindow(),但这只增加了GtkWindow,而不是GtkApplicationWindow,在强类型语言如go中,这是一个"no go"(没有双关语).
您可以将GTK应用程序与ApplicationWindow一起导出到.UI文件中,理论上,如果您可以成功地这样做,您可以将它们解压缩并以这种方式连接它们.然而,我还没有成功导出GTK应用程序,ApplicationWindow和菜单,因为gkt4-Builder-Tool总是会出现验证错误(在try 了许多配置之后),所以Cambalache不知道如何导出该组合;或者我不知道如何让它这样做;或者它在.UI文件中不是真正合法的组合.
所以我的问题是,我是否应该放弃try 在.UI文件中存储ApplicationWindow,而只是在代码中构建ApplicationWindow小部件,或者还有其他我还没有学会的 Select ?
如果真的没有必要,我可以放弃ApplicationWindow分,直接 Select Windows作为另一种 Select .
感谢您的知识和经验.
谢谢!
UPDATE:个
更清楚地说,这是基于克里普托的 comments .
以下是代码.这不会直接运行,因为我从一个大得多的程序中提取了main()中的相关代码片段,这个代码片段中不存在env, log := boot.Initialize()
,但是理解这个问题应该没有关系.
我知道GTK GUI中只有一个Application Window.这个概念类似于,如果不是相同的,从我的老Visual Basic天Application Window.
以下是go code和包含.UI文件中相关元素的精简版本:
如果我将.UI文件中的第8行从以下内容更改为:
<object class="GtkApplicationWindow" id="appWin">
个
对此:
<object class="GtkWindow" id="appWin">
个
Go code将打开.UI文件,它将工作,但现在我没有应用程序窗口.
如果我保留.UI文件中的第8行不变,那么它仍然会打开该文件,但生成的图形用户界面没有交互作用,并且只有当我停止在GoLand中以调试模式运行的GO程序时它才会关闭.这是因为要运行它,我必须对围棋程序进行两次更改.
- 更改此行:
appWindow := builder.GetObject(
appWin).Cast().(*gtk.Window)
至
appWindow := builder.GetObject(
appWin).Cast().(*gtk.ApplicationWindow)
- 注释掉此行:
app.AddWindow(appWindow)
个
And 2nd one is the problem because now the Window is not attached 至 the application which I am sure is why it's non-interactive.
package main
import (
"os"
"github.com/diamondburned/gotk4/pkg/gio/v2"
"github.com/diamondburned/gotk4/pkg/gtk/v4"
"gitlab.com/trading5124936/core.git/loggers"
)
func main() {
env, log := boot.Initialize()
var app *gtk.Application
app = gtk.NewApplication(`site.TradingAnalyzer`, gio.ApplicationFlagsNone)
app.ConnectActivate(func() { activate(app, log, env.Paths.GUIFile) })
if code := app.Run(os.Args); code > 0 {
os.Exit(code)
}
}
func activate(app *gtk.Application, log *loggers.Logger, guiPath string) {
// You can build UIs using Cambalache (https://flathub.org/apps/details/ar.xjuan.Cambalache)
b, err := os.ReadFile(guiPath)
if err != nil {
log.Critical(err)
return
}
uiXML := string(b)
builder := gtk.NewBuilderFromString(uiXML, len(uiXML))
// MainWindow and But至n are object IDs from the UI file
appWindow := builder.GetObject(`appWin`).Cast().(*gtk.Window)
entry := builder.GetObject(`GeneralSetup.Timezone`).Cast().(*gtk.Entry)
entry.Connect("changed", func() {
println(`Changed`)
})
app.AddWindow(appWindow)
appWindow.Show()
}
下面是.UI文件:
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.16.0 -->
<interface domain="ta.site">
<!-- interface-name TradingAnalyzer.ui -->
<!-- interface-authors Reg Proc至r -->
<requires lib="gtk" version="4.6"/>
<object class="GtkApplication" id="app"/>
<object class="GtkApplicationWindow" id="appWin">
<property name="default-height">925</property>
<property name="default-width">1200</property>
<child>
<object class="GtkPaned">
<child>
<object class="GtkFrame">
<property name="label">Settings</property>
<child>
<object class="GtkStackSidebar">
<property name="halign">start</property>
<property name="height-request">900</property>
<property name="stack">pages</property>
<property name="valign">start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkFrame">
<child>
<object class="GtkStack" id="pages">
<property name="name">Timezone</property>
<child>
<object class="GtkStackPage" id="GeneralSetup">
<property name="child">
<object class="GtkFlowBox">
<property name="margin-bot至m">20</property>
<property name="margin-end">50</property>
<property name="margin-start">50</property>
<property name="margin-至p">20</property>
<property name="name">Timezone</property>
<child>
<object class="GtkEntry" id="GeneralSetup.Timezone">
<property name="activates-default">True</property>
<property name="halign">start</property>
<property name="height-request">10</property>
<property name="input-purpose">alpha</property>
<property name="placeholder-text">Timezone</property>
<property name="text">America/Phoenix</property>
<property name="至oltip-text">Enter your timezone</property>
<property name="valign">center</property>
<property name="width-request">50</property>
</object>
</child>
</object>
</property>
<property name="name">General Setup</property>
<property name="title">General Setup</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>
UPDATE 2个
I found a partial answer. You can do it but you need 至 add the App 至 the ApplicationWindow, not the other way around so it's a different function. Here's the way it works (It's also a little shorter as I learned there's a function 至 load from a file):
func activate(app *gtk.Application, log *loggers.Logger, guiPath string, appName string) {
const ext = `.ui`
guiPath += `/`
builder := gtk.NewBuilderFromFile(guiPath + appName + ext)
// builder := gtk.NewBuilderFromFile(guiPath + `Another template File.ui`)
appWindow := builder.GetObject(`appWin`).Cast().(*gtk.ApplicationWindow)
entry := builder.GetObject(`GeneralSetup.Timezone`).Cast().(*gtk.Entry)
entry.Connect("changed", func() {
println(`Changed`)
})
// ***** THE LINE THAT MAKES THE DIFFERENCE ***
appWindow.SetApplication(app)
appWindow.Show()
}
I'm still not sure if there's ever a case where you would export the application object in至 one of these .UI files.
I haven't found an example of anyone doing so and I'm inclined 至 believe that's not what you are supposed 至 do but I'm still learning so could easily be wrong.