65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Go 语言创建窗口

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7投票s)

2015年12月1日

CPOL

4分钟阅读

viewsIcon

38807

downloadIcon

962

本技巧介绍了如何使用 Win32 API 函数在 Go 编程语言中创建一个简单的窗口。

引言

本技巧介绍了如何使用 Win32 API 函数在 Go 编程语言中创建一个简单的窗口。

本技巧仅展示了在 Go 中创建简单窗口的步骤。有关 Go 语言的更多信息,您可以访问 Go 文档网站 - https://golang.ac.cn/doc

Go 简介 (摘自 https://golang.ac.cn)

Go 是一种开源编程语言,可以轻松构建简单、可靠和高效的软件。

Go 具有表达力、简洁、清晰和高效的特点。其并发机制使其易于编写能够充分利用多核和网络机器的程序,而其新颖的类型系统则支持灵活和模块化的程序构造。Go 可以快速编译成机器码,但同时具有垃圾回收的便利性和运行时反射的强大功能。它是一种快速的、静态类型的、编译型语言,感觉就像是一种动态类型的、解释型语言。

Using the Code

我假设您具备 Win32 API 的基本知识。

对于这个项目,我使用了 1.5.1 64 位 版本的 Go。

要在 Go 语言中使用 Win32 API,我们需要 'w32' 包。可以在 Git Hub 网站上找到该包 - https://github.com/AllenDang/w32

这是我们的窗口创建代码

Go 源文件中的第一个语句必须是包名。由于我们的程序是一个可执行程序,因此包名必须是 main。它告诉 Go 编译器应该将该包编译成一个可执行程序,而不是一个共享库

package main

在 Go 中,import 关键字用于将包导入到其他包中。因此,我们使用 import 关键字以这种方式导入我们必要的包

import "./w32" // I had putted the w32 package inside the project source folder -

我们还需要导入以下包

import "syscall"
import "unsafe"

Unsafe 是 Go 语言的内置包。它提供用于低级编程的工具,包括违反类型系统的操作。我们需要它将 uintptr 类型转换为指针,并且该包包含一个名为 Sizeof 的函数。我们将使用 Sizeof 函数获取 WNDCLASSEX 结构的大小。

这是一个简单的 Windows 资源 ID 到 uint16 指针转换器函数。我们需要它将 IDI_APPLICATIONIDC_ARROW 常量传递给 LoadIconLoadCursor 函数参数。在 Go 中,类型转换表达式为 T(v),其中将值 v 转换为类型 T

func MakeIntResource(id uint16) (*uint16) {
    return (*uint16)(unsafe.Pointer(uintptr(id)))
}

这是我们的窗口消息处理程序函数,它仅处理 WM_DESTROY 消息,以确保我们的窗口在 close 事件上正确关闭

func WndProc(hWnd w32.HWND, msg uint32, wParam, lParam uintptr) (uintptr) {
switch msg {
case w32.WM_DESTROY:
        w32.PostQuitMessage(0)
    default:
        return w32.DefWindowProc(hWnd, msg, wParam, lParam)
    }
    return 0
}

以下 WinMain 函数创建我们的窗口,并运行一个标准的应用循环

func WinMain() int {

在名为 hInstance 的局部变量中获取我们的应用程序实例句柄。在 Go 语言中,:= 运算符同时用作声明和初始化

hInstance := w32.GetModuleHandle("")

由于 w32 包仅定义 Unicode (UTF16) 兼容的 WinAPI 函数,因此我们必须使用来自 syscall 包的 StringToUTF16Ptr 函数将 Go string 类型转换为 UTF16 指针

lpszClassName := syscall.StringToUTF16Ptr("WNDclass")

在这里,我们使用 'var' 关键字声明变量

var wcex w32.WNDCLASSEX

赋值只需使用 '=' 运算符即可完成

wcex.Size            = uint32(unsafe.Sizeof(wcex))
wcex.Style         = w32.CS_HREDRAW | w32.CS_VREDRAW
wcex.WndProc       = syscall.NewCallback(WndProc)
wcex.ClsExtra        = 0
wcex.WndExtra        = 0
wcex.Instance         = hInstance
wcex.Icon         = w32.LoadIcon(hInstance, MakeIntResource(w32.IDI_APPLICATION))
wcex.Cursor       = w32.LoadCursor(0, MakeIntResource(w32.IDC_ARROW))
wcex.Background = w32.COLOR_WINDOW + 11

在 Go 语言中,nil 等同于 NULL。由于我们没有为窗口提供任何菜单,因此我们将 MenuName 字段分配为 nil

wcex.MenuName  = nil

wcex.ClassName = lpszClassName
wcex.IconSm       = w32.LoadIcon(hInstance, MakeIntResource(w32.IDI_APPLICATION))

在这里,我们使用 RegisterClassEx 函数注册我们的类,该函数来自 w32 包。我们将 wcex 变量的地址传递给其参数 -

w32.RegisterClassEx(&wcex)

然后,我们使用来自 w32 包的 CreateWindowEx 函数创建我们的窗口。我们的窗口大小将为 400x400

hWnd := w32.CreateWindowEx(
0, lpszClassName, syscall.StringToUTF16Ptr("Simple Go Window!"), 
w32.WS_OVERLAPPEDWINDOW | w32.WS_VISIBLE, 
w32.CW_USEDEFAULT, w32.CW_USEDEFAULT, 400, 400, 0, 0, hInstance, nil)

我们使用来自 w32 包的 ShowWindow 函数在屏幕上显示我们的窗口

w32.ShowWindow(hWnd, w32.SW_SHOWDEFAULT)
w32.UpdateWindow(hWnd)

以下代码将运行标准的应用循环,直到我们关闭窗口。它将尝试从我们的窗口获取消息

   var msg w32.MSG
   for {
        if w32.GetMessage(&msg, 0, 0, 0) == 0 {
            break
        }
        w32.TranslateMessage(&msg)
        w32.DispatchMessage(&msg)
   }
   return int(msg.WParam)
}

这是我们的程序入口点函数。它调用 WinMain 函数来创建并显示我们的窗口

func main() {
    WinMain()
    return
}

现在我们有了我们的源代码。我使用了 main.go 作为源文件名。

使用以下命令编译源文件

go.exe build -ldflags "-H windowsgui" main.go

' -ldflags "-H windowsgui" ' 标志将从我们的应用程序中删除黑色的控制台窗口。

现在,运行 main.exe 文件,看看你的简单 Go 窗口!

给读者的请求

如果您对 Go 语言的新项目有任何想法,这将有助于人们更轻松地学习该语言,您可以通过评论告知我。

结论

Go 是一种非常棒的编程语言。我们应该明智地使用它,以便从中获得适当的好处。我希望本技巧对初学者程序员有所帮助。

© . All rights reserved.