fyne

fyne

fyne框架:https://github.com/fyne-io/fyne

对应文档:https://developer.fyne.io/

要使用 Fyne 开发应用程序,您需要 Go 版本 1.14 或更高版本、C 编译器和系统的开发工具(也即是gcc

1. 常用函数

1.1 窗口标题title

设置窗口标题

func (App)NewWindow(title string) Window 绑定在app一个方法

package main

import (
	"fyne.io/fyne/v2/app"
)

func main() {
	//创建一个app
	a:=app.New()

	//创建一个窗口
	w:=a.NewWindow("my frist title")

    //运行
	w.ShowAndRun()
}

窗口大小可以随意调解

1.2 修改窗口默认大小Resize

修改默认窗口大小,只是修改了初始显示窗口大小,任然可以缩放大小

func (window)Resize(fyne.NewSize(w,h)) w---width h----height

package main

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
)

func main() {
	//创建一个app
	a:=app.New()

	//创建一个window
	w:=a.NewWindow("my title")

	//设置初始窗口大小
	w.Resize(fyne.NewSize(600,600))

	//运行
	w.ShowAndRun()
}

1.3 组件 微件

1.3.1 标签 label text

创建一个小装置 微件

将创建的小装置添加到窗口

w.SetContent(widget.NewLabel("title label"))

package main

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/widget"
)

func main() {
	//创建一个app
	a:=app.New()

	//创建一个window
	w := a.NewWindow("my title")

	//修改初始显示窗口大小
	w.Resize(fyne.NewSize(300,300))
	
    //widget:组件 
    //新建一个标签组件
	w.SetContent(widget.NewLabel("title label"))

	//运行
	w.ShowAndRun()
}

1.3.2 按钮button

//创建一个按钮button     第一个参数是button名字  第二个是点击就会对应执行的函数
button:=widget.NewButton("my name is button", func() {
	
})
package main

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/widget"
)

func main() {
	//创建一个app
	a:=app.New()

	//创建一个window
	w := a.NewWindow("my title")

	//改变初始窗口大小
	w.Resize(fyne.NewSize(300,300))

	//创建一个按钮button组件
	button:=widget.NewButton("my name is button", func() {
		fmt.Println("button is pressed")
	})

	//将装置添加到窗口
	w.SetContent(button)

	//运行
	w.ShowAndRun()
}

点击一次就会执行一次打印

1.3.2.1 button失效 disable
btn:=widget.NewButton("button", func() {
    fmt.Println("button is pressed")
})

//让button失效
//btn.Disable()

1.3.2.2 给button设置背景色
//按钮
btn:=widget.NewButton("visit", func() {

})

//按钮颜色
btn_color:=canvas.NewRectangle(color.NRGBA{R: 255,G: 0,B: 0,A: 255})

