Go GUI---lxn/walk 自带demo学习---7.文件浏览器

如上图,从左到右用来TreeView、TableView、WebView

定义了一个名为Directory的目录结构体,每个目录理论上有一个父节点,有0到n个子节点。

type Directory struct {
	name     string
	parent   *Directory
	children []*Directory
}

 

 

filebrowser.go

// Copyright 2011 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"log"
	"os"
	"path/filepath"
	"time"
)

import (
	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
)

type Directory struct {
	name     string
	parent   *Directory
	children []*Directory
}

func NewDirectory(name string, parent *Directory) *Directory {
	return &Directory{name: name, parent: parent}
}

var _ walk.TreeItem = new(Directory)

func (d *Directory) Text() string {
	return d.name
}

func (d *Directory) Parent() walk.TreeItem {
	if d.parent == nil {
		// We can't simply return d.parent in this case, because the interface
		// value then would not be nil.
		return nil
	}

	return d.parent
}

func (d *Directory) ChildCount() int {
	if d.children == nil {
		// It seems this is the first time our child count is checked, so we
		// use the opportunity to populate our direct children.
		if err := d.ResetChildren(); err != nil {
			log.Print(err)
		}
	}

	return len(d.children)
}

func (d *Directory) ChildAt(index int) walk.TreeItem {
	return d.children[index]
}

func (d *Directory) Image() interface{} {
	return d.Path()
}

func (d *Directory) ResetChildren() error {
	d.children = nil

	dirPath := d.Path()

	if err := filepath.Walk(d.Path(), func(path string, info os.FileInfo, err error) error {
		if err != nil {
			if info == nil {
				return filepath.SkipDir
			}
		}

		name := info.Name()

		if !info.IsDir() || path == dirPath || shouldExclude(name) {
			return nil
		}

		d.children = append(d.children, NewDirectory(name, d))

		return filepath.SkipDir
	}); err != nil {
		return err
	}

	return nil
}

func (d *Directory) Path() string {
	elems := []string{d.name}

	dir, _ := d.Parent().(*Directory)

	for dir != nil {
		elems = append([]string{dir.name}, elems...)
		dir, _ = dir.Parent().(*Directory)
	}

	return filepath.Join(elems...)
}

type DirectoryTreeModel struct {
	walk.TreeModelBase
	roots []*Directory
}

var _ walk.TreeModel = new(DirectoryTreeModel)

func NewDirectoryTreeModel() (*DirectoryTreeModel, error) {
	model := new(DirectoryTreeModel)

	drives, err := walk.DriveNames()
	if err != nil {
		return nil, err
	}

	for _, drive := range drives {
		switch drive {
		case "A:\\", "B:\\":
			continue
		}

		model.roots = append(model.roots, NewDirectory(drive, nil))
	}

	return model, nil
}

func (*DirectoryTreeModel) LazyPopulation() bool {
	// We don't want to eagerly populate our tree view with the whole file system.
	return true
}

func (m *DirectoryTreeModel) RootCount() int {
	return len(m.roots)
}

func (m *DirectoryTreeModel) RootAt(index int) walk.TreeItem {
	return m.roots[index]
}

type FileInfo struct {
	Name     string
	Size     int64
	Modified time.Time
}

type FileInfoModel struct {
	walk.SortedReflectTableModelBase
	dirPath string
	items   []*FileInfo
}

var _ walk.ReflectTableModel = new(FileInfoModel)

func NewFileInfoModel() *FileInfoModel {
	return new(FileInfoModel)
}

func (m *FileInfoModel) Items() interface{} {
	return m.items
}

func (m *FileInfoModel) SetDirPath(dirPath string) error {
	m.dirPath = dirPath
	m.items = nil

	if err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			if info == nil {
				return filepath.SkipDir
			}
		}

		name := info.Name()

		if path == dirPath || shouldExclude(name) {
			return nil
		}

		item := &FileInfo{
			Name:     name,
			Size:     info.Size(),
			Modified: info.ModTime(),
		}

		m.items = append(m.items, item)

		if info.IsDir() {
			return filepath.SkipDir
		}

		return nil
	}); err != nil {
		return err
	}

	m.PublishRowsReset()

	return nil
}

func (m *FileInfoModel) Image(row int) interface{} {
	return filepath.Join(m.dirPath, m.items[row].Name)
}

func shouldExclude(name string) bool {
	switch name {
	case "System Volume Information", "pagefile.sys", "swapfile.sys":
		return true
	}

	return false
}

func main() {
	var mainWindow *walk.MainWindow
	var splitter *walk.Splitter
	var treeView *walk.TreeView
	var tableView *walk.TableView
	var webView *walk.WebView

	treeModel, err := NewDirectoryTreeModel()
	if err != nil {
		log.Fatal(err)
	}
	tableModel := NewFileInfoModel()

	if err := (MainWindow{
		AssignTo: &mainWindow,
		Title:    "Walk File Browser Example",
		MinSize:  Size{600, 400},
		Size:     Size{1024, 640},
		Layout:   HBox{MarginsZero: true},
		Children: []Widget{
			HSplitter{
				AssignTo: &splitter,
				Children: []Widget{
					TreeView{
						AssignTo: &treeView,
						Model:    treeModel,
						OnCurrentItemChanged: func() {
							dir := treeView.CurrentItem().(*Directory)
							if err := tableModel.SetDirPath(dir.Path()); err != nil {
								walk.MsgBox(
									mainWindow,
									"Error",
									err.Error(),
									walk.MsgBoxOK|walk.MsgBoxIconError)
							}
						},
					},
					TableView{
						AssignTo:      &tableView,
						StretchFactor: 2,
						Columns: []TableViewColumn{
							TableViewColumn{
								DataMember: "Name",
								Width:      192,
							},
							TableViewColumn{
								DataMember: "Size",
								Format:     "%d",
								Alignment:  AlignFar,
								Width:      64,
							},
							TableViewColumn{
								DataMember: "Modified",
								Format:     "2006-01-02 15:04:05",
								Width:      120,
							},
						},
						Model: tableModel,
						OnCurrentIndexChanged: func() {
							var url string
							if index := tableView.CurrentIndex(); index > -1 {
								name := tableModel.items[index].Name
								dir := treeView.CurrentItem().(*Directory)
								url = filepath.Join(dir.Path(), name)
							}

							webView.SetURL(url)
						},
					},
					WebView{
						AssignTo:      &webView,
						StretchFactor: 2,
					},
				},
			},
		},
	}.Create()); err != nil {
		log.Fatal(err)
	}

	splitter.SetFixed(treeView, true)
	splitter.SetFixed(tableView, true)

	mainWindow.Run()
}

Walk库中,可以使用`TabPage`和`TabWidget`控件来创建和管理选项卡。下面是一个简单的示例代码,演示如何初始化包含两个选项卡的`TabWidget`: ```go package main import ( "github.com/lxn/walk" . "github.com/lxn/walk/declarative" ) func main() { // 创建一个新的主窗口 mainWindow := new(MyMainWindow) // 创建一个新的TabWidget tabWidget := new(walk.TabWidget) // 创建第一个选项卡 tabPage1 := walk.NewTabPage() tabPage1.SetTitle("Tab Page 1") tabPage1.SetLayout(walk.NewVBoxLayout()) // 添加一些控件到第一个选项卡中 tabPage1.Layout().Add(walk.NewLabel(mainWindow)) tabPage1.Layout().Add(walk.NewPushButton(mainWindow)) // 创建第二个选项卡 tabPage2 := walk.NewTabPage() tabPage2.SetTitle("Tab Page 2") tabPage2.SetLayout(walk.NewVBoxLayout()) // 添加一些控件到第二个选项卡中 tabPage2.Layout().Add(walk.NewLabel(mainWindow)) tabPage2.Layout().Add(walk.NewCheckBox(mainWindow)) // 将两个选项卡添加到TabWidget中 tabWidget.Pages().Add(tabPage1) tabWidget.Pages().Add(tabPage2) // 创建一个新的主布局,并将TabWidget添加到其中 mainLayout := VBox{ MarginsZero: true, Children: []Widget{ tabWidget, }, } // 创建主窗口的声明式描述 mainWindow.Desc = &MainWindow{ Title: "My App", MinSize: Size{600, 400}, Layout: mainLayout, AssignTo: &mainWindow.MainWindow, } // 运行应用程序 mainWindow.Run() } // 定义一个新的主窗口类型 type MyMainWindow struct { *walk.MainWindow } ``` 在这个示例中,我们创建了一个`TabWidget`,并向其中添加了两个选项卡。每个选项卡都包含一些基本控件,例如`Label`,`PushButton`和`CheckBox`,以演示如何将控件添加到选项卡中。最后,我们将`TabWidget`添加到一个主布局中,并将其分配给主窗口的`Desc`属性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值