[출처 - 이 글은 tornadofx-guide르 통해 공부한 내용을 정리한 글입니다. 더 정확한 내용은 https://edvin.gitbooks.io/tornadofx-guide/part1/5.%20Data%20Controls.html 에서 확인 하실 수 있습니다.]
Data를 관리하는 controls에 대해서 알아보겠습니다.
ListView
ListView는 combobox와 비슷하지만 combobox의 경우에는 항목을 click해야 list가 나타나지만 ListView는 바로 List가 나타납니다.
class Data_controls_view : View(){
override val root = vbox {
listview<String> {
items.add("Alpha")
items.add("Beta")
items.add("Gamma")
items.add("Delta")
items.add("Epsilon")
selectionModel.selectionMode = SelectionMode.MULTIPLE
}
}
}
class Data_controls_app : App(Data_controls_view::class)
fun main() {
launch<Data_controls_app>()
}
위의 방법 말고도 다음과 같은 방법으로 ListView를 만들 수 있습니다. (selectionModel의 mode를 MULTIPLE로 했기 때문에 다중 선택이 가능합니다.)
class Data_controls_view : View(){
override val root = vbox {
val greekLetters = listOf("Alpha","Beta",
"Gamma","Delta","Epsilon").observable()
listview(greekLetters) {
selectionModel.selectionMode = SelectionMode.MULTIPLE
}
}
}
결과는 위와 동일 합니다.
TableView
tableview를 생성하는 기본은 다음과 같다.
class Person(val id: Int, val name: String, val birthday: LocalDate) {
val age: Int
get() = Period.between(birthday, LocalDate.now()).years
}
private val persons = listOf(
Person(1, "Samantha Stuart", LocalDate.of(1981, 12, 4)),
Person(2, "Tom Marks", LocalDate.of(2001, 1, 23)),
Person(3, "Stuart Gills", LocalDate.of(1989, 5, 23)),
Person(4, "Nicole Williams", LocalDate.of(1998, 8, 11))
).asObservable()
class table_view: View(){
override val root = tableview(persons){
readonlyColumn("ID",Person::id)
readonlyColumn("Name", Person::name)
readonlyColumn("Birthday", Person::birthday)
readonlyColumn("Age",Person::age)
}
}
class table_app: App(table_view::class)
fun main() {
launch<table_app>()
}
이렇게 Person이라는 클레스를 사용하여 person의 내용을 정하고, listof로 person 데이터들을 생성후 table에 적용 시키면
와 같은 결과가 나옵니다.(위의 code에서 readonlyColumn은 데이터 클래스 및 변경 불가능한 특성에 사용되는 column 입니다.)
그럼 위의 테이블 생성을 property를 사용하여 생성해 보겠습니다. (readonlycolumn의 경우에는 property가 필요 없지만 각 cell별로 수정이 가능한 테이블을 생성할 때는 column을 사용해야 하는데, 이때 property가 필요합니다.)
class Person(id: Int, name: String, birthday: LocalDate) {
var id by property(id)
var name by property(name)
var birthday by property(birthday)
val age: Int get() = Period.between(birthday, LocalDate.now()).years
}
private val persons = listOf(
Person(1, "Samantha Stuart", LocalDate.of(1981, 12, 4)),
Person(2, "Tom Marks", LocalDate.of(2001, 1, 23)),
Person(3, "Stuart Gills", LocalDate.of(1989, 5, 23)),
Person(4, "Nicole Williams", LocalDate.of(1998, 8, 11))
).asObservable()
class table_view: View(){
override val root = tableview(persons){
column("ID",Person::id).makeEditable()
column("Name", Person::name).makeEditable()
column("Birthday", Person::birthday).makeEditable()
readonlyColumn("Age",Person::age)
}
}
class table_app: App(table_view::class)
fun main() {
launch<table_app>()
}
이렇게 생성을 하면 처음에는 위의 결과와 같은 모습이 나오지만 항목을 클릭하여 수정을 할 수 있습니다.
그리고 property는 위의 방법 말고도
class Person(id: Int, name: String, birthday: LocalDate) {
var id by property(id)
fun idProperty() = getProperty(Person::id)
var name by property(name)
fun nameProperty() = getProperty(Person::name)
var birthday by property(birthday)
fun birthdayProperty() = getProperty(Person::birthday)
val age: Int get() = Period.between(birthday, LocalDate.now()).years
}
class table_view: View(){
override val root = tableview(persons){
column("ID",Person::idProperty).makeEditable()
column("Name", Person::nameProperty).makeEditable()
column("Birthday", Person::birthdayProperty).makeEditable()
readonlyColumn("Age",Person::age)
}
}
이런 방식과
class Person(id: Int, name: String, birthday: LocalDate) {
val idProperty = SimpleIntegerProperty(id)
var id by idProperty
val nameProperty = SimpleStringProperty(name)
var name by nameProperty
val birthdayProperty = SimpleObjectProperty(birthday)
var birthday by birthdayProperty
// Make age an observable value as well
val ageProperty = Period.between(birthdayProperty.get(), LocalDate.now()).years
}
class table_view: View(){
override val root = tableview(persons){
column("ID",Person::id).makeEditable()
column("Name", Person::name).makeEditable()
column("Birthday", Person::birthday).makeEditable()
readonlyColumn("Age",Person::ageProperty)
}
}
// or
class table_view: View(){
override val root = tableview(persons){
column("ID",Person::idProperty).makeEditable()
column("Name", Person::nameProperty).makeEditable()
column("Birthday", Person::birthdayProperty).makeEditable()
readonlyColumn("Age",Person::ageProperty)
}
}
또는
class Person(id: Int, name: String, birthday: LocalDate) {
val idProperty = SimpleIntegerProperty(id)
fun idPropertyfun() = idProperty
val nameProperty = SimpleStringProperty(name)
fun namePropertyfun() = nameProperty
val birthdayProperty = SimpleObjectProperty(birthday)
fun birthdayPropertyfun() = birthdayProperty
// Make age an observable value as well
val ageProperty =Period.between(birthdayProperty.get(), LocalDate.now()).years
}
class table_view: View(){
override val root = tableview(persons){
column("ID",Person::idPropertyfun).makeEditable()
column("Name", Person::namePropertyfun).makeEditable()
column("Birthday", Person::birthdayPropertyfun).makeEditable()
readonlyColumn("Age",Person::ageProperty)
}
}
로 적용할 수있습니다.
확장함수
makeEditable과 같은 확장 함수로 다음과 같은 확장 함수를 적용할 수 있는데, 이 확장 함수로 각 cell에 특성을 부여할 수 있습니다.
그리고 각 cell별로 format을 줄 수 있습니다.
readonlyColumn("Age",Person::ageProperty).cellFormat {
text = it.toString()
style {
if (it < 20) {
backgroundColor += c("#8b0000")
textFill = Color.WHITE
} else {
backgroundColor += Color.WHITE
textFill = Color.BLACK
}
}
}
이렇게 .cellFormat 후 블럭안에 적용을 하면 나이가 20 미만이 cell의 배경은 붉은 색이 되고, 나머지들은 배경이 흰색이 됩니다.
기능적 열값 생성 방법 (Declaring Column Values Functionally)
class table_view : View() {
override val root = tableview<WeeklyReport> {
for (dayOfWeek in DayOfWeek.values()) {
column<WeeklyReport, BigDecimal>(dayOfWeek.toString()) {
ReadOnlyObjectWrapper(it.value.getTotal(dayOfWeek))
}
}
}
}
abstract class WeeklyReport(val startDate: LocalDate) {
abstract fun getTotal(dayOfWeek: DayOfWeek): BigDecimal
}
class table_app : App(table_view::class)
fun main() {
launch<table_app>()
}
이렇게 생성을 하면 열 항목에 요일이 생성됩니다.
열 확장(Row Expanders)
class Region(val id: Int, val name: String, val country: String, val branches: ObservableList<Branch>)
class Branch(val id: Int, val facilityCode: String, val city: String, val stateProvince: String)
val regions = listOf(
Region(1,"Pacific Northwest", "USA",listOf(
Branch(1,"D","Seattle","WA"),
Branch(2,"W","Portland","OR")
).observable()),
Region(2,"Alberta", "Canada",listOf(
Branch(3,"W","Calgary","AB")
).observable()),
Region(3,"Midwest", "USA", listOf(
Branch(4,"D","Chicago","IL"),
Branch(5,"D","Frankfort","KY"),
Branch(6, "W","Indianapolis", "IN")
).observable())
).observable()
class row_expand_view: View(){
override val root = tableview (regions){
readonlyColumn("ID",Region::id)
readonlyColumn("Name", Region::name)
readonlyColumn("Country", Region::country)
rowExpander {
paddingLeft = expanderColumn.width
tableview(it.branches) {
readonlyColumn("ID",Branch::id)
readonlyColumn("Facility Code",Branch::facilityCode)
readonlyColumn("City",Branch::city)
readonlyColumn("State/Province",Branch::stateProvince)
}
}
}
}
class row_expand_app: App(row_expand_view::class)
fun main() {
launch<row_expand_app>()
}
이렇게 작성을 하면 다음과 같은 결과가 나타난다고 합니다.
그러나 현재 제 build 환경에서 어떤 문제가 있어서 빌드가 성공하지 못하고 있어 원인 파악 중입니다. (구글링 해보니 java 버전 문제라는데 아직 해결을 하지 못하였습니다.)
(rowExpander의 경우 Java JDK version 11로 동작 시키면 ClassNotFoundException이 발생하여 동작되지 않습니다. Java JDK version 8로 실행 하시는 것을 추천드립니다. 설정 방법은 제글 TornadoFX - Exception 문제에서 확인 하실 수도 있습니다.)
'2023년 이전 > kotlin-TornadoFx' 카테고리의 다른 글
TornadoFX - Exception 문제 (0) | 2019.10.11 |
---|---|
TornadoFx - Data Controls(2) (0) | 2019.10.11 |
TornadoFx - Builders for Basic Controls (0) | 2019.10.10 |
TornadoFx - How Builders Work (0) | 2019.10.10 |
TornadoFx - Accessing (0) | 2019.10.07 |