contain:=container.New(
    layout.NewMaxLayout(),
    //第一个是颜色
    btn_color,
    //第二个是按钮
    btn,

//添加到窗口
w.SetContent(contain)   

使用图片做背景色

btn:=widget.NewButton("Visit", func() {

})
//图片来源
img:=canvas.NewImageFromFile("C:/Users/jq/Desktop/bdyjy.jpg")
img_contain:=container.New(layout.NewMaxLayout(),img,btn)
//添加到窗口
w.SetContent(contain)   

1.3.3 复选框CheckBox

勾选上了 b就为真 没勾选上 b就为假

func main() {
	//创建一个app
	a:=app.New()

	//创建一个窗口
	w:=a.NewWindow("my name is winodows title")

	//设置初始窗口打下
	w.Resize(fyne.NewSize(300,300))

	//定义一个装置  checkbox组件
	check:=widget.NewCheck("men", func(b bool) {
		//勾选上  就为true
		if b{
			fmt.Println("我是男性")
            check.Show()//显示
		}else{
			fmt.Println("我是女性")
            check.Hide()//隐藏
		}
	})

	//将装置添加到窗口
	w.SetContent(check)

	//运行
	w.ShowAndRun()
}

check.Hide()  //可将复选框隐藏

超链接 点击即可实现跳转

//定义一个装置  hyperlink
url,_:=url.Parse("https://www.cnblogs.com/wustjq/p/16426471.html")
widgetUrl:=widget.NewHyperlink("my name is hyperlink",url)

//添加至窗口
w.SetContent(widgetUrl)

成功实现超链接跳转

1.3.5 图标 Icon

//定义一个装置  icon组件
icon:=widget.NewIcon(theme.CancelIcon())

//添加到窗口
w.SetContent(icon)

1.3.6 cards

//定义一个组件  cards
widgetCard:=widget.NewCard("title","sub title",canvas.NewCircle(color.Black))

//添加到窗口
w.SetContent(widgetCard)

1.3.7 多行文本 multiline

multilineEntry:=widget.NewMultiLineEntry()
const loren="The sunset and the solitary bird fly together, and the autumn water is the same color as the sky"
multilineEntry.SetText(loren)

显示样式

multilineEntry.Wrapping=fyne.TextWrapBreak   //不够换行显示

multilineEntry.Wrapping=fyne.TextWrapOff	//一行显示

multilineEntry.Wrapping=fyne.TextTruncate

1.3.8 滑动数据 slider

f:=20.0
data:=binding.BindFloat(&f)
//滑动数据的组件   最小数据0   最大数据100  初始默认数为20
slider1:=widget.NewSliderWithData(0.0,100.0,data)

//根据数据创建label   将实时数据显示  如果没有这个label就看不到数据
label1:=widget.NewLabelWithData(
    binding.FloatToString(data),
)

w.SetContent(container.NewVBox(slider1,label1))

1.3.9 登录提交 form

label:=widget.NewLabel("")
form:=widget.NewForm(
    widget.NewFormItem("UserName",widget.NewEntry()),
    widget.NewFormItem("PassWord",widget.NewPasswordEntry()),
)
form.OnCancel= func() {
    label.Text="Cancel"
    label.Refresh()
}
form.OnSubmit= func() {
    label.Text="Submit"
    label.Refresh()
}


w.SetContent(container.NewVBox(form,label))

1.3.10 列表list

list:=widget.NewList(
		func() int {return 5},	//最终显示个数
		func() fyne.CanvasObject {return widget.NewLabel("")},
		func(id widget.ListItemID, object fyne.CanvasObject) {object.(*widget.Label).SetText("Hello World")},	//显示的内容
	)

w.SetContent(list)

1.3.11 下拉框选择 select

label:=widget.NewLabel("")
sel:=widget.NewSelect([]string{"one","two","three","four"}, func(s string) {
    fmt.Printf("selected is %s\n",s)
    label.Text=s
    label.Refresh()
})

w.SetContent(container.NewVBox(sel,label))

1.4 画布

1.4.1 修改文本颜色 Change color

显示有颜色的字

func main() {
	//创建一个app
	a:=app.New()

	//创建一个窗口
	w:=a.NewWindow("my name is winodows title")

	//设置默认窗口打下
	w.Resize(fyne.NewSize(300,300))

	//画布里面创建文字
	canvasText:=canvas.NewText("canvas text",color.NRGBA{B: 255,G: 0,R: 0,A: 255})
    //设置文字字体大小
	canvasText.TextSize=30

	//添加到窗口
	w.SetContent(canvasText)

	//运行
	w.ShowAndRun()
}

1.4.2 图片展示 image

//画布里面创建图片
img:=canvas.NewImageFromFile("C:/Users/jq/Desktop/1.jpg")
//添加到窗口
w.SetContent(img)

1.4.3 圆 circle

//画布里面创建圆
canvasCircle:=canvas.NewCircle(color.NRGBA{B: 255,G: 0,R: 0,A: 255})
//边框颜色 边框线宽
canvasCircle.StrokeColor=color.Black
canvasCircle.StrokeWidth=3

//添加到窗口
w.SetContent(canvasCircle)

1.4.4 矩形 recttangle

//画布里面创建矩形
canvasRect:=canvas.NewRectangle(color.NRGBA{B: 255,G: 0,R: 0,A: 255})
//边框颜色 边框线宽
canvasRect.StrokeColor=color.Black
canvasRect.StrokeWidth=3

//添加到窗口
w.SetContent(canvasRect)

1.4.5 线 line

//画布里面创建线
canvasLine:=canvas.NewLine(color.NRGBA{B: 255,G: 0,R: 0,A: 255})
//边框颜色 边框线宽
canvasLine.StrokeColor=color.Black
canvasLine.StrokeWidth=3

1.4.6 颜色梯度变化gradient

//水平渐变
canvas.NewHorizontalGradient(color.White,color.Black)
//数值渐变
canvas.NewVerticalGradient(color.White,color.Black)
//以中心圆渐变
canvas.NewRadialGradient(color.White,color.Black)
	参1:起始颜色  参2 终止颜色


//一定角度渐变
canvas.NewLinearGradient(color.White,color.Black,45)
	参1:起始颜色  参2 终止颜色  参3 角度

//画布里面创建梯度
canvasgradient:=canvas.NewHorizontalGradient(color.White,color.Black)
//添加到窗口
w.SetContent(canvasgradient)

1.5 容器container

1.5.1 水平 竖直框

将多个组件装在一起显示

w.SetContent(newHBox)只能有一个参数,所以用个框装起来

水平:体现在两个组件之间位置关系

//创建一个按钮button
button:=widget.NewButton("my name is button", func() {

})

//新建一个标签
label:=widget.NewLabel("my name is label")

//水平box将两个组件装起来
newHBox:=container.NewHBox(button,label)

//显示在窗口
w.SetContent(newHBox)

1.5.2 水平 竖直隔离框

//画布中创建文本
labels1:=canvas.NewText("text1",color.Black)
labels2:=canvas.NewText("text2",color.Black)

//创建一个标签组件
w1:=widget.NewLabel("widget label")
//添加到窗口
w.SetContent(container.NewVSplit(container.NewHSplit(labels1,labels2),w1))

先是labels1labels2在水平方向隔离,然后他们整体又再竖直方向和w1进行隔离

1.5.3 水平 竖直滚动框

//red rect
redRect:=canvas.NewRectangle(color.NRGBA{R: 255,G: 0,B: 0,A: 255})
redRect.SetMinSize(fyne.NewSize(200,200))

//blue rect
blueRect:=canvas.NewRectangle(color.NRGBA{R: 0,G: 0,B: 255,A: 255})
blueRect.SetMinSize(fyne.NewSize(200,200))

c:=container.NewVBox(redRect,blueRect)

//创建scroll 滚动框
scroll:=container.NewScroll(c)

//显示在窗口
w.SetContent(scroll)

1.6 修改主题颜色

a.Settings().SetTheme(theme.LightTheme())	//设置亮色主题
a.Settings().SetTheme(theme.DarkTheme())	//设置暗色主题

//文字说明
label:=widget.NewLabel("Fyne Theme")

//亮色主题
btn1:=widget.NewButton("Light Theme", func() {
    a.Settings().SetTheme(theme.LightTheme())
})
//暗色主题
btn2:=widget.NewButton("Dark Theme", func() {
    a.Settings().SetTheme(theme.DarkTheme())
})
//退出
btn3:=widget.NewButton("Exit", func() {
    a.Quit()
})

//添加到窗口
w.SetContent(container.NewVBox(label,btn1,btn2,btn3))

1.7 设置窗口图标

1.使用fyne默认图标

//设置app 图口默认图标
w.SetIcon(theme.FyneLogo())

2.加载本地图片做图标

//指定你需要加载图片路径
r,_:=fyne.LoadResourceFromPath("./bdyjy.jpg")   //相对路径和绝对路径都可
//设置app 图标
w.SetIcon(r)

3.从网上指定图片url作为图标

//指定你需要加载图片的url
r,_:=fyne.LoadResourceFromURLString("https://picsum.photos/200")
//设置app 图标
w.SetIcon(r)

1.8 菜单栏 menu

//设置menuitem相关信息
menuItem:=&fyne.Menu{
    Label: "File",
    Items: nil,
}

//根据item创建menu
menu:=fyne.NewMainMenu(menuItem)

//在窗口显示
w.SetMainMenu(menu)

创建多个item子项

//点击每个item执行相应的回调
menuItems1:=fyne.NewMenuItem("New", func() {
    fmt.Println("New is pressed")
})
menuItems2:=fyne.NewMenuItem("Save", func() {
    fmt.Println("Save is pressed")
})
menuItems3:=fyne.NewMenuItem("Edit", func() {
    fmt.Println("Edit is pressed")
})

//根据item创建menu
newMenu:=fyne.NewMenu("File",menuItems1,menuItems2,menuItems3)

//创建主menu
menu:=fyne.NewMainMenu(newMenu)

//设置在窗口
w.SetMainMenu(menu)

创建多个并列menu

//创建多个item
newItem:=fyne.NewMenuItem("New",nil)
editItem:=fyne.NewMenuItem("Edit",nil)
saveItem:=fyne.NewMenuItem("Save",nil)

//创建menu   这个相当于是折叠起来先显示的
menu1:=fyne.NewMenu("File",newItem,editItem,saveItem)
menu2:=fyne.NewMenu("Config",newItem,editItem,saveItem)
menu3:=fyne.NewMenu("Content",newItem,editItem,saveItem)

//创建mainmenu
mainmenu:=fyne.NewMainMenu(menu1,menu2,menu3)

//设置在窗口上
w.SetMainMenu(mainmenu)

1.8.1 子菜单

//创建多个item
item1:=fyne.NewMenuItem("New",nil)
item2:=fyne.NewMenuItem("Edit",nil)
item3:=fyne.NewMenuItem("Save",nil)

item2.ChildMenu=fyne.NewMenu("",
    fyne.NewMenuItem("Add",nil),
    fyne.NewMenuItem("Sub",nil),
    fyne.NewMenuItem("Div",nil),
)
//创建menu   这个相当于是折叠起来先显示的
menu:=fyne.NewMenu("File",item1,item2,item3)

//创建mainmenu
mainmenu:=fyne.NewMainMenu(menu)

//设置在窗口上
w.SetMainMenu(mainmenu)

1.9 对话框dialog

1.9.1 打开文件

btn:=widget.NewButton("Open .txt files", func() {
    //使用对话框打开文件
    //第一个参数是函数体,第二个参数是父窗口
    file_dial:=dialog.NewFileOpen(func(r fyne.URIReadCloser, err error) {
        //读取文件
        data,_:=ioutil.ReadAll(r)

        //得到结果
        result:=fyne.NewStaticResource("name",data)

        //展示文本在标签
        entry:=widget.NewMultiLineEntry()
        entry.SetText(string(result.StaticContent))

        //显示  title就设置为文件名,
        w:=fyne.CurrentApp().NewWindow(string(result.StaticName))

        w.SetContent(container.NewVBox(entry))

        w.Show()
    },w)

    //进行过滤
    file_dial.SetFilter(storage.NewExtensionFileFilter([]string{".txt"}))
    file_dial.Show()
})
w.SetContent(container.NewVBox(btn))

1.9.2 存储文件

entry:=widget.NewMultiLineEntry()
//创建按钮用来储存文件
btn:=widget.NewButton("Save .txt file", func() {
    //第一个是个函数  第二个是父窗口
    fileDialog:=dialog.NewFileSave(func(wc fyne.URIWriteCloser, err error) {
        //从输入获取数据信息
        data:=entry.Text
        //写到文件去
        wc.Write([]byte(data))
    },w)

    //设置文件名
    fileDialog.SetFileName("anyFileName.txt")
    fileDialog.Show()
    fileDialog.Refresh()
})

//窗口显示
w.SetContent(container.NewVBox(entry,btn))

1.9.3 显示图片

btn:=widget.NewButton("Open .jpg & .png", func() {
    fileDialog:=dialog.NewFileOpen(func(r fyne.URIReadCloser, err error) {
        data,_:=ioutil.ReadAll(r)
        res:=fyne.NewStaticResource(r.URI().Name(),data)

        img:=canvas.NewImageFromResource(res)
        win:=fyne.CurrentApp().NewWindow(r.URI().Name())

        win.SetContent(img)
        win.Resize(fyne.NewSize(500,500))
        win.Show()
    },w)

    fileDialog.SetFilter(storage.NewExtensionFileFilter([]string{".jpg",".png"}))
    fileDialog.Show()
})

w.SetContent(btn)

1.10 组件位置大小约束

btn:=widget.NewButton("Button", func() {})
btn.Resize(fyne.NewSize(40,100))
btn.Move(fyne.Position{0,0})

red_Rect:=canvas.NewRectangle(color.NRGBA{R: 255,G: 0,B: 0,A: 255})
red_Rect.Resize(fyne.NewSize(40,100))
red_Rect.Move(fyne.Position{250,250})

blue_cicle:=canvas.NewCircle(color.NRGBA{0,255,0,255})
blue_cicle.Resize(fyne.NewSize(40,100))
blue_cicle.Move(fyne.Position{350,80})

//这里一定要选择NewWithoutLayout 无布局方式  不然我们设置的位置大小都无效
w.SetContent(container.NewWithoutLayout(btn,red_Rect,blue_cicle))

fmt.Println("blue_cicle:",blue_cicle.Position())   //可打印当前组件所在位置,以左上为基准

1.11 fyne不支持中文问题

方法1

借助第三方库:github.com/flopp/go-findfont

在init函数中完成初始化

package main

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/widget"
	"github.com/flopp/go-findfont"
	"os"
	"strings"
)

