golang windowns界面开发框架
// 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.
// +build windows
package walk
import (
"encoding/json"
"fmt"
"math/big"
"reflect"
"syscall"
"time"
"unsafe"
"github.com/lxn/win"
)
const tableViewWindowClass = `\o/ Walk_TableView_Class \o/`
func init() {
MustRegisterWindowClass(tableViewWindowClass)
}
var (
defaultTVRowBGColor = Color(win.GetSysColor(win.COLOR_WINDOW))
white = win.COLORREF(RGB(255, 255, 255))
checkmark = string([]byte{0xE2, 0x9C, 0x94})
tableViewFrozenLVWndProcPtr = syscall.NewCallback(tableViewFrozenLVWndProc)
tableViewNormalLVWndProcPtr = syscall.NewCallback(tableViewNormalLVWndProc)
)
const (
tableViewCurrentIndexChangedTimerId = 1 + iota
tableViewSelectedIndexesChangedTimerId
)
// TableView is a model based widget for record centric, tabular data.
//
// TableView is implemented as a virtual mode list view to support quite large
// amounts of data.
type TableView struct {
WidgetBase
hwndFrozen win.HWND
frozenLVOrigWndProcPtr uintptr
hwndNormal win.HWND
normalLVOrigWndProcPtr uintptr
columns *TableViewColumnList
model TableModel
providedModel interface{}
itemChecker ItemChecker
imageProvider ImageProvider
styler CellStyler
style CellStyle
customDrawItemHot bool
hIml win.HIMAGELIST
usingSysIml bool
imageUintptr2Index map[uintptr]int32
filePath2IconIndex map[string]int32
rowsResetHandlerHandle int
rowChangedHandlerHandle int
rowsInsertedHandlerHandle int
rowsRemovedHandlerHandle int
sortChangedHandlerHandle int
selectedIndexes []int
prevIndex int
currentIndex int
currentIndexChangedPublisher EventPublisher
selectedIndexesChangedPublisher EventPublisher
itemActivatedPublisher EventPublisher
columnClickedPublisher IntEventPublisher
columnsOrderableChangedPublisher EventPublisher
columnsSizableChangedPublisher EventPublisher
publishNextSelClear bool
inSetSelectedIndexes bool
lastColumnStretched bool
inEraseBkgnd bool
persistent bool
itemStateChangedEventDelay int
alternatingRowBGColor Color
hasDarkAltBGColor bool
delayedCurrentIndexChangedCanceled bool
sortedColumnIndex int
sortOrder SortOrder
formActivatingHandle int
scrolling bool
inSetCurrentIndex bool
inMouseEvent bool
hasFrozenColumn bool
}
// NewTableView creates and returns a *TableView as child of the specified
// Container.
func NewTableView(parent Container) (*TableView, error) {
return NewTableViewWithStyle(parent, win.LVS_SHOWSELALWAYS)
}
// NewTableViewWithStyle creates and returns a *TableView as child of the specified
// Container and with the provided additional style bits set.
func NewTableViewWithStyle(parent Container, style uint32) (*TableView, error) {
tv := &TableView{
alternatingRowBGColor: defaultTVRowBGColor,
imageUintptr2Index: make(map[uintptr]int32),
filePath2IconIndex: make(map[string]int32),
formActivatingHandle: -1,
}
tv.columns = newTableViewColumnList(tv)
if err := InitWidget(
tv,
parent,
tableViewWindowClass,
win.WS_BORDER|win.WS_VISIBLE,
win.WS_EX_CONTROLPARENT); err != nil {
return nil, err
}
succeeded := false
defer func() {
if !succeeded {
tv.Dispose()
}
}()
if tv.hwndFrozen = win.CreateWindowEx(
0,
syscall.StringToUTF16Ptr("SysListView32"),
nil,
win.WS_CHILD|win.WS_CLIPSIBLINGS|win.WS_TABSTOP|win.WS_VISIBLE|win.LVS_OWNERDATA|win.LVS_REPORT|style,
win.CW_USEDEFAULT,
win.CW_USEDEFAULT,
win.CW_USEDEFAULT,
win.CW_USEDEFAULT,
tv.hWnd,
0,
0,
nil,
); tv.hwndFrozen == 0 {
return nil, newErr("creating frozen lv failed")
}
tv.frozenLVOrigWndProcPtr = win.SetWindowLongPtr(tv.hwndFrozen, win.GWLP_WNDPROC, tableViewFrozenLVWndProcPtr)
if tv.frozenLVOrigWndProcPtr == 0 {
return nil, lastError("SetWindowLongPtr")
}
if tv.hwndNormal = win.CreateWindowEx(
0,
syscall.StringToUTF16Ptr("SysListView32"),
nil,
win.WS_CHILD|win.WS_CLIPSIBLINGS|win.WS_TABSTOP|win.WS_VISIBLE|win.LVS_OWNERDATA|win.LVS_REPORT|style,
win.CW_USEDEFAULT,
win.CW_USEDEFAULT,
win.CW_USEDEFAULT,
win.CW_USEDEFAULT,
tv.hWnd,
0,
0,
nil,
); tv.hwndNormal == 0 {
return nil, newErr("creating normal lv failed")
}
tv.normalLVOrigWndProcPtr = win.SetWindowLongPtr(tv.hwndNormal, win.GWLP_WNDPROC, tableViewNormalLVWndProcPtr)
if tv.normalLVOrigWndProcPtr == 0 {
return nil, lastError("SetWindowLongPtr")
}
tv.SetPersistent(true)
exStyle := win.SendMessage(tv.hwndFrozen, win.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)
exStyle |= win.LVS_EX_DOUBLEBUFFER | win.LVS_EX_FULLROWSELECT | win.LVS_EX_HEADERDRAGDROP | win.LVS_EX_LABELTIP | win.LVS_EX_SUBITEMIMAGES
win.SendMessage(tv.hwndFrozen, win.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle)
win.SendMessage(tv.hwndNormal, win.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle)
if hr := win.SetWindowTheme(tv.hwndFrozen, syscall.StringToUTF16Ptr("Explorer"), nil); win.FAILED(hr) {
return nil, errorFromHRESULT("SetWindowTheme", hr)
}
if hr := win.SetWindowTheme(tv.hwndNormal, syscall.StringToUTF16Ptr("Explorer"), nil); win.FAILED(hr) {
return nil, errorFromHRESULT("SetWindowTheme", hr)
}
win.SendMessage(tv.hwndFrozen, win.WM_CHANGEUISTATE, uintptr(win.MAKELONG(win.UIS_SET, win.UISF_HIDEFOCUS)), 0)
win.SendMessage(tv.hwndNormal, win.WM_CHANGEUISTATE, uintptr(win.MAKELONG(win.UIS_SET, win.UISF_HIDEFOCUS)), 0)
tv.currentIndex = -1
tv.GraphicsEffects().Add(InteractionEffect)
tv.GraphicsEffects().Add(FocusEffect)
tv.MustRegisterProperty("ColumnsOrderable", NewBoolProperty(
func() bool {
return tv.ColumnsOrderable()
},
func(b bool) error {
tv.SetColumnsOrderable(b)
return nil
},
tv.columnsOrderableChangedPublisher.Event()))
tv.MustRegisterProperty("ColumnsSizable", NewBoolProperty(
func() bool {
return tv.ColumnsSizable()
},
func(b bool) error {
return tv.SetColumnsSizable(b)
},
tv.columnsSizableChangedPublisher.Event()))
tv.MustRegisterProperty("CurrentIndex", NewProperty(
func() interface{} {
return tv.CurrentIndex()
},
func(v interface{}) error {
return tv.SetCurrentIndex(v.(int))
},
tv.CurrentIndexChanged()))
tv.MustRegisterProperty("CurrentItem", NewReadOnlyProperty(
func() interface{} {
if i := tv.CurrentIndex(); i > -1 {
if rm, ok := tv.providedModel.(reflectModel); ok {
return reflect.ValueOf(rm.Items()).Index(i).Interface()
}
}
return nil
},
tv.CurrentIndexChanged()))
tv.MustRegisterProperty("HasCurrentItem", NewReadOnlyBoolProperty(
func() bool {
return tv.CurrentIndex() != -1
},
tv.CurrentIndexChanged()))
tv.MustRegisterProperty("SelectedCount", NewReadOnlyProperty(
func() interface{} {
return len(tv.selectedIndexes)
},
tv.SelectedIndexesChanged()))
succeeded = true
return tv, nil
}
// Dispose releases the operating system resources, associated with the
// *TableView.
func (tv *TableView) Dispose() {
tv.columns.unsetColumnsTV()
tv.disposeImageListAndCaches()
if tv.hWnd != 0 {
if !win.KillTimer(tv.hWnd, tableViewCurrentIndexChangedTimerId) {
lastError("KillTimer")
}
if !win.KillTimer(tv.hWnd, tableViewSelectedIndexesChangedTimerId) {