Golang으로 테이블을 구현할만한 GUI 라이브러리를 찾고 있는 중, andlabs/ui에서 예제를 발견하여 소스 코드를 올려봅니다. 분석도 좀 필요한데..아직은 그냥 몇몇 부분만 단순화 해놓은 상태입니다.
// tabletest.go
package main
import (
"fmt"
"github.com/andlabs/ui"
_ "github.com/andlabs/ui/winmanifest"
)
type modelHandler struct {
row9Text string
yellowRow int
checkStates [3]int
}
func (mh *modelHandler) ColumnTypes(m *ui.TableModel) []ui.TableValue {
return []ui.TableValue{
ui.TableString(""), // column 0 text
ui.TableString(""), // column 1 text
ui.TableString(""), // column 2 text
}
}
func (mh *modelHandler) NumRows(m *ui.TableModel) int {
return 3
}
func (mh *modelHandler) CellValue(m *ui.TableModel, row, column int) ui.TableValue {
fmt.Printf("%d %d\n", row, column)
return ui.TableString(row_data[row][column]) //테이블 내부에서 모든 행/열에 대해 자동 수행됨.
//String으로 선언된 배열 값을 행/렬 값을 인덱스로 받아들
}
func (mh *modelHandler) SetCellValue(m *ui.TableModel, row, column int, value ui.TableValue) {
mh.row9Text = string(value.(ui.TableString))
}
func newModelHandler() *modelHandler {
m := new(modelHandler)
m.row9Text = "You can edit this one"
m.yellowRow = -1
return m
}
//불러올 데이터를 전역변수로 정의
var row_data = [3][3]string{
{"a", "b", "c"},
{"f", "e", "d"},
{"g", "h", "i"},
}
func setupUI() {
mainwin := ui.NewWindow("libui Control Gallery", 640, 480, true)
mainwin.OnClosing(func(*ui.Window) bool {
ui.Quit()
return true
})
ui.OnShouldQuit(func() bool {
mainwin.Destroy()
return true
})
mh := newModelHandler()
model := ui.NewTableModel(mh)
table := ui.NewTable(&ui.TableParams{
Model: model,
RowBackgroundColorModelColumn: -1, // "RowBackgroundColorModelColumn"는 테이블의 전체 행에
//사용되는 배경색을 사용하는 열 번호를 정의.
//모든 행에 기본 배경색을 사용하려면 -1.
//CellValue가 NULL이면 기본 배경색.
})
table.AppendTextColumn("Column 1", 0, ui.TableModelColumnNeverEditable, nil)
table.AppendTextColumn("Column 2", 1, ui.TableModelColumnNeverEditable, nil)
table.AppendTextColumn("Editable", 2, ui.TableModelColumnAlwaysEditable, nil)
input := ui.NewEntry()
button := ui.NewButton("Greet")
box := ui.NewVerticalBox()
box.Append(ui.NewLabel("Enter your name:"), false)
box.Append(input, false)
box.Append(button, false)
box.Append(table, true)
mainwin.SetChild(box)
mainwin.SetMargined(true)
mainwin.Show()
}
func main() {
ui.Main(setupUI)
}
결과물은 아래처럼 나오는데.....적당히 수정해서 Oracle하고 연동해서 사용할 계획입니다.
(결과물 나오는대로 포스팅 업데이트 예정)
2020.04.01수정:
외부 데이터를 받아들여 표시하기 위해 이것 저것 만져보았습니다. 우선 "RowBackgroundColorModelColumn" 녀석이 있는데, 이게 -1로 되어있어야 했습니다. 배경색을 정의하는 인자 같은데, 이걸 다른 값을 설정하면....예를 들어 3을 설정하면 칼럼 값이 3+3=6이 됩니다. 화면에 나타나지 않아서 찾느라 고생했습니다ㅠㅠ. 덕분에 CellValue 함수 정의하는데 고생을 좀 했습니다.
Go가 설치된 디렉토리(윈도우즈의 경우 디폴트로 C:\Go)를 가리키며, Go 실행파일은 GOROOT/bin 폴더에, Go 표준 패키지들은 GOROOT/pkg 폴더에 존재합니다. 윈도우즈에 GO 설치시 시스템 환경변수로 자동으로 설정됩니다.
GOPATH:
Go는 표준 패키지 이외의 3rd Party 패키지나 사용자 정의 패키지들을 이 GOPATH 에서 찾습니다. 복수 개의 경로를 지정한 경우, 3rd Party 패키지는 처음 경로에 설치됩니다. 그런데 최초 설치시 GOPATH가 C:\C:\Users\USER\go로 지정됩니다. 따라서 다른 폴더를 적용하고 싶을 경우에는 적당한 폴더로 변경해주는 게 좋을 것 같습니다.
GOROOT나 GOPATH나 모두 최초 설치시에는 사용자 변수로 등록되므로, 저는 삭제하고 다시 시스템 변수로 등록해주었습니다. 그리고 GOPATH는 3rd party 패키지 설치를 위한 폴더, 직접 작업할 파일 폴더, 이렇게 두 폴더를 각각 지정해 두었습니다.
3. Hello World 출력
LiteIDE로 작업을 했습니다. 폴더 하나를 생성하고, hello.go파일을 만들면 자동으로 아래와 같이 디폴트로 코드가 생성됩니다. 여기서 BR을 눌러줘도 되구요... (main함수가 한 폴더에 두개이상 존재하면 에러가 나기 때문에, 별도의 폴더를 생성하는 것이 필요합니다.)
커맨드 창에서 실행해도 잘 출력되는 것을 확인할 수 있습니다.
이상으로 Go언어 설치/환경변수 설정/Hello world 출력하는 방법에 대해 간단히 알아보았습니다.
3. 컨트롤->GtkButton 3개를 생성해서 아이디를 TestBtn, HelloBtn, exitBtn으로 해주세요. 그리고 그에 맞게 레이블도 수정해 줍니다.
이렇게 구성하면 glade2.glade 로 저장합니다. 물론 아무 이름이나 상관 없습니다만, 그럴 경우 아래 소스코드의 파일명 부분을 적당히 수정해주세요. 이제 아래의 소스코드를 수행해봅니다.
// gotk_glade.go
package main
import (
"errors"
"fmt"
"log"
"os"
"reflect"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
)
var headerBar *gtk.HeaderBar
func main() {
// Create a new application.
application, err := gtk.ApplicationNew("new.test", glib.APPLICATION_FLAGS_NONE)
errorCheck(err)
// Connect function to application startup event, this is not required.
application.Connect("startup", func() {
log.Println("application startup")
})
// Connect function to application activate event
application.Connect("activate", func() {
log.Println("application activate")
// Get the GtkBuilder UI definition in the glade file.
builder, err := gtk.BuilderNewFromFile("glade2.glade")
errorCheck(err)
// Map the handlers to callback functions, and connect the signals
// to the Builder.
signals := map[string]interface{}{
"on_main_window_destroy": onMainWindowDestroy,
"on_HelloBtn_clicked": clickedTestButton,
}
builder.ConnectSignals(signals)
// Get the object with the id of "main_window".
obj, err := builder.GetObject("main_window")
fmt.Println(reflect.TypeOf(obj))
errorCheck(err)
// Verify that the object is a pointer to a gtk.ApplicationWindow.
win, err := isWindow(obj)
fmt.Println(reflect.TypeOf(win))
errorCheck(err)
headerBar, err := builder.GetObject("headerbar")
errorCheck(err)
fmt.Println(reflect.TypeOf(headerBar))
//headerBar.SetTitle("sss")
// Show the Window and all of its components.
win.Show()
application.AddWindow(win)
})
// Connect function to application shutdown event, this is not required.
application.Connect("shutdown", func() {
log.Println("application shutdown")
})
// Launch the application
os.Exit(application.Run(os.Args))
}
func isWindow(obj glib.IObject) (*gtk.Window, error) {
// Make type assertion (as per gtk.go).
if win, ok := obj.(*gtk.Window); ok {
return win, nil
}
return nil, errors.New("not a *gtk.Window")
}
func errorCheck(e error) {
if e != nil {
// panic for any errors.
log.Panic(e)
}
}
// onMainWindowDestory is the callback that is linked to the
// on_main_window_destroy handler. It is not required to map this,
// and is here to simply demo how to hook-up custom callbacks.
func onMainWindowDestroy() {
log.Println("onMainWindowDestroy")
}
func clickedTestButton() {
fmt.Println("Testclick")
//headerBar.SetTitle("New Title!!")
}