func init() {
	fontPaths := findfont.List()
	for _, path := range fontPaths {
		//楷体 "simkai.ttf"
		//黑体 "simhei.ttf"
		if strings.Contains(path, "simkai.ttf") {
			os.Setenv("FYNE_FONT",path)
			break
		}
	}
}

func main(){
	//创建app
	a:=app.New()

	//创建一个windows
	w:=a.NewWindow("我是窗口")

	w.Resize(fyne.NewSize(500,500))

	label:=widget.NewLabel("这是标签")
	w.SetContent(label)
	//运行
	w.ShowAndRun()
}

方法2

  • C:\Windows\Fonts下选择合适的字体复制到你的项目路径下

  • 使用init函数,设置环境变量即可使用

    func init() {
    	os.Setenv("FYNE_FONT","msyhl.ttc")
    }
    
    

1.15 小案例

案例1: 实现随机数

实现一个点击产生随机数

func main() {
	//创建一个app
	a:=app.New()
	
	//创建一个windows
	w:=a.NewWindow("my name is title")

	//修改默认大小
	w.Resize(fyne.NewSize(300,300))
    
    //添加随机数种子  避免伪随机
	rand.Seed(time.Now().UnixNano())
	//新建一个标签
	label:=widget.NewLabel("my name is label")

	//创建一个按钮button  只要点击按钮就回触发回调函数
	button:=widget.NewButton("Generate", func() {
        //产生0-99随机数
		rand1:=rand.Intn(100)
        //相当于将label标签的文本覆盖
		label.Text=fmt.Sprint(rand1)
        //实时刷新
		label.Refresh()
	})

	//水平box将两个微件装起来
	newHBox:=container.NewVBox(button,label)

	//显示在窗口
	w.SetContent(newHBox)
	//运行
	w.ShowAndRun()
}

