피로곰's 모두의 프린터

모두의 프린터는 개인, 기업 상관 없이 누구나 무료로 사용가능한 프로그램입니다. 회원가입,카드결제등을 요구하지 않습니다! 광고를 통해 연결되는 사이트에서의 회원가입, 카드결제 피해를 보지 않도록 주의하세요!
반응형

앞서 기본적인 트리뷰 생성법에 대해서는 아래 링크를 참고하시구요.

https://modu-print.tistory.com/938

 

[Go언어 윈도 GUI] walkmgr에 트리뷰(TreeView) 추가 1편

이번에 모두의 PDF에 책갈피 기능을 추가하면서 PDF의 책갈피 기능이 Parent, Children 을 이용한 무한 계층구조 인지라 이런 형태를 다루는데 가장 적합한 UI요소는 아무래도 트리뷰(TreeView)라서 관련

modu-print.tistory.com

몇가지 예제를 가지고 추가 사용법을 알려드리도록 하겠습니다.

트리뷰에서 선택된 아이템의 이름을 변경하는 예제입니다. 현재 선택된 아이템의 객체를 얻는 방법과 명칭을 변경하는 방법입니다.

func TestTreeView3(t *testing.T) {
	icon1, _ := walk.NewIconFromFile("./icon/icon1.ico")
	icon2, _ := walk.NewIconFromFile("./icon/icon2.ico")

	wm := walkmgr.NewWin("트리뷰 예제", 640, 480)

	treeView := wm.NewTreeView()
	treeView.AddItem("1", icon1)
	treeView.AddItem("2", icon2)
	treeView.AddItem("3", icon1)
	treeView.UpdateItems()

	wm.PushButton("선택 아이템 이름 변경", func() {
		ci := treeView.CurrentItem()

		if ci != nil {
			ci.SetText(fmt.Sprintf("변경된 이름 - %d", time.Now().Unix()))
			treeView.UpdateItems()
			treeView.SetCurrentItem(ci)
		}
	})

	wm.Start()
}
	treeView := wm.NewTreeView()
	treeView.AddItem("1", icon1)
	treeView.AddItem("2", icon2)
	treeView.AddItem("3", icon1)
	treeView.UpdateItems()

1,2,3 이라는 이름을 가진 3개의 아이템을 트리뷰의 루트에 추가하였습니다. 여기까진 앞서 알려드린 예제들과 같이 AddItem 메소드의 사용법만 알고 계시다면 큰 차이는 없습니다.

	wm.PushButton("선택 아이템 이름 변경", func() {
		ci := treeView.CurrentItem()

		if ci != nil {
			ci.SetText(fmt.Sprintf("변경된 이름 - %d", time.Now().Unix()))
			treeView.UpdateItems()
			treeView.SetCurrentItem(ci)
		}
	})

"선택 아이템 이름 변경" 이라는 버튼을 하나 만들고 이 버튼이 클릭되면 동작할 함수를 작성합니다.

	ci := treeView.CurrentItem()

현재 트리뷰에 선택된 아이템은 CurrentItem() 메소드로 얻을 수 있습니다. 전달되는 파라미터는 없고 그냥 호출만 하시면 됩니다. 만약 현재 선택된 아이템이 없으면 이 메소드의 리턴값은 nil입니다.

    if ci != nil {
        ci.SetText(fmt.Sprintf("변경된 이름 - %d", time.Now().Unix()))
        treeView.UpdateItems()
        treeView.SetCurrentItem(ci)
    }

CurrentItem 메소드의 리턴값은 항상 체크하셔야 합니다. 트리뷰 아이템의 이름과 관련된 메소드는 Text(), SetText() 2가지가 있습니다. 이는 walkmgr 관련 이전 글들에 다른 UI요소들에도 문자열로 정보가 표시되는 버튼이나 라벨등에는 대부분 Text,SetText 라는 이름으로 존재하는 메소드들을 통해 현재 텍스트를 얻거나 수정할 수 있습니다. 이놈도 똑 같습니다. Text() 메소드로는 현재의 값을 리턴 받을수 있고, SetText로는 변경할 텍스트를 전달하면 전달된 내용으로 변경됩니다.

아이템의 정보가 변경 되었기 때문에 UpdateItems() 메소드를 호출해 주셔야 변경된 사항이 트리뷰에 적용이 됩니다.

