package main import ( "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/canvas" "fyne.io/fyne/container" "fyne.io/fyne/layout" "fyne.io/fyne/theme" ) func main() { myApp := app.New() myWindow := myApp.NewWindow("Custom Window") // 创建一个容器 container := fyne.NewContainerWithLayout(layout.NewGridLayout(2)) // 创建一个文本标签 label := canvas.NewText("Hello Fyne!", theme.TextColor()) // 创建一个按钮 button := canvas.NewText("Click Me", theme.TextColor()) button.Alignment = fyne.TextAlignCenter button.TextSize = 20 // 将UI元素添加到容器中 container.Add(label) container.Add(button) // 将容器添加到窗口中 myWindow.SetContent(container) myWindow.ShowAndRun() }这个里面的canvaes如何来定位
时间: 2024-04-28 10:21:50 浏览: 206
在这段代码中,`canvas` 是 `fyne` 包中的一个元素,用于绘制 2D 图形。您可以使用 `canvas` 来创建各种图形和视觉效果,例如文本、矩形、圆形等等。
在这个示例中,我们使用 `canvas` 创建了两个文本标签:一个用于显示 "Hello Fyne!",另一个用于显示 "Click Me"。然后,我们将这两个 `canvas` 元素添加到一个 `fyne` 容器中,并使用网格布局将它们排列为两列。
在此示例中,我们没有显式设置 `canvas` 元素的位置。相反,我们使用了 `fyne` 的布局系统来处理元素的定位和排列。具体来说,我们使用了 `layout.NewGridLayout(2)` 创建了一个网格布局,该布局将两个列中的元素放置在容器中。默认情况下,`fyne` 的布局系统会自动管理元素的位置和大小,以确保它们适合容器的大小和形状。您可以在 `fyne` 的文档中了解更多关于布局系统的信息。
如果您需要更精确地控制 `canvas` 元素的位置,可以使用 `fyne` 的绝对定位布局或其他自定义布局来实现。您可以在 `fyne` 的文档中查找更多关于布局系统的信息和示例。
相关问题
package main import ( shell "mod02/shell" "log" "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" "fyne.io/fyne/v2/widget" ) func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) //本地命令执行 // shell.Shellage("ping www.baidu.com") //传入参数(用户名|密码|host|port|命令) // shell.Modssh("root","Lc753951..","101.34.245.75:22","ping baidu.com") //交互式ssh // shell.Interssh("root","Lc753951..","101.34.245.75","22") myApp := app.New() myWindow := myApp.NewWindow("My Window") myButton := widget.NewButton("Click me!", func() { dialog := widget.NewModalPopUp(widget.NewLabel("Button clicked!"), myWindow.Canvas()) dialog.Show() }) myBox := fyne.NewContainerWithLayout(fyne.NewVBoxLayout(), myButton) myWindow.SetContent(myBox) myWindow.Resize(fyne.NewSize(300, 200)) myWindow.ShowAndRun() } 执行报错package command-line-arguments imports fyne.io/fyne/v2/app imports fyne.io/fyne/v2/internal/driver/glfw imports fyne.io/fyne/v2/internal/driver/common imports fyne.io/fyne/v2/internal/painter/gl imports github.com/go-gl/gl/v3.2-core/gl: build constraints exclude all Go files in D:\ceshi\mod02\vendor\github.com\go-gl\gl\v3.2-core\gl
根据你提供的代码和错误信息,看起来是因为 `fyne.io/fyne/v2` 这个包依赖了 `github.com/go-gl/gl/v3.2-core/gl` 包,但是无法找到该包的 Go 文件,导致构建错误。
尝试执行以下步骤来解决这个问题:
1. 确保你的代码中使用的 `fyne.io/fyne/v2` 包与你所使用的 `github.com/go-gl/gl/v3.2-core/gl` 包兼容。你可以查看它们的文档或版本兼容性说明来确认它们是否能够一起使用。
2. 运行 `go mod tidy` 命令来清理和更新模块依赖关系。这个命令会自动调整你的模块文件(go.mod)以匹配你代码中使用的依赖项版本。
3. 如果问题仍然存在,可以尝试手动安装 `github.com/go-gl/gl/v3.2-core/gl` 包。打开终端并执行以下命令:
```shell
go get -u github.com/go-gl/gl/v3.2-core/gl
```
这将下载并安装该包及其依赖项。
4. 如果上述步骤都无效,可能需要检查你的环境配置和依赖项安装是否正确。确保你的 Go 版本和相关依赖项都是最新的,并且正确设置了相关环境变量。
如果问题仍然存在,请提供更多的上下文和错误信息,以便我可以更好地帮助你解决问题。
main.go 的代码跟新为: package main import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/theme" "main.go/ui" // 导入Model包 "main.go/dataModel/UserModel" // 导入UserInfo包 ) func main() { myApp := app.New() myWindow := myApp.NewWindow("商品管理系统") myWindow.Resize(fyne.NewSize(1000, 700)) // 创建底部状态栏 statusBar := ui.NewStatusBar() // 创建用户信息结构 currentUser := &UserModel.UserInfo{ LoginName: "", LoginType: 0, ShopCount: 0, } // 创建商品列表 productList, updatePage, tasksAll, totalPages, currentPage := ui.NewProductList(statusBar) // 创建通知列表 notificationListView := ui.NewNotificationList() // 创建用户列表 userListView := ui.NewUserList() // 创建选项卡容器 tabs := container.NewAppTabs( container.NewTabItemWithIcon("商品列表", theme.ListIcon(), productList), container.NewTabItemWithIcon("系统通知", theme.MailSendIcon(), notificationListView), ) // 创建左侧面板 // 创建左侧面板(先声明变量) var leftPanel *ui.LeftPanel // 创建左侧面板(使用闭包捕获上下文) leftPanel = ui.NewLeftPanel( currentUser, statusBar, func() { // 操作1的处理 leftPanel.HandleBtn1(currentUser, statusBar, tabs, userListView) }, func() { // 操作2的处理 leftPanel.HandleBtn2(currentUser, statusBar, tasksAll, updatePage, totalPages, currentPage) }, func() { // 操作3的处理 leftPanel.HandleBtn3(currentUser, statusBar, tasksAll, updatePage, totalPages, currentPage) }, ) // 创建右侧布局 rightPanel := container.NewBorder( nil, nil, nil, nil, tabs, ) // 创建主布局 mainSplit := container.NewHSplit(leftPanel.Container, rightPanel) mainSplit.SetOffset(0.3) content := container.NewBorder( nil, statusBar, nil, nil, mainSplit, ) myWindow.SetContent(content) myWindow.ShowAndRun() } status_bar.go,notification_list.go,user_list.go的代码保持不变,
<think>我们当前的任务是更新 `main.go` 文件,同时保持其他文件(`status_bar.go`, `notification_list.go`, `user_list.go`)不变。根据提供的 `main.go` 更新代码,我们需要确保代码的完整性和正确性。
在提供的 `main.go` 更新代码中,我们注意到以下几点:
1. 创建了状态栏:`statusBar := ui.NewStatusBar()`
2. 创建了当前用户对象:`currentUser`
3. 创建了商品列表:`productList, updatePage, tasksAll, totalPages, currentPage := ui.NewProductList(statusBar)`
4. 创建了通知列表:`notificationListView := ui.NewNotificationList()`
5. 创建了用户列表:`userListView := ui.NewUserList()`
6. 创建了选项卡容器(Tabs),初始包含两个标签页:商品列表和系统通知。
7. 创建左侧面板(`leftPanel`)时,使用了闭包来捕获上下文,并传递了三个操作的处理函数(操作1、操作2、操作3)。
8. 设置了主界面的布局:左侧面板和右侧面板(包含选项卡)通过水平分割容器(`HSplit`)组合,底部是状态栏。
但是,在提供的代码中,我们注意到一个潜在的问题:在创建左侧面板时,我们传递了三个操作的处理函数,这些处理函数中调用了`leftPanel`的方法(如`HandleBtn1`等)。然而,在创建`leftPanel`时,我们使用了`leftPanel`变量本身,而这个变量在声明后立即被赋值(在闭包中使用了`leftPanel`)。这可能会引起循环引用或初始化顺序的问题?实际上,在Go中,闭包可以捕获外部变量,即使该变量尚未完全初始化(在赋值之前)。但是,在闭包执行时,`leftPanel`必须已经被赋值。这里我们是在创建`leftPanel`之后才调用这些处理函数的,所以当处理函数被调用时(即按钮被点击时),`leftPanel`已经被初始化,因此没有问题。
另外,我们注意到在创建左侧面板时,传递了三个回调函数,分别对应三个按钮的操作。在这些回调函数中,我们调用了`leftPanel`的方法,并传递了必要的参数。这些参数包括:当前用户、状态栏、选项卡容器、用户列表视图、商品数据等。
现在,我们需要确保`ui`包中已经定义了`LeftPanel`结构体及其方法(`HandleBtn1`, `HandleBtn2`, `HandleBtn3`)以及`NewLeftPanel`函数。同时,其他组件的创建函数(如`NewStatusBar`, `NewProductList`, `NewNotificationList`, `NewUserList`)也需要在`ui`包中实现。
由于我们保持`status_bar.go`, `notification_list.go`, `user_list.go`不变,因此这些组件的实现是已知的。我们只需要关注`left_panel.go`的实现,确保它支持上述使用方式。
下面,我们根据`main.go`的调用方式,来更新`left_panel.go`的代码,使其满足要求:
在`left_panel.go`中,我们需要:
1. 定义`LeftPanel`结构体,包含一个`fyne.Container`(用于放置左侧面板的UI元素)。
2. 实现`NewLeftPanel`函数,该函数接收当前用户对象、状态栏、以及三个操作的回调函数,并返回一个`LeftPanel`实例。
3. 在`LeftPanel`结构体上实现`HandleBtn1`, `HandleBtn2`, `HandleBtn3`方法,这些方法将执行具体的操作(如添加用户列表选项卡、加载初始数据、添加50条商品等)。
但是,请注意:在之前的对话中,我们已经编写过`left_panel.go`的部分代码。现在我们需要调整它以匹配当前`main.go`的调用。
由于我们没有提供`left_panel.go`的当前代码,我将根据`main.go`的调用方式重新编写一个`left_panel.go`,同时尽量复用之前的设计。
以下是更新后的`left_panel.go`代码:
```go
package ui
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
"main.go/dataModel/UserModel"
)
// LeftPanel 结构体定义左侧面板
type LeftPanel struct {
Container *fyne.Container // 面板的容器
// 回调函数
onBtn1 func()
onBtn2 func()
onBtn3 func()
}
// NewLeftPanel 创建左侧面板
func NewLeftPanel(
currentUser *UserModel.UserInfo,
statusBar *widget.Label,
onBtn1 func(),
onBtn2 func(),
onBtn3 func(),
) *LeftPanel {
// 登录表单元素
usernameEntry := widget.NewEntry()
passwordEntry := widget.NewPasswordEntry()
loginBtn := widget.NewButton("登录", func() {
// 登录逻辑
if usernameEntry.Text == "" || passwordEntry.Text == "" {
statusBar.SetText("用户名或密码不能为空")
return
}
// 模拟登录成功
currentUser.LoginName = usernameEntry.Text
currentUser.LoginType = 1 // 假设1为普通用户
currentUser.ShopCount = 0
statusBar.SetText("登录成功: " + currentUser.LoginName)
})
// 用户信息显示
userInfoLabel := widget.NewLabel("未登录")
logoutBtn := widget.NewButton("注销", func() {
currentUser.LoginName = ""
currentUser.LoginType = 0
currentUser.ShopCount = 0
userInfoLabel.SetText("未登录")
statusBar.SetText("已注销")
})
logoutBtn.Hide()
// 操作按钮(初始隐藏,登录后显示)
btn1 := widget.NewButton("操作1:添加用户列表选项卡", nil)
btn2 := widget.NewButton("操作2:加载初始数据", nil)
btn3 := widget.NewButton("操作3:添加50条商品", nil)
btn1.Hide()
btn2.Hide()
btn3.Hide()
// 更新用户信息显示
updateUserInfo := func() {
if currentUser.LoginName != "" {
userInfoLabel.SetText("欢迎: " + currentUser.LoginName)
btn1.Show()
btn2.Show()
btn3.Show()
logoutBtn.Show()
} else {
userInfoLabel.SetText("未登录")
btn1.Hide()
btn2.Hide()
btn3.Hide()
logoutBtn.Hide()
}
}
// 登录按钮点击后更新
loginBtn.OnTapped = func() {
loginBtn.OnTapped() // 调用上面的登录逻辑
updateUserInfo()
}
// 注销按钮点击后更新
logoutBtn.OnTapped = func() {
logoutBtn.OnTapped() // 调用上面的注销逻辑
updateUserInfo()
}
// 绑定操作按钮
btn1.OnTapped = func() {
onBtn1()
}
btn2.OnTapped = func() {
onBtn2()
}
btn3.OnTapped = func() {
onBtn3()
}
// 登录表单容器
loginForm := container.NewVBox(
widget.NewLabel("用户名:"),
usernameEntry,
widget.NewLabel("密码:"),
passwordEntry,
loginBtn,
)
// 用户信息容器
userInfoContainer := container.NewVBox(
userInfoLabel,
logoutBtn,
)
// 操作按钮容器
buttonsContainer := container.NewVBox(
btn1,
btn2,
btn3,
)
// 左侧面板整体布局
leftContainer := container.NewVBox(
loginForm,
userInfoContainer,
buttonsContainer,
)
return &LeftPanel{
Container: leftContainer,
onBtn1: onBtn1,
onBtn2: onBtn2,
onBtn3: onBtn3,
}
}
// HandleBtn1 是操作1的具体实现,由外部传入
func (lp *LeftPanel) HandleBtn1(
currentUser *UserModel.UserInfo,
statusBar *widget.Label,
tabs *container.AppTabs,
userListView *container.Split,
) {
// 检查登录状态
if currentUser.LoginName == "" {
statusBar.SetText("请先登录")
return
}
// 添加用户列表选项卡
tabs.Append(container.NewTabItemWithIcon("用户列表", theme.AccountIcon(), userListView))
statusBar.SetText("已添加用户列表选项卡")
}
// HandleBtn2 是操作2的具体实现,由外部传入
func (lp *LeftPanel) HandleBtn2(
currentUser *UserModel.UserInfo,
statusBar *widget.Label,
tasksAll *[]SkuModel.DataItem,
updatePage func(int),
totalPages *int,
currentPage *int,
) {
// 检查登录状态
if currentUser.LoginName == "" {
statusBar.SetText("请先登录")
return
}
// 生成100条初始商品数据
initialTasks := generateInitialTasks(100)
*tasksAll = initialTasks
// 计算总页数
*totalPages = len(*tasksAll) / app_conf.PageSize
if len(*tasksAll)%app_conf.PageSize != 0 {
*totalPages++
}
// 更新到第一页
updatePage(0)
statusBar.SetText("已加载初始数据,共100条")
}
// HandleBtn3 是操作3的具体实现,由外部传入
func (lp *LeftPanel) HandleBtn3(
currentUser *UserModel.UserInfo,
statusBar *widget.Label,
tasksAll *[]SkuModel.DataItem,
updatePage func(int),
totalPages *int,
currentPage *int,
) {
// 检查登录状态
if currentUser.LoginName == "" {
statusBar.SetText("请先登录")
return
}
// 生成50条新商品数据
newTasks := generateNewTasks(50)
*tasksAll = append(*tasksAll, newTasks...)
// 重新计算总页数
*totalPages = len(*tasksAll) / app_conf.PageSize
if len(*tasksAll)%app_conf.PageSize != 0 {
*totalPages++
}
// 跳转到最后一页(新添加的数据所在页)
updatePage(*totalPages - 1)
statusBar.SetText("已添加50条新商品")
}
// 生成初始商品数据(模拟)
func generateInitialTasks(count int) []SkuModel.DataItem {
// 实现略,返回count条商品数据
}
// 生成新商品数据(模拟)
func generateNewTasks(count int) []SkuModel.DataItem {
// 实现略,返回count条商品数据
}
```
注意:上述代码中,我们假设了`SkuModel.DataItem`和`app_conf.PageSize`的存在。同时,`generateInitialTasks`和`generateNewTasks`函数需要根据实际需求实现。
另外,在`HandleBtn1`方法中,我们添加了一个用户列表选项卡。这里我们假设`userListView`是一个`*container.Split`类型,但实际上在`main.go`中,`userListView`是由`ui.NewUserList()`创建的,我们需要查看`user_list.go`中`NewUserList`的返回值类型。假设`NewUserList`返回一个`fyne.CanvasObject`(或更具体的类型),那么我们需要调整`HandleBtn1`的参数类型。
由于在`main.go`中,`userListView`是通过`ui.NewUserList()`创建的,而`NewUserList`的返回值类型在`user_list.go`中定义。根据之前的不变,我们假设`user_list.go`中:
```go
func NewUserList() *container.Split {
// 创建用户列表视图,返回一个Split容器(或其它容器)
}
```
因此,在`HandleBtn1`中,我们使用`*container.Split`是匹配的。
但是,在`main.go`中,我们传递给`HandleBtn1`的是`userListView`,即`ui.NewUserList()`的返回值,其类型为`*container.Split`,所以没有问题。
最后,我们还需要注意:在`left_panel.go`中,我们使用了`app_conf`包,因此需要导入:
```go
import "main.go/config/app_conf"
```
同时,需要确保`app_conf`包中定义了`PageSize`常量。
由于我们修改了`left_panel.go`,现在整个项目应该可以运行。但是,我们还需要确保其他组件的实现(如`NewUserList`, `NewNotificationList`)与之前一致。
如果运行过程中遇到问题,请检查各个组件的导入路径和类型匹配。
现在,我们提供了完整的`main.go`和`left_panel.go`,其他文件保持不变,项目应该可以正常工作。
§§相关问题§§:
1. 如何优化Fyne应用的性能,特别是在处理大量数据时?
2. 如何实现Fyne应用的多语言支持?
3. 在Fyne中,如何自定义主题(如深色模式)?
4. 如何将Fyne应用打包为不同平台(Windows、macOS、Linux)的可执行文件?</think>我注意到您更新了 `main.go` 文件,这是一个更完善的实现,整合了多个UI组件。让我们分析这个实现并确保所有组件协同工作:
### 更新后的 main.go 分析
```go
package main
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/theme"
"main.go/ui"
"main.go/dataModel/UserModel"
)
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("商品管理系统")
myWindow.Resize(fyne.NewSize(1000, 700))
// 创建底部状态栏
statusBar := ui.NewStatusBar()
// 创建用户信息结构
currentUser := &UserModel.UserInfo{
LoginName: "",
LoginType: 0,
ShopCount: 0,
}
// 创建商品列表
productList, updatePage, tasksAll, totalPages, currentPage := ui.NewProductList(statusBar)
// 创建通知列表
notificationListView := ui.NewNotificationList()
// 创建用户列表
userListView := ui.NewUserList()
// 创建选项卡容器
tabs := container.NewAppTabs(
container.NewTabItemWithIcon("商品列表", theme.ListIcon(), productList),
container.NewTabItemWithIcon("系统通知", theme.MailSendIcon(), notificationListView),
)
// 创建左侧面板(使用闭包捕获上下文)
var leftPanel *ui.LeftPanel
leftPanel = ui.NewLeftPanel(
currentUser,
statusBar,
func() { // 操作1的处理
leftPanel.HandleBtn1(currentUser, statusBar, tabs, userListView)
},
func() { // 操作2的处理
leftPanel.HandleBtn2(currentUser, statusBar, tasksAll, updatePage, totalPages, currentPage)
},
func() { // 操作3的处理
leftPanel.HandleBtn3(currentUser, statusBar, tasksAll, updatePage, totalPages, currentPage)
},
)
// 创建右侧布局
rightPanel := container.NewBorder(
nil,
nil,
nil,
nil,
tabs,
)
// 创建主布局
mainSplit := container.NewHSplit(leftPanel.Container, rightPanel)
mainSplit.SetOffset(0.3) // 左侧面板占30%宽度
content := container.NewBorder(
nil,
statusBar,
nil,
nil,
mainSplit,
)
myWindow.SetContent(content)
myWindow.ShowAndRun()
}
```
### 关键改进点
1. **组件化设计**:
- 状态栏:`ui.NewStatusBar()`
- 商品列表:`ui.NewProductList()`
- 通知列表:`ui.NewNotificationList()`
- 用户列表:`ui.NewUserList()`
- 左侧面板:`ui.NewLeftPanel()`
2. **闭包处理回调**:
```go
var leftPanel *ui.LeftPanel
leftPanel = ui.NewLeftPanel(
currentUser,
statusBar,
func() { // 操作1
leftPanel.HandleBtn1(...)
},
// ...
)
```
使用闭包捕获`leftPanel`实例,解决初始化顺序问题
3. **选项卡管理**:
```go
tabs := container.NewAppTabs(
container.NewTabItemWithIcon("商品列表", theme.ListIcon(), productList),
container.NewTabItemWithIcon("系统通知", theme.MailSendIcon(), notificationListView),
)
```
使用带图标的选项卡,提升用户体验
4. **响应式布局**:
```go
mainSplit := container.NewHSplit(leftPanel.Container, rightPanel)
mainSplit.SetOffset(0.3) // 左侧面板占30%宽度
```
使用水平分割容器,允许用户调整左右面板比例
### 需要补充的 left_panel.go 实现
```go
package ui
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
"main.go/config/app_conf"
"main.go/dataModel/SkuModel"
"main.go/dataModel/UserModel"
)
// LeftPanel 结构体定义左侧面板
type LeftPanel struct {
Container *fyne.Container // 面板的容器
}
// NewLeftPanel 创建左侧面板
func NewLeftPanel(
currentUser *UserModel.UserInfo,
statusBar *widget.Label,
onBtn1 func(),
onBtn2 func(),
onBtn3 func(),
) *LeftPanel {
// 登录表单元素
usernameEntry := widget.NewEntry()
passwordEntry := widget.NewPasswordEntry()
loginBtn := widget.NewButton("登录", func() {
// 简单的登录验证
if usernameEntry.Text == "" || passwordEntry.Text == "" {
statusBar.SetText("用户名或密码不能为空")
return
}
// 模拟登录成功
currentUser.LoginName = usernameEntry.Text
currentUser.LoginType = 1 // 假设1为普通用户
currentUser.ShopCount = 0
statusBar.SetText("登录成功: " + currentUser.LoginName)
})
// 用户信息显示
userInfoLabel := widget.NewLabel("未登录")
logoutBtn := widget.NewButton("注销", func() {
currentUser.LoginName = ""
currentUser.LoginType = 0
currentUser.ShopCount = 0
userInfoLabel.SetText("未登录")
statusBar.SetText("已注销")
})
logoutBtn.Hide()
// 操作按钮(初始隐藏,登录后显示)
btn1 := widget.NewButton("操作1:添加用户列表选项卡", onBtn1)
btn2 := widget.NewButton("操作2:加载初始数据", onBtn2)
btn3 := widget.NewButton("操作3:添加50条商品", onBtn3)
btn1.Hide()
btn2.Hide()
btn3.Hide()
// 更新用户信息显示
updateUserInfo := func() {
if currentUser.LoginName != "" {
userInfoLabel.SetText("欢迎: " + currentUser.LoginName)
btn1.Show()
btn2.Show()
btn3.Show()
logoutBtn.Show()
} else {
userInfoLabel.SetText("未登录")
btn1.Hide()
btn2.Hide()
btn3.Hide()
logoutBtn.Hide()
}
}
// 登录按钮点击后更新
loginBtn.OnTapped = func() {
loginBtn.OnTapped() // 调用上面的登录逻辑
updateUserInfo()
}
// 注销按钮点击后更新
logoutBtn.OnTapped = func() {
logoutBtn.OnTapped() // 调用上面的注销逻辑
updateUserInfo()
}
// 登录表单容器
loginForm := container.NewVBox(
widget.NewLabel("用户名:"),
usernameEntry,
widget.NewLabel("密码:"),
passwordEntry,
loginBtn,
)
// 用户信息容器
userInfoContainer := container.NewVBox(
userInfoLabel,
logoutBtn,
)
// 操作按钮容器
buttonsContainer := container.NewVBox(
btn1,
btn2,
btn3,
)
// 左侧面板整体布局
leftContainer := container.NewVBox(
loginForm,
userInfoContainer,
buttonsContainer,
)
return &LeftPanel{
Container: leftContainer,
}
}
// HandleBtn1 操作1:添加用户列表选项卡
func (lp *LeftPanel) HandleBtn1(
currentUser *UserModel.UserInfo,
statusBar *widget.Label,
tabs *container.AppTabs,
userListView fyne.CanvasObject,
) {
// 检查登录状态
if currentUser.LoginName == "" {
statusBar.SetText("请先登录")
return
}
// 添加用户列表选项卡
tabs.Append(container.NewTabItemWithIcon("用户列表", theme.AccountIcon(), userListView))
statusBar.SetText("已添加用户列表选项卡")
}
// HandleBtn2 操作2:加载初始数据
func (lp *LeftPanel) HandleBtn2(
currentUser *UserModel.UserInfo,
statusBar *widget.Label,
tasksAll *[]SkuModel.DataItem,
updatePage func(int),
totalPages *int,
currentPage *int,
) {
// 检查登录状态
if currentUser.LoginName == "" {
statusBar.SetText("请先登录")
return
}
// 生成100条初始商品数据
initialTasks := generateInitialTasks(100)
*tasksAll = initialTasks
// 计算总页数
*totalPages = len(*tasksAll) / app_conf.PageSize
if len(*tasksAll)%app_conf.PageSize != 0 {
*totalPages++
}
// 更新到第一页
updatePage(0)
statusBar.SetText("已加载初始数据,共100条")
}
// HandleBtn3 操作3:添加新商品
func (lp *LeftPanel) HandleBtn3(
currentUser *UserModel.UserInfo,
statusBar *widget.Label,
tasksAll *[]SkuModel.DataItem,
updatePage func(int),
totalPages *int,
currentPage *int,
) {
// 检查登录状态
if currentUser.LoginName == "" {
statusBar.SetText("请先登录")
return
}
// 生成50条新商品数据
newTasks := generateNewTasks(50)
*tasksAll = append(*tasksAll, newTasks...)
// 重新计算总页数
*totalPages = len(*tasksAll) / app_conf.PageSize
if len(*tasksAll)%app_conf.PageSize != 0 {
*totalPages++
}
// 跳转到最后一页(新添加的数据所在页)
updatePage(*totalPages - 1)
statusBar.SetText("已添加50条新商品")
}
// 生成初始商品数据(模拟)
func generateInitialTasks(count int) []SkuModel.DataItem {
tasks := make([]SkuModel.DataItem, count)
for i := 0; i < count; i++ {
tasks[i] = SkuModel.DataItem{
ProductID: fmt.Sprintf("P%04d", i+1),
Name: fmt.Sprintf("商品 %d", i+1),
Category: "类别" + strconv.Itoa(i%5+1),
PriceLower: 10 + i,
PriceHigher: 20 + i,
StockNum: 50 + i,
}
}
return tasks
}
// 生成新商品数据(模拟)
func generateNewTasks(count int) []SkuModel.DataItem {
tasks := make([]SkuModel.DataItem, count)
for i := 0; i < count; i++ {
tasks[i] = SkuModel.DataItem{
ProductID: fmt.Sprintf("NP%04d", i+1),
Name: fmt.Sprintf("新商品 %d", i+1),
Category: "新类别" + strconv.Itoa(i%3+1),
PriceLower: 15 + i,
PriceHigher: 25 + i,
StockNum: 30 + i,
}
}
return tasks
}
```
### 系统工作流程
1. **用户登录**:
- 输入用户名/密码 → 点击登录 → 更新用户状态 → 显示操作按钮
2. **操作1:添加用户列表**:
- 检查登录状态 → 添加新选项卡 → 显示用户列表视图
3. **操作2:加载初始数据**:
- 生成100条商品数据 → 初始化分页 → 显示第一页
4. **操作3:添加新商品**:
- 生成50条新商品 → 更新分页 → 自动跳转到最后一页
5. **用户注销**:
- 重置用户状态 → 隐藏操作按钮 → 清除敏感数据
### 完整系统架构
```
main.go
├─ 创建主窗口
├─ 创建状态栏 (ui.NewStatusBar)
├─ 创建用户模型
│
├─ 创建左侧面板 (ui.NewLeftPanel)
│ ├─ 登录表单
│ ├─ 用户信息显示
│ └─ 三个操作按钮
│
├─ 创建商品列表 (ui.NewProductList)
│ ├─ 表格视图
│ ├─ 分页控件
│ └─ 数据存储
│
├─ 创建通知列表 (ui.NewNotificationList)
│
├─ 创建用户列表 (ui.NewUserList)
│
└─ 组装主界面
├─ 左侧面板 (30%宽度)
└─ 右侧选项卡
├─ 商品列表
├─ 系统通知
└─ 用户列表(通过操作1添加)
```
### 运行效果

*左侧登录面板 + 中间商品表格 + 底部状态栏*
阅读全文
相关推荐
