案例2: 随机点数图片

func main() {
	//创建一个app
	a:=app.New()

	//创建一个windows
	w:=a.NewWindow("my name is title")

	//修改默认大小
	w.Resize(fyne.NewSize(300,300))

	//创建图片组件  初始显示1.png
	canvasImg:=canvas.NewImageFromFile("C:/Users/jq/Desktop/dice/1.png")
	//以原始图片样式显示    必须有
	canvasImg.FillMode=canvas.ImageFillOriginal

	//随机数种子
	rand.Seed(time.Now().UnixNano())

	//创建一个组件button
	button:=widget.NewButton("run", func() {
        //1-6
		rand1:=rand.Intn(6)+1
        //修改图片路径
		canvasImg.File=fmt.Sprintf("C:/Users/jq/Desktop/dice/%d.png",rand1)
        //刷新
		canvasImg.Refresh()
	})

	//创建竖直box容器
	vBox:=container.NewVBox(canvasImg,button)

	//在窗口显示
	w.SetContent(vBox)
	//运行
	w.ShowAndRun()
}

案例3: 随机颜色生成

func main() {
	//创建一个app
	a:=app.New()

	//创建一个windows
	w:=a.NewWindow("my name is title")

	//修改默认大小
	w.Resize(fyne.NewSize(300,300))

	//播种随机数
	rand.Seed(time.Now().UnixNano())
    
	//画图创建矩形	默认初始是黑色	
	rect:=canvas.NewRectangle(color.NRGBA{R: 0,G: 0,B: 0,A: 255})
	rect.SetMinSize(fyne.NewSize(150,150))

	//随机颜色
	btn1:=widget.NewButton("Ranndom Color", func() {
        //点击按钮 就会触发func ,将填充颜色进行修改
		rect.FillColor=color.NRGBA{R: uint8(rand.Intn(255)),B: uint8(rand.Intn(255)),G: uint8(rand.Intn(255)),A: 255}
		rect.Refresh()
	})

	//随机红色
	btnRed:=widget.NewButton("Ranndom Red", func() {
		rect.FillColor=color.NRGBA{R: uint8(rand.Intn(255)),B:0,G: 0,A: 255}
		rect.Refresh()
	})

	//随机绿
	btnGreen:=widget.NewButton("Ranndom Green", func() {
		rect.FillColor=color.NRGBA{R: 0,B:0,G: uint8(rand.Intn(255)),A: 255}
		rect.Refresh()
	})

	//随机蓝色
	btnBlue:=widget.NewButton("Ranndom Blue", func() {
		rect.FillColor=color.NRGBA{R: 0,B:uint8(rand.Intn(255)),G: 0,A: 255}
		rect.Refresh()
	})

	w.SetContent(container.NewVBox(rect,btn1,btnRed,btnBlue,btnGreen))
	//运行
	w.ShowAndRun()
}