마지막 SetCurrentItem 메소드는 호출해도 되고 않해도 되지만 .. UpdateItems 메소드를 호출하고 나면 선택된 아이템 정보가 소멸됩니다. 그러다보니 선택해서 수정한 아이템이 무엇인지 다소 했갈릴수 있기 때문에 저는 내용을 변경한 아이템을 다시 선택해 주는 방향으로 사용하고 있습니다.

UpdateItems() 메소드 내부에서 관련 처리를 자동으로 하도록 구성을 할까 하였지만 선택된 아이템이 삭제 되는 경우에는 기존에 선택된 아이템을 선택하면 안되기 때문에.. 현재는 이러한 형태로 구성했습니다만, 아이템 삭제관련 기능이 추가되고 나면 UpdateItems() 내부에서 알아서 할 수 있도록도 가능할것 같습니다. 

이제 다음 예제를 봅시다!

현재 선택 아이템이 변경되는 이벤트를 처리하는 예제입니다.

func TestTreeView4(t *testing.T) {
	icon1, _ := walk.NewIconFromFile("./icon/icon1.ico")
	icon2, _ := walk.NewIconFromFile("./icon/icon2.ico")

	wm := walkmgr.NewWin("트리뷰 예제", 640, 480)

	treeView := wm.NewTreeView()
	treeView.AddItem("1", icon1)
	treeView.AddItem("2", icon2)
	treeView.AddItem("3", icon1)
	treeView.AddItem("4", icon1)
	treeView.AddItem("5", icon1)
	treeView.AddItem("6", icon1)
	treeView.AddItem("7", icon1)
	treeView.AddItem("8", icon1)
	treeView.UpdateItems()

	treeView.Tv().CurrentItemChanged().Attach(func() {
		ci := treeView.CurrentItem()
		if ci != nil {
			walkmgr.MsgBox(ci.Text(), wm.Window())
		}
	})

	wm.Start()
}

창을 만들고 아이템을 추가하는 예는 다른 예제와 다를게 없으니 이벤트 처리 부분만 설명하도록 합니다.

	treeView.Tv().CurrentItemChanged().Attach(func() {
		ci := treeView.CurrentItem()
		if ci != nil {
			walkmgr.MsgBox(ci.Text(), wm.Window())
		}
	})

walmgr 에서는 walk 패키지의 TreeView를 랩핑한 구조이기 때문에 실제 이벤트 핸들러를 처리하는것은 walkmgr 의 TreeView 객채 내에 존재하는 walk.TreeView 객체를 통해서 처리합니다. Tv() 메소드를 호출하면 이 walk 의 TreeView 객체를 리턴해 줍니다.

기존의 다른 UI 요소들에 이벤트 처리를 하는것과 동일하게 Tv() 메소드로 walk.TreeView 를 받고 이 walk.TreeView 의 CurrentItemChanged() 이벤트에 Attach 메소드로 이벤트를 처리할 함수를 전달하시면 되겠습니다. 이벤트 핸들러는 별다른 파라미터 없이 func(){} 로 만드시면 됩니다.

앞서 아이템의 이름변경때와 같이 CurrentItem() 메소드로 현재 아이템을 얻은 뒤에 이 아이템 객체의 Text() 함수로 아이템의 이름값을 얻어서 메시지 박스로 출력하는 예제입니다.

다음 예제는 .. 약간 트리뷰의 구조적 특성때문에 생겨난 구조에 대한 설명입니다. 보통 트리뷰는 트리뷰에 보여지는 정보와 실제 처리될 데이터가 별개로 존재하는 경우가 많습니다.

예를들어 윈도 탐색기의 트리뷰의 경우 트리뷰에는 MAIN(C:) 라고 아이템 이름이 표시되지만 실제 이 아이템을 선택해서 처리해야할 정보는 C: 일겁니다. Desktop 이나 다운로드, 문서 같은 경우도 실제로는 C:\Users\사용자명\Desktop 이나 Documents 같은 실질 경로를 저장한 데이터는 따로 존재를 하겠지요.

이런 경우 실제 데이터로도 트리뷰의 아이템에 접근이 가능해야하고 선택한 트리뷰의 특정 아이템으로도 이 아이템의 실질 데이터에 접근이 가능해야할 필요성이 있습니다.

그런 의미로 walkmgr.TreeViewItem 에는 interface{} 형으로 변수를 하나 포함하고 있고 이 변수에 실질 데이터를 연동해서 처리할 수 있는 메소드들을 제공하고 있습니다.

우선 코드 먼저 보겠습니다.

func TestTreeView5(t *testing.T) {
	icon1, _ := walk.NewIconFromFile("./icon/icon1.ico")
	icon2, _ := walk.NewIconFromFile("./icon/icon2.ico")

	wm := walkmgr.NewWin("트리뷰 예제", 640, 480)

	treeView := wm.NewTreeView()
	item1 := treeView.AddItem("1", icon1)
	data1 := "This is data number 1"
	item1.SetData(&data1)
	item2 := treeView.AddItem("2", icon2)
	data2 := "This is data number 2"
	item2.SetData(&data2)
	item3 := treeView.AddItem("3", icon1)
	data3 := "This is data number 3"
	item3.SetData(&data3)
	treeView.UpdateItems()

	treeView.Tv().CurrentItemChanged().Attach(func() {
		ci := treeView.CurrentItem()
		if ci != nil {
			data := ci.Data().(*string)
			if data != nil {
				walkmgr.MsgBox("Item Data : "+*data, wm.Window())

				fi := treeView.FindItem(data)

				if fi != nil {
					walkmgr.MsgBox("Find item from data : " + (*fi).Text())
				}
			}
		}
	})

	wm.Start()
}

창의 생성이나 그런부분은 다른 예들과 별 차이가 없습니다만.

	treeView := wm.NewTreeView()
	item1 := treeView.AddItem("1", icon1)
	data1 := "This is data number 1"
	item1.SetData(&data1)

AddItem 으로 아이템을 추가한 후 리턴받은 추가된 아이템 객체에 SetData 메소드로 data1 이라는 string 변수의 포인터를 파라미터로 전달하였습니다. 이러면 이 아이템 객체 내부의 interface{} 변수에 data1 변수의 포인터가 저장되게 됩니다.

	item2 := treeView.AddItem("2", icon2)
	data2 := "This is data number 2"
	item2.SetData(&data2)
	item3 := treeView.AddItem("3", icon1)
	data3 := "This is data number 3"
	item3.SetData(&data3)

나머지 아이템들도 같은식으로 1,2,3에 대한 string 데이터인 "This is data number 2 ~ 3"의 문자열을 담은 변수의 포인터를 SetData 메소드로 전달하고 있습니다.

	treeView.Tv().CurrentItemChanged().Attach(func() {
		ci := treeView.CurrentItem()
		if ci != nil {
			data := ci.Data().(*string)
			if data != nil {
				walkmgr.MsgBox("Item Data : "+*data, wm.Window())

				fi := treeView.FindItem(data)

				if fi != nil {
					walkmgr.MsgBox("Find item from data : " + (*fi).Text())
				}
			}
		}
	})

이제 CurrentItemChanged() 이벤트 핸들러에 현재 선택된 아이템을 ci 라는 변수에 받고 이 아이템 객체에 저장된 데이터를 리턴해주는 Data()라는 메소드를 사용하면 앞서 SetData로 저장해둔 변수의 포인터를 얻을 수 있습니다.

SetData로 string 데이터의 포인터를 전달 하였으니 위 예제의 경우 Data().(*string) 으로 형을 맞춰서 리턴 받은 것이구요. 이 부분은 각자 SetData에 전달한 데이터의 형에 맞춰서 작성하시면 되겠습니다.

        fi := treeView.FindItem(data)

        if fi != nil {
            walkmgr.MsgBox("Find item from data : " + (*fi).Text())
        }

이제 반대로 특정 데이터를 기준으로 이 데이터를 SetData로 저장시킨 트리뷰 아이템을 역으로 찾는 예를 보겠습니다.

walkmgr.TreeView의 메소드들중 FindItem 이라는 메소드가 있습니다. 이 메소드의 파라미터로 찾을 대상 데이터를 전달하면 이 데이터를 가지고 있는 트리뷰 아이템을 찾아서 리턴해줍니다.

위 코드의 실행결과를 봅시다.

우선 현재 선택된 아이템에 저장된 데이터의 값을 출력해주고 .. 이 데이터를 포함한 아이템을 찾은 후 이 아이템의 이름을 메시지 박스로 출력해주고 있습니다.

트리뷰 관련 예제는 하나 정도 더 글을 올릴 예정입니다.

이상입니다.

반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band