mirror of
https://github.com/mappu/miqt.git
synced 2025-04-01 11:20:23 +00:00
Introduce an example of implementing a custom QAbstractItemModel and QSortFilterProxyModel
This commit is contained in:
parent
2c04594b71
commit
4bba1b8c01
93
examples/customsortfiltermodel/main.go
Normal file
93
examples/customsortfiltermodel/main.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
qt "github.com/mappu/miqt/qt6"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetTreeView(parent *qt.QWidget) *qt.QTreeView {
|
||||||
|
treeView := qt.NewQTreeView(parent)
|
||||||
|
treeView.SetAlternatingRowColors(true)
|
||||||
|
treeView.SetSortingEnabled(true)
|
||||||
|
treeView.SetColumnWidth(0, 300)
|
||||||
|
treeView.SetContentsMargins(0, 0, 0, 0)
|
||||||
|
treeView.Header().SetDefaultSectionSize(200)
|
||||||
|
treeView.Header().SetStretchLastSection(true)
|
||||||
|
treeView.SetSelectionMode(qt.QAbstractItemView__ExtendedSelection)
|
||||||
|
|
||||||
|
return treeView
|
||||||
|
}
|
||||||
|
|
||||||
|
func PopulateData(rootItem *TreeItem) {
|
||||||
|
cellData := make([]*TreeCell, 0)
|
||||||
|
cellData = append(cellData, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("Big File")))
|
||||||
|
cellData = append(cellData, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("10.7 MiB")))
|
||||||
|
item := NewTreeItem(cellData, rootItem, false)
|
||||||
|
err := item.SetData(1, qt.NewQVariant11("11225400"), qt.UserRole)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error setting UserData: %v\n", err)
|
||||||
|
}
|
||||||
|
rootItem.AppendChild(&item)
|
||||||
|
|
||||||
|
cellData2 := make([]*TreeCell, 0)
|
||||||
|
cellData2 = append(cellData2, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("Small File")))
|
||||||
|
cellData2 = append(cellData2, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("110 Bytes")))
|
||||||
|
item2 := NewTreeItem(cellData2, rootItem, false)
|
||||||
|
err = item2.SetData(1, qt.NewQVariant11("110"), qt.UserRole)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error setting UserData: %v\n", err)
|
||||||
|
}
|
||||||
|
rootItem.AppendChild(&item2)
|
||||||
|
|
||||||
|
cellData3 := make([]*TreeCell, 0)
|
||||||
|
cellData3 = append(cellData3, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("Medium File")))
|
||||||
|
cellData3 = append(cellData3, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("109.5 KiB")))
|
||||||
|
item3 := NewTreeItem(cellData3, rootItem, false)
|
||||||
|
err = item3.SetData(1, qt.NewQVariant11("112200"), qt.UserRole)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error setting UserData: %v\n", err)
|
||||||
|
}
|
||||||
|
rootItem.AppendChild(&item3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDialog() *qt.QDialog {
|
||||||
|
dialog := qt.NewQDialog3(nil, qt.Dialog)
|
||||||
|
dialog.SetWindowFlags(qt.WindowStaysOnTopHint)
|
||||||
|
dialogLayout := qt.NewQVBoxLayout2()
|
||||||
|
dialogLayout.SetSpacing(0)
|
||||||
|
dialogLayout.SetContentsMargins(0, 0, 0, 0)
|
||||||
|
dialog.SetContentsMargins(10, 10, 10, 10)
|
||||||
|
dialog.SetLayout(dialogLayout.Layout())
|
||||||
|
dialog.SetWindowTitle("Example Sort Model Usage")
|
||||||
|
|
||||||
|
treeView := GetTreeView(dialog.QWidget)
|
||||||
|
|
||||||
|
// Model
|
||||||
|
model, rootItem := GetModel(dialog.QObject)
|
||||||
|
PopulateData(rootItem)
|
||||||
|
|
||||||
|
sortModel := qt.NewQSortFilterProxyModel2(treeView.QObject)
|
||||||
|
sortModel.SetSortRole(int(qt.UserRole))
|
||||||
|
sortModel.OnLessThan(func(super func(source_left *qt.QModelIndex, source_right *qt.QModelIndex) bool, source_left *qt.QModelIndex, source_right *qt.QModelIndex) bool {
|
||||||
|
// In our case we know that the data from our TreeItem will come back as an int for our UserRole
|
||||||
|
leftData := sortModel.SourceModel().Data(source_left, sortModel.SortRole())
|
||||||
|
rightData := sortModel.SourceModel().Data(source_right, sortModel.SortRole())
|
||||||
|
return leftData.ToInt() < rightData.ToInt()
|
||||||
|
})
|
||||||
|
|
||||||
|
sortModel.SetSourceModel(model)
|
||||||
|
treeView.SetModel(sortModel.QAbstractItemModel)
|
||||||
|
|
||||||
|
dialogLayout.AddWidget3(treeView.QWidget, 0, qt.AlignCenter)
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
qt.NewQApplication(os.Args)
|
||||||
|
|
||||||
|
dialog := GetDialog()
|
||||||
|
dialog.Show()
|
||||||
|
|
||||||
|
qt.QApplication_Exec()
|
||||||
|
}
|
94
examples/customsortfiltermodel/model.go
Normal file
94
examples/customsortfiltermodel/model.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
qt "github.com/mappu/miqt/qt6"
|
||||||
|
"slices"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetModel(parent *qt.QObject) (*qt.QAbstractItemModel, *TreeItem) {
|
||||||
|
model := qt.NewQAbstractItemModel2(parent)
|
||||||
|
|
||||||
|
data := make([]*TreeCell, 0)
|
||||||
|
data = append(data, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("Name")))
|
||||||
|
data = append(data, NewTreeCell(qt.DisplayRole, *qt.NewQVariant11("Size")))
|
||||||
|
rootItem := NewTreeItem(data, nil, true)
|
||||||
|
|
||||||
|
model.OnData(func(index *qt.QModelIndex, role int) *qt.QVariant {
|
||||||
|
if !index.IsValid() {
|
||||||
|
return qt.NewQVariant()
|
||||||
|
}
|
||||||
|
if !slices.Contains([]qt.ItemDataRole{qt.DisplayRole, qt.UserRole}, qt.ItemDataRole(role)) {
|
||||||
|
return qt.NewQVariant()
|
||||||
|
}
|
||||||
|
item := (*TreeItem)(index.InternalPointer())
|
||||||
|
return item.Data(index.Column(), qt.ItemDataRole(role))
|
||||||
|
})
|
||||||
|
|
||||||
|
model.OnHeaderData(func(super func(section int, orientation qt.Orientation, role int) *qt.QVariant, section int, orientation qt.Orientation, role int) *qt.QVariant {
|
||||||
|
if qt.ItemDataRole(role) != qt.DisplayRole {
|
||||||
|
return qt.NewQVariant()
|
||||||
|
}
|
||||||
|
if orientation == qt.Horizontal && role == int(qt.DisplayRole) {
|
||||||
|
return rootItem.Data(section, qt.DisplayRole)
|
||||||
|
}
|
||||||
|
return qt.NewQVariant()
|
||||||
|
})
|
||||||
|
|
||||||
|
model.OnIndex(func(row int, column int, parent *qt.QModelIndex) *qt.QModelIndex {
|
||||||
|
if !model.HasIndex3(row, column, parent) {
|
||||||
|
return qt.NewQModelIndex()
|
||||||
|
}
|
||||||
|
var parentItem *TreeItem
|
||||||
|
if !parent.IsValid() {
|
||||||
|
parentItem = &rootItem
|
||||||
|
} else {
|
||||||
|
parentItem = (*TreeItem)(parent.InternalPointer())
|
||||||
|
}
|
||||||
|
child, err := parentItem.Child(row)
|
||||||
|
if err != nil {
|
||||||
|
return qt.NewQModelIndex()
|
||||||
|
}
|
||||||
|
newIndex := model.CreateIndex2(row, column, uintptr(unsafe.Pointer(child)))
|
||||||
|
return &newIndex
|
||||||
|
})
|
||||||
|
|
||||||
|
model.OnParent(func(child *qt.QModelIndex) *qt.QModelIndex {
|
||||||
|
if !child.IsValid() {
|
||||||
|
return qt.NewQModelIndex()
|
||||||
|
}
|
||||||
|
parentItem := (*TreeItem)(child.InternalPointer()).ParentItem()
|
||||||
|
if parentItem != &rootItem {
|
||||||
|
row, err := parentItem.Row()
|
||||||
|
if err != nil {
|
||||||
|
return qt.NewQModelIndex()
|
||||||
|
}
|
||||||
|
index := model.CreateIndex2(row, 0, uintptr(unsafe.Pointer(parentItem)))
|
||||||
|
return &index
|
||||||
|
}
|
||||||
|
return qt.NewQModelIndex()
|
||||||
|
})
|
||||||
|
|
||||||
|
model.OnRowCount(func(parent *qt.QModelIndex) int {
|
||||||
|
if parent.Column() > 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var item *TreeItem
|
||||||
|
if !parent.IsValid() {
|
||||||
|
item = &rootItem
|
||||||
|
} else {
|
||||||
|
item = (*TreeItem)(parent.InternalPointer())
|
||||||
|
}
|
||||||
|
return item.ChildCount()
|
||||||
|
})
|
||||||
|
|
||||||
|
model.OnColumnCount(func(parent *qt.QModelIndex) int {
|
||||||
|
if parent.IsValid() {
|
||||||
|
item := (*TreeItem)(parent.InternalPointer())
|
||||||
|
return item.ColumnCount()
|
||||||
|
}
|
||||||
|
return rootItem.ColumnCount()
|
||||||
|
})
|
||||||
|
|
||||||
|
return model, &rootItem
|
||||||
|
}
|
33
examples/customsortfiltermodel/tree_cell.go
Normal file
33
examples/customsortfiltermodel/tree_cell.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
qt "github.com/mappu/miqt/qt6"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TreeCell struct {
|
||||||
|
data map[qt.ItemDataRole]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTreeCell(role qt.ItemDataRole, value qt.QVariant) *TreeCell {
|
||||||
|
data := make(map[qt.ItemDataRole]string)
|
||||||
|
data[role] = value.ToString()
|
||||||
|
return &TreeCell{data: data}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cell *TreeCell) SetData(data qt.QVariant, role qt.ItemDataRole) {
|
||||||
|
cell.data[role] = data.ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cell *TreeCell) Data(role qt.ItemDataRole) *qt.QVariant {
|
||||||
|
if role == qt.UserRole {
|
||||||
|
number, err := strconv.Atoi(cell.data[role])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error converting %s to int: %v\n", number, err)
|
||||||
|
return qt.NewQVariant11(cell.data[role])
|
||||||
|
}
|
||||||
|
return qt.NewQVariant4(number)
|
||||||
|
}
|
||||||
|
return qt.NewQVariant11(cell.data[role])
|
||||||
|
}
|
82
examples/customsortfiltermodel/tree_item.go
Normal file
82
examples/customsortfiltermodel/tree_item.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
qt "github.com/mappu/miqt/qt6"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TreeItem struct {
|
||||||
|
data []*TreeCell
|
||||||
|
parent *TreeItem
|
||||||
|
children []*TreeItem
|
||||||
|
isRoot bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTreeItem(data []*TreeCell, parent *TreeItem, isRoot bool) TreeItem {
|
||||||
|
return TreeItem{
|
||||||
|
data: data,
|
||||||
|
parent: parent,
|
||||||
|
isRoot: isRoot,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TreeItem) IsRoot() bool {
|
||||||
|
return self.isRoot
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TreeItem) AppendChild(child *TreeItem) {
|
||||||
|
self.children = append(self.children, child)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TreeItem) Child(row int) (*TreeItem, error) {
|
||||||
|
if row >= 0 && row <= self.ChildCount() {
|
||||||
|
return self.children[row], nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("TreeItem does not have child at row %d", row)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TreeItem) ColumnCount() int {
|
||||||
|
return len(self.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TreeItem) ChildCount() int {
|
||||||
|
return len(self.children)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TreeItem) Data(column int, role qt.ItemDataRole) *qt.QVariant {
|
||||||
|
if column >= 0 && column < len(self.data) {
|
||||||
|
if !slices.Contains([]qt.ItemDataRole{qt.DisplayRole, qt.UserRole}, role) {
|
||||||
|
return qt.NewQVariant()
|
||||||
|
}
|
||||||
|
return self.data[column].Data(role)
|
||||||
|
}
|
||||||
|
return qt.NewQVariant()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TreeItem) SetData(column int, value *qt.QVariant, role qt.ItemDataRole) error {
|
||||||
|
if column >= 0 && column < len(self.data) {
|
||||||
|
self.data[column].SetData(*value, role)
|
||||||
|
} else {
|
||||||
|
cell := NewTreeCell(role, *value)
|
||||||
|
self.data = append(self.data, cell)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TreeItem) Row() (int, error) {
|
||||||
|
if self.parent == nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
for index, child := range self.parent.children {
|
||||||
|
if child == self {
|
||||||
|
return index, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("could not find child in its parent")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TreeItem) ParentItem() *TreeItem {
|
||||||
|
return self.parent
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user