案例4:随机密码生成器

首先如何生成密码

func main() {
	rand.Seed(time.Now().UnixNano())
	//假设密码长度为10
	length := 10
    
	//数字
	strNum:="0123456789"
    
	//小写
	strLow:="abcdefghijklmnopqrstuvwxyz"
    
	//大写
	strUp:="ABCDEFGHIJKLMNOPQRSTUVWSYZ"
    
    //最后结果
	ans:=""
    //总共循环指定密码长度次数
	for i:=0;i<length;i++{
        //随机选择数字 小写  大写   根据不同case 在随机生成出一个字母  加在ans上
		randstr:=rand.Intn(3)
		switch randstr {
		case 0:
			rand1:=rand.Intn(len(strNum))
			ans+=string(strNum[rand1])
			
		case 1:
			rand2:=rand.Intn(len(strLow))
			ans+=string(strLow[rand2])
			
		case 2:
			rand3:=rand.Intn(len(strUp))
			ans+=string(strUp[rand3])
			
		}
	}
}

最后实现:

func main() {
	//创建app
	a:=app.New()

	//创建一个windows
	w:=a.NewWindow("Rand Code")

	//修改默认大小
	w.Resize(fyne.NewSize(300,300))

	title:=canvas.NewText("Password Generator",color.Black)

	//客户输入密码长度的位置
	input:=widget.NewEntry()
	input.SetPlaceHolder("Enter Password length")

	//生成结果的位置  初始结果为空
	textAns:=canvas.NewText("",color.Black)
	textAns.TextSize=20
	//运行的按钮
	btn:=widget.NewButton("Generate", func() {
		//获取输入的数字结果,转成int类型
		length,_:=strconv.Atoi(input.Text)
		//验证码
		ans:=RandGenCode(length)
		textAns.Text=ans
		textAns.Refresh()
	})

	w.SetContent(container.NewVBox(title,input,textAns,btn))
	//运行
	w.ShowAndRun()
}

func RandGenCode(length int)(ans string){
	rand.Seed(time.Now().UnixNano())
	//数字
	strNum:="0123456789"
	//小写
	strLow:="abcdefghijklmnopqrstuvwxyz"
	//大写
	strUp:="ABCDEFGHIJKLMNOPQRSTUVWSYZ"
	for i:=0;i<length;i++{
		randstr:=rand.Intn(3)
		switch randstr {
		case 0:
			rand1:=rand.Intn(len(strNum))
			ans+=string(strNum[rand1])

		case 1:
			rand2:=rand.Intn(len(strLow))
			ans+=string(strLow[rand2])

		case 2:
			rand3:=rand.Intn(len(strUp))
			ans+=string(strUp[rand3])

		}
	}
	return ans
}

posted @   wustjq  阅读(2783)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示