我使用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 BasicApplication Window.

以下是go code和包含.UI文件中相关元素的精简版本:

如果我将.UI文件中的第8行从以下内容更改为:

<object class="GtkApplicationWindow" id="appWin">

对此:

<object class="GtkWindow" id="appWin">

Go code将打开.UI文件,它将工作,但现在我没有应用程序窗口.

如果我保留.UI文件中的第8行不变,那么它仍然会打开该文件,但生成的图形用户界面没有交互作用,并且只有当我停止在GoLand中以调试模式运行的GO程序时它才会关闭.这是因为要运行它,我必须对围棋程序进行两次更改.

  1. 更改此行:

appWindow := builder.GetObject(appWin).Cast().(*gtk.Window)

appWindow := builder.GetObject(appWin).Cast().(*gtk.ApplicationWindow)

  1. 注释掉此行:

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.

推荐答案

Update 2可以回答这个问题的大部分答案.

此外,到目前为止,我认为没有任何理由将应用程序添加到UI文件中.无论如何,它都倾向于抛出错误.

Go相关问答推荐

如何使用Docker Compose配置Go,使main. go文件位于/CMD文件夹中

GoLang:无法发送带有附件的邮箱

如何在v2 Go SDK中使用KeyConditionExpression查询AWS DynamoDb?

go mod tidy会自动升级go.mod中的go版本吗?

如何确定泛型类型在运行时是否可比较?

Go 1.20 中如何计算连接错误?

为什么标准库中的 IsSorted 会反向迭代切片?

如何在正则表达式中使整个单词可选?

生成一个 CSV/Excel,在 Golang 中该列的下拉选项中指定值

是否需要手动调用rand.Seed?

我突然无法再将我的 GoLang 应用程序部署到 Google AppEngine

Go泛型:无效的复合文字

go:识别重新定义标志的包

github.com/rs/zerolog 字段的延迟判断

具有相同提前返回语句的函数的不同基准测试结果

如何从 Go 1.18 中的单个方法返回两种不同的具体类型?

如何在 docker 文件中安装 golang 包?

如何在 Gorm 中获得特定日期的最大值?

try 创建新的 etcdv3 客户端时出现pc error: code = Unavailable desc = error reading from server: EOF

Go 语言的select语句