Golang中QT-Widgets的QFileDialog问题:定义了6个参数,但需要7个?

Golang中QT-Widgets的QFileDialog问题:定义了6个参数,但需要7个? 各位Gopher们,

这对我来说真是个谜。我正在使用 github.com/therecipe/qt-Package 包,并将一个按钮与匿名函数连接起来,用于选择文件或目录并将所选路径设置到 QLineEdit 中。它确实可以这样工作:

import (
	"github.com/therecipe/qt/core"
	"github.com/therecipe/qt/uitools"
	"github.com/therecipe/qt/widgets"
)
//...
var (
  		ui_formConfigs map[string](*widgets.QLineEdit)
   		ui_pushButtons map[string](*widgets.QPushButton)
   	)
ui_formConfigs = make(map[string]*widgets.QLineEdit)
ui_pushButtons = make(map[string]*widgets.QPushButton)
//...
ui_formConfigs["InputDirectory"] = widgets.NewQLineEditFromPointer(widget.FindChild("inputDirectoryLineEdit", core.Qt__FindChildrenRecursively).Pointer())
ui_formConfigs["InputDirectory"].SetText(config.Paths.InputDirectory)
ui_pushButtons["pushButtonSelectInputDirectory"] = widgets.NewQPushButtonFromPointer(widget.FindChild("pushButtonSelectInputDirectory", core.Qt__FindChildrenRecursively).Pointer())
ui_pushButtons["pushButtonSelectInputDirectory"].ConnectClicked(func(checked bool) {
//ui_formConfigs["InputDirectory"].SetText((*widgets.QFileDialog).GetOpenFileName(nil, "Some title", "./", "*", "*", widgets.QFileDialog__ShowDirsOnly))
ui_formConfigs["InputDirectory"].SetText((*widgets.QFileDialog).GetOpenFileName(nil, nil, "Some title", "./", "*", "*", widgets.QFileDialog__ShowDirsOnly))
})

然而,

(*widgets.QFileDialog).GetOpenFileName(nil, nil, "Some Title", "./", "*", "*", widgets.QFileDialog__ShowDirsOnly)

对我来说很奇怪。因为编译器之前提示我:

方法表达式 widgets.(*QFileDialog).GetOpenFileName 的调用参数不足 已有 (nil, string, string, string, string, widgets.QFileDialog__Option) 需要 (*widgets.QFileDialog, widgets.QWidget_ITF, string, string, string, string, widgets.QFileDialog__Option)

现在请看看 src/github.com/therecipe/qt/widgets/widgets.go 中的定义:

func (ptr *QFileDialog) GetOpenFileName(parent QWidget_ITF, caption string, dir string, filter string, selectedFilter string, options QFileDialog__Option) string {...}

我数了6个参数,但编译器需要7个!!!哪里出错了?这怎么可能呢?

提前感谢!


更多关于Golang中QT-Widgets的QFileDialog问题:定义了6个参数,但需要7个?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

7 回复

做得好 😊

更多关于Golang中QT-Widgets的QFileDialog问题:定义了6个参数,但需要7个?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我已经解决了这个问题。我之前忽略了(*widgets.QFileDialog).GetOpenFileName实际上是一种没有定义对象的静态方法!因此,需要将对象作为额外的(第一个)参数来调用。

顺便提一下,还有一个可行的替代方案:

ui_formConfigs["InputDirectory"].SetText(widgets.QFileDialog_GetOpenFileName(nil, "Some Title", "", "", "", widgets.QFileDialog__ShowDirsOnly))

非常感谢您的评论!几年前,我开始开发一个跨平台GUI应用程序,在分析了所有可能性后,我也认为使用Qt是开发面向Linux、Windows和macOS应用程序的最佳方式。当时没有其他方案能与之媲美。我需要使用高效的编译语言进行编程,因为这是一个实时音频程序,需要尽可能高的CPU性能。

我希望将来能用Go重写我的项目并继续开发,很高兴知道有一个可用的Go语言Qt绑定!未来,我期待看到Go被应用于更多类型的编程场景中。

哦,对了!我记得之前在Go语言规范中读到过类似的内容。看看这个:

https://golang.org/ref/spec#Method_expressions

你居然在实际开发中遇到了这种情况,这真的很有趣,而且恭喜你找到了解决方案!在将Go与像Qt这样复杂的C++库绑定的代码中发现一些奇怪的东西是很合理的。

我一直对使用Go编写原生GUI应用的想法很感兴趣,用Qt来提供跨平台GUI支持。你觉得therecipe/qt这个包用起来怎么样?你认为它足够成熟可以用于生产环境吗?它是否能够良好运行,满足你的所有需求……而且没有问题?

我真的很想听听任何在Go中成功编写Qt应用的人的意见!

谢谢 😊 我之前不知道这种静态方法调用是有效的!对于有同样疑问的人,以下示例可能会有帮助:

package main

import "fmt"

type myStructType struct {
	X int
}

func (s myStructType) doSomething(v int) {
	fmt.Println("I got", v)
	s.X = v //X ist actually not needed
}
func (s *myStructType) setValue(v int) {
	fmt.Println("I set", v)
	s.X = v
}

func (s *myStructType) getValue() int {
	return s.X
}

func main() {
	var a myStructType = myStructType{123}
	//Static method call, the first *additional* argument is the object!
	fmt.Println("I read", (*myStructType).getValue(&a)) // 123
	myStructType.doSomething(a, 1)                      // 1
	(*myStructType).setValue(&a, 2)                     // 2
	fmt.Println("I read", (*myStructType).getValue(&a)) // 2
}

我一直对使用Go编写原生GUI应用的想法很感兴趣,通过Qt提供跨平台GUI支持。请问therecipe/qt包对您来说效果如何?在您看来,它是否已经足够成熟可用于生产环境?它是否能够良好运行并满足您的所有需求……且没有出现问题?

……嗯,我现在决定将QT投入生产使用。最初我用go-QTgo-GTKgo-GTK3做了一些小实验。过去我喜欢在Python中使用WxWidgets和GTK,对QT不太感冒。对我来说QT过于庞大,而我很喜欢Glade和wxGlade构建器。但现在我需要编写几个工艺可视化界面,这些界面必须能在Win7 😪和Win10 🤕上运行,同时也要支持Linux 😍。

目前看来,QT似乎是唯一足够成熟的GUI框架,能够在多系统上运行且无需大量配置!遗憾的是go-GTK还不够成熟,在Windows下问题更多。但我不得不承认,用QT进行交叉编译确实让我有些头疼。在Win7_32位系统上直接编译go-QT也遇到了许多尚未解决的问题。在Linux下使用Docker开发应用程序似乎是最便捷的方式,但最终要部署到各种Windows系统上。至少我现在有信心,相关问题总能找到解决办法。

另一种替代方案是使用JavaScript-jQuery-EasyUI等框架设计界面,就像现在大家普遍做的那样。但我不喜欢通过消耗大量内存和引入无数依赖来弥补性能缺陷。

QT有一个显著优点:实践证明,将Qt Widgets 5.11的代码示例移植到Go非常实用,这也间接说明其文档质量很高。此外,您还应该关注GitHub - therecipe/examples: Examples for https://github.com/therecipe/qt

顺便提一下,Home · tomarus/go-gui-libs Wiki · GitHub提供了当前Go语言可实现的可视化技术的精彩概览!

在Go语言中使用therecipe/qt包时,QFileDialog.GetOpenFileName方法确实需要7个参数,这与您看到的函数签名一致。问题在于您使用了方法表达式的调用方式,这需要将接收者作为第一个参数传递。

让我们分析一下正确的调用方式:

问题分析

从错误信息可以看出:

  • 方法表达式需要:(*widgets.QFileDialog, widgets.QWidget_ITF, string, string, string, string, widgets.QFileDialog__Option)
  • 您提供了:(nil, string, string, string, string, widgets.QFileDialog__Option)

正确的调用方式

方式1:使用包级函数(推荐)

ui_pushButtons["pushButtonSelectInputDirectory"].ConnectClicked(func(checked bool) {
    fileName := widgets.QFileDialog_GetOpenFileName(nil, "Some Title", "./", "*", "*", widgets.QFileDialog__ShowDirsOnly)
    ui_formConfigs["InputDirectory"].SetText(fileName)
})

方式2:创建QFileDialog实例

ui_pushButtons["pushButtonSelectInputDirectory"].ConnectClicked(func(checked bool) {
    fileDialog := widgets.NewQFileDialog(nil, 0)
    fileName := fileDialog.GetOpenFileName(nil, "Some Title", "./", "*", "*", widgets.QFileDialog__ShowDirsOnly)
    ui_formConfigs["InputDirectory"].SetText(fileName)
})

方式3:使用方法表达式(需要接收者)

ui_pushButtons["pushButtonSelectInputDirectory"].ConnectClicked(func(checked bool) {
    fileDialog := widgets.NewQFileDialog(nil, 0)
    // 方法表达式调用 - 需要接收者作为第一个参数
    fileName := (*widgets.QFileDialog).GetOpenFileName(fileDialog, nil, "Some Title", "./", "*", "*", widgets.QFileDialog__ShowDirsOnly)
    ui_formConfigs["InputDirectory"].SetText(fileName)
})

完整的工作示例

package main

import (
    "github.com/therecipe/qt/core"
    "github.com/therecipe/qt/widgets"
)

func main() {
    app := widgets.NewQApplication(len(os.Args), os.Args)
    
    window := widgets.NewQMainWindow(nil, 0)
    centralWidget := widgets.NewQWidget(nil, 0)
    layout := widgets.NewQVBoxLayout()
    
    lineEdit := widgets.NewQLineEdit(nil)
    button := widgets.NewQPushButton2("Select Directory", nil)
    
    layout.AddWidget(lineEdit, 0, 0)
    layout.AddWidget(button, 0, 0)
    centralWidget.SetLayout(layout)
    window.SetCentralWidget(centralWidget)
    
    button.ConnectClicked(func(checked bool) {
        // 使用包级函数 - 最简洁的方式
        selectedDir := widgets.QFileDialog_GetOpenFileName(
            nil,                    // parent
            "Select Input Directory", // caption
            "./",                   // dir
            "All Files (*)",        // filter
            "",                     // selectedFilter
            widgets.QFileDialog__ShowDirsOnly, // options
        )
        lineEdit.SetText(selectedDir)
    })
    
    window.Show()
    app.Exec()
}

参数说明

GetOpenFileName的7个参数分别是:

  1. parent QWidget_ITF - 父窗口(可为nil)
  2. caption string - 对话框标题
  3. dir string - 初始目录
  4. filter string - 文件过滤器
  5. selectedFilter string - 选中的过滤器
  6. options QFileDialog__Option - 选项标志
  7. 返回 string - 选择的文件路径

推荐使用widgets.QFileDialog_GetOpenFileName这个包级函数,它封装了方法调用,使用起来更简洁。

回到顶部