桑格芝士网

百科知识分享平台,汇聚全球百科全书与学习资源

用GO+webview做个桌面程序

前两天我讲了bun+webview,今天我讲一下GO+webview。

GO语言有好多第三方的webview包,我个人感觉好用的是
github.com/webview/webview_go

安装包:

go get github.com/webview/webview_go

我下面的例子包含了web框架和winAPI

// main.go
package main

import (
	"io"
	"os"
	"unsafe"

	"github.com/labstack/echo/v4"
	"github.com/labstack/gommon/log"
	webview "github.com/webview/webview_go"
)

const (
	SW_MAXIMIZE = 3
	SW_MINIMIZE = 6
	SW_RESTORE  = 9
)

var (
	w webview.WebView
	h unsafe.Pointer
)

var (
	width  = 1280
	height = 720
	scale  = 1.0
)

func main() {

	//Message_Box("标题", "内容", 64)

	go func() {
		e := echo.New()
		e.Logger.SetLevel(log.OFF)
		e.Logger.SetOutput(io.Discard)
		e.Static("/", "app")
		e.Start("127.0.0.1:60088")
	}()

	args := os.Args

	if len(args) > 1 {
		if args[1] == "--debug" {
			w = webview.New(true)
		} else {
			os.Exit(0)
		}
	} else {
		w = webview.New(false)
		w.Init("document.addEventListener('keydown', function (event) {if ( (event.ctrlKey && event.key === 'r') || (event.ctrlKey && event.key === 'R') || event.key === 'F5') {event.preventDefault();}});")
		w.Init("document.addEventListener('contextmenu', function(event) {event.preventDefault();});")
	}

	defer w.Destroy()
	h = w.Window()
	w.SetTitle("MATAVIEW")
	w.SetSize(width, height, webview.HintNone)
	w.Bind("mata_win_minimize", win_minimize)
	w.Bind("mata_win_maximize", win_maximize)
	w.Bind("mata_win_restore", win_restore)
	w.Bind("mata_win_close", win_close)
	w.Bind("mata_win_center", win_center)
	w.Bind("mata_win_title", win_title)
	w.Init("window.mata={}")
	w.Init("window.mata.win={}")
	w.Init("window.mata.win.close=mata_win_close")
	w.Init("window.mata.win.minimize=mata_win_minimize")
	w.Init("window.mata.win.maximize=mata_win_maximize")
	w.Init("window.mata.win.restore=mata_win_restore")
	w.Init("window.mata.win.center=mata_win_center")
	w.Init("window.mata.win.title=mata_win_title")
	w.Navigate("http://127.0.0.1:60088/")

	var dpi, _ = Get_Dpi_For_System()
	scale = float64(dpi) / 96

	win_center()

	w.Run()

}

func win_size(ww int, hh int) {

}

func win_title(title string) {
	w.SetTitle(title)
}

func win_minimize() {
	Show_Window(h, SW_MINIMIZE)
}

func win_maximize() {
	Show_Window(h, SW_MAXIMIZE)
}

func win_restore() {
	Show_Window(h, SW_RESTORE)
}

func win_close() {
	w.Terminate()
}

func win_center() {
	screenWidth, _ := Get_System_Metrics(0)
	screenHeight, _ := Get_System_Metrics(1)
	realwidth := float64(width) * scale
	realheight := float64(height) * scale
	x := (screenWidth - int(realwidth)) / 2
	y := (screenHeight - int(realheight)) / 2
	Set_Window_Pos(h, 0, x, y, int(realwidth), int(realheight), 0)
}
// winapi.go
package main

import (
	"syscall"
	"unsafe"

	"golang.org/x/sys/windows"
)

var (
	user32           = syscall.NewLazyDLL("user32.dll")
	kernel32         = syscall.NewLazyDLL("kernel32.dll")
	FindWindow       = user32.NewProc("FindWindowW")
	ShowWindow       = user32.NewProc("ShowWindow")
	GetWindowRect    = user32.NewProc("GetWindowRect")
	GetSystemMetrics = user32.NewProc("GetSystemMetrics")
	SetWindowPos     = user32.NewProc("SetWindowPos")
	GetDpiForSystem  = user32.NewProc("GetDpiForSystem")
	GetDpiForWindow  = user32.NewProc("GetDpiForWindow")
	SetWindowLongW   = user32.NewProc("SetWindowLongW")
)

const (
	GWL_STYLE      = -16
	WS_MAXIMIZEBOX = 0x00010000
)

func Set_Window_LongW(hwnd unsafe.Pointer, nIndex int, dwNewLong float64) (uintptr, uintptr, error) {
	ret, ret2, err := SetWindowLongW.Call(uintptr(hwnd), uintptr(nIndex), uintptr(dwNewLong))
	return ret, ret2, err
}

func Show_Window(hwnd unsafe.Pointer, show int) error {

	ret, _, err := ShowWindow.Call(uintptr(hwnd), uintptr(show))
	if ret == 0 {
		return err
	}
	return nil
}

func Set_Window_Pos(hwnd unsafe.Pointer, hwndInsertAfter uintptr, x, y, cx, cy int, flags uint) error {
	ret, _, err := SetWindowPos.Call(
		uintptr(hwnd),
		hwndInsertAfter,
		uintptr(x),
		uintptr(y),
		uintptr(cx),
		uintptr(cy),
		uintptr(flags),
	)
	if ret == 0 {
		return err
	}
	return nil
}

func Ge_Window_Rect(hwnd unsafe.Pointer) (rect struct{ Left, Top, Right, Bottom int }, err error) {
	ret, _, err := GetWindowRect.Call(uintptr(hwnd), uintptr(unsafe.Pointer(&rect)))
	if ret == 0 {
		return rect, err
	}
	return rect, nil
}

func Get_System_Metrics(nIndex int) (int, error) {
	ret, _, err := GetSystemMetrics.Call(uintptr(nIndex))
	if ret == 0 {
		return 0, err
	}
	return int(ret), nil
}

func Get_Dpi_For_System() (uint, error) {
	ret, _, err := GetDpiForSystem.Call()
	if ret == 0 {
		return 0, err
	}
	return uint(ret), nil
}

func Get_Dpi_For_Window(hwnd unsafe.Pointer) (uint, error) {
	ret, _, err := GetDpiForWindow.Call(uintptr(hwnd))
	if ret == 0 {
		return 0, err
	}
	return uint(ret), nil
}

func Message_Box(title string, message string, utype uint32) {
	hwnd := windows.HWND(0)
	ptitle, _ := syscall.UTF16PtrFromString(title)
	pmessage, _ := syscall.UTF16PtrFromString(message)
	windows.MessageBox(hwnd, pmessage, ptitle, utype)
}

如果你是我的老粉丝,你可以看出来这个就是我之前发布的MATAVIEW


下面是 精简版 MATAVIEW LITE源码

// main.go
package main

import (
	"strconv"
	"time"

	"github.com/labstack/echo"
	webview "github.com/webview/webview_go"
)

var w webview.WebView

func main() {

	go func() {
		e := echo.New()
		e.Debug = false
		e.HideBanner = true
		e.DisableHTTP2 = true
		e.Static("/", "./")
		e.Start("127.0.0.1:60088")
	}()

	now := time.Now()
	timestamp := strconv.FormatInt(now.UnixNano(), 10)

	w = webview.New(false)
	defer w.Destroy()
	w.Init("document.addEventListener('keydown', function (event) {if ( (event.ctrlKey && event.key === 'r') || (event.ctrlKey && event.key === 'R') || event.key === 'F5') {event.preventDefault();}});")
	w.Init("document.addEventListener('contextmenu', function(event) {event.preventDefault();});")
	w.Bind("win_size", win_size)
	w.Bind("win_close", win_close)
	w.Bind("win_title", win_title)
	w.Navigate("http://127.0.0.1:60088/?timestamp=" + timestamp)
	w.Run()

}

func win_size(width int, height int, htype int) {
	if htype == 0 {
		w.SetSize(width, height, webview.HintNone)
	} else {
		w.SetSize(width, height, webview.HintFixed)
	}

}

func win_close() {
	w.Terminate()
}

func win_title(title string) {
	w.SetTitle(title)
}
// index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button onclick="win_size(800,480,1)">修改大小</button>
    <button onclick="win_title('新标题')">修改标题</button>
    <button onclick="win_close()">关闭窗口</button>
    <pre><code>
win_size(长,宽,锁定)
win_title(标题)
win_close()
    </code></pre>
    <div>MATAVIEW LITE是MATAVIEW的精简版,只保留三个函数,程序是静态编译,只包含HTTP静态服务器和WEBVIEW2(还是要安装webview2 runtime,WIN10 2004版本及其以上自带),减少杀软误杀的几率。</div>
    <br>
    <div>下载地址:https://share.weiyun.com/uhgAsAKI</div>
    <script>
        win_title("MATAVIEW LITE")
        win_size(480, 800, 1)
    </script>
</body>

</html>

LITE版取消了WINAPI接口,只保留了webview_go的接口和echo框架,其实如果你不需要echo也可以删除。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言