Go GUI---lxn/walk 自带demo学习---13.listbox_ownerdrawing

这个demo是干什么的呢???将近三百行。一个自定义的自增的列表框?

 

listbox_ownerdrawing.go

// Copyright 2019 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 (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
	"github.com/lxn/win"
)

func main() {
	var mw *walk.MainWindow
	var lb *walk.ListBox
	var items []logEntry
	for i := 10000; i > 0; i-- {
		items = append(items, logEntry{time.Now().Add(-time.Second * time.Duration(i)), fmt.Sprintf("Some stuff just happend. %s", strings.TrimSpace(strings.Repeat("blah ", i%100)))})
	}
	model := &logModel{items: items}
	styler := &Styler{
		lb:                  &lb,
		model:               model,
		dpi2StampSize:       make(map[int]walk.Size),
		widthDPI2WsPerLine:  make(map[widthDPI]int),
		textWidthDPI2Height: make(map[textWidthDPI]int),
	}

	if err := (MainWindow{
		AssignTo: &mw,
		Title:    "Walk ListBox Owner Drawing Example",
		MinSize:  Size{200, 200},
		Size:     Size{800, 600},
		Font:     Font{Family: "Segoe UI", PointSize: 9},
		Layout:   VBox{},
		Children: []Widget{
			Composite{
				DoubleBuffering: true,
				Layout:          VBox{},
				Children: []Widget{
					ListBox{
						AssignTo:       &lb,
						MultiSelection: true,
						Model:          model,
						ItemStyler:     styler,
					},
				},
			},
		},
	}).Create(); err != nil {
		log.Fatal(err)
	}

	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()

	cancel := make(chan bool, 1)

	go func() {
		for {
			select {
			case <-ticker.C:
				mw.Synchronize(func() {
					trackLatest := lb.ItemVisible(len(model.items)-1) && len(lb.SelectedIndexes()) <= 1

					model.items = append(model.items, logEntry{time.Now(), "Some new stuff."})
					index := len(model.items) - 1
					model.PublishItemsInserted(index, index)

					if trackLatest {
						lb.EnsureItemVisible(len(model.items) - 1)
					}
				})

			case <-cancel:
				break
			}
		}
	}()

	mw.Show()
	mw.Run()

	cancel <- true
}

type logModel struct {
	walk.ReflectListModelBase
	items []logEntry
}

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

type logEntry struct {
	timestamp time.Time
	message   string
}

type widthDPI struct {
	width int // in native pixels
	dpi   int
}

type textWidthDPI struct {
	text  string
	width int // in native pixels
	dpi   int
}

type Styler struct {
	lb                  **walk.ListBox
	canvas              *walk.Canvas
	model               *logModel
	font                *walk.Font
	dpi2StampSize       map[int]walk.Size
	widthDPI2WsPerLine  map[widthDPI]int
	textWidthDPI2Height map[textWidthDPI]int // in native pixels
}

func (s *Styler) ItemHeightDependsOnWidth() bool {
	return true
}

func (s *Styler) DefaultItemHeight() int {
	dpi := (*s.lb).DPI()
	marginV := walk.IntFrom96DPI(marginV96dpi, dpi)

	return s.StampSize().Height + marginV*2
}

const (
	marginH96dpi int = 6
	marginV96dpi int = 2
	lineW96dpi   int = 1
)

func (s *Styler) ItemHeight(index, width int) int {
	dpi := (*s.lb).DPI()
	marginH := walk.IntFrom96DPI(marginH96dpi, dpi)
	marginV := walk.IntFrom96DPI(marginV96dpi, dpi)
	lineW := walk.IntFrom96DPI(lineW96dpi, dpi)

	msg := s.model.items[index].message

	twd := textWidthDPI{msg, width, dpi}

	if height, ok := s.textWidthDPI2Height[twd]; ok {
		return height + marginV*2
	}

	canvas, err := s.Canvas()
	if err != nil {
		return 0
	}

	stampSize := s.StampSize()

	wd := widthDPI{width, dpi}
	wsPerLine, ok := s.widthDPI2WsPerLine[wd]
	if !ok {
		bounds, _, err := canvas.MeasureTextPixels("W", (*s.lb).Font(), walk.Rectangle{Width: 9999999}, walk.TextCalcRect)
		if err != nil {
			return 0
		}
		wsPerLine = (width - marginH*4 - lineW - stampSize.Width) / bounds.Width
		s.widthDPI2WsPerLine[wd] = wsPerLine
	}

	if len(msg) <= wsPerLine {
		s.textWidthDPI2Height[twd] = stampSize.Height
		return stampSize.Height + marginV*2
	}

	bounds, _, err := canvas.MeasureTextPixels(msg, (*s.lb).Font(), walk.Rectangle{Width: width - marginH*4 - lineW - stampSize.Width, Height: 255}, walk.TextEditControl|walk.TextWordbreak|walk.TextEndEllipsis)
	if err != nil {
		return 0
	}

	s.textWidthDPI2Height[twd] = bounds.Height

	return bounds.Height + marginV*2
}

func (s *Styler) StyleItem(style *walk.ListItemStyle) {
	if canvas := style.Canvas(); canvas != nil {
		if style.Index()%2 == 1 && style.BackgroundColor == walk.Color(win.GetSysColor(win.COLOR_WINDOW)) {
			style.BackgroundColor = walk.Color(win.GetSysColor(win.COLOR_BTNFACE))
			if err := style.DrawBackground(); err != nil {
				return
			}
		}

		pen, err := walk.NewCosmeticPen(walk.PenSolid, style.LineColor)
		if err != nil {
			return
		}
		defer pen.Dispose()

		dpi := (*s.lb).DPI()
		marginH := walk.IntFrom96DPI(marginH96dpi, dpi)
		marginV := walk.IntFrom96DPI(marginV96dpi, dpi)
		lineW := walk.IntFrom96DPI(lineW96dpi, dpi)

		b := style.BoundsPixels()
		b.X += marginH
		b.Y += marginV

		item := s.model.items[style.Index()]

		style.DrawText(item.timestamp.Format(time.StampMilli), b, walk.TextEditControl|walk.TextWordbreak)

		stampSize := s.StampSize()

		x := b.X + stampSize.Width + marginH + lineW
		canvas.DrawLinePixels(pen, walk.Point{x, b.Y - marginV}, walk.Point{x, b.Y - marginV + b.Height})

		b.X += stampSize.Width + marginH*2 + lineW
		b.Width -= stampSize.Width + marginH*4 + lineW

		style.DrawText(item.message, b, walk.TextEditControl|walk.TextWordbreak|walk.TextEndEllipsis)
	}
}

func (s *Styler) StampSize() walk.Size {
	dpi := (*s.lb).DPI()

	stampSize, ok := s.dpi2StampSize[dpi]
	if !ok {
		canvas, err := s.Canvas()
		if err != nil {
			return walk.Size{}
		}

		bounds, _, err := canvas.MeasureTextPixels("Jan _2 20:04:05.000", (*s.lb).Font(), walk.Rectangle{Width: 9999999}, walk.TextCalcRect)
		if err != nil {
			return walk.Size{}
		}

		stampSize = bounds.Size()
		s.dpi2StampSize[dpi] = stampSize
	}

	return stampSize
}

func (s *Styler) Canvas() (*walk.Canvas, error) {
	if s.canvas != nil {
		return s.canvas, nil
	}

	canvas, err := (*s.lb).CreateCanvas()
	if err != nil {
		return nil, err
	}
	s.canvas = canvas
	(*s.lb).AddDisposable(canvas)

	return canvas, nil
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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、付费专栏及课程。

余额充值