티스토리 뷰
들어가며
- 이전에 썼던 글인 JavaFX TableView 사용법 이 시간이 지나서 보니 조금 설명이 허접한 것 같기도 하고.. 리뉴얼이 필요할 것 같았다.
- 원본 소스는 아래 위치에 있습니다.
TableView
-
TableView
데이터를 Row과, Column형태로 시각화하도록 설계된 컨트롤이다.- 얼핏보면 ListView와 비슷하지만 Column이 추가되었다는 점에서 다름
-
TableView
의 특징- 강력한
TableColumn
API를 제공함 (TableColumn
은 아래에서 자세하게 설명하도록 하겠음)- Cell을 쉽게 customize할 수 있는 Cell Factory들을 제공함 (Cell은 TableView의 한 칸이라고 보면 될 것 같음)
- minWidth / prefWidth / maxWidth 및 fixed width를 Column에 적용 가능함
- 런타임시에 리사이징이 가능함
- 런타임시에 Column 렌더링이 가능함
- Column 중첩을 지원함
- 사용자가 Column 크기를 조정할 때 발생하는 UI 동작에 대한 다양한 리사이징 정책이 있음
- Column Header를 클릭했을 때 다양한 데이터 정렬을 지원함 (여러 열을 한번에 정렬하기 위해서는 Shift를 누른채로 클릭하길)
- 강력한
-
TableView
는 데이터를 시각화하기 위한 의도로 만들어진 컨트롤이다.- 사용자 인터페이스를 배치하는 데 사용되지 않음
- 만약 Grid 형태로 사용자 인터페이스를 배치하고자 한다면
GridPane
레이아웃 사용을 고려해보길
-
설명은 했지만 잘 이해가 안될 수도 있다. 아마 사용하다 보면 이해가 될 것이다.
TableColumn
-
TableView
는 다수의TableColumn
으로 이루어져 있다. -
TableColumn
은 단일 열에 대한 데이터를 표시하고 편집하며 이에 필요한 속성도 포함한다.- 크기 조정 (
minWidth / prefWidth / maxWidth
및 width 속성 사용) - visibility 전환
- Header Text 전시
- 중첩 Column이 포함된 경우 표시
- Column 우클릭 시 전시되는 메뉴
- 테이블의 내용 정렬
- 크기 조정 (
-
TableColumn
을 생성할 때 가장 중요한 속성 두 가지는- Column Header에 표시될 Text를 정의하는 것
ObservableList<Person> data = ... TableView<Person> tableView = new TableView<Person>(data);
- Column의 cell value factory를 정의하는 것
TableColumn<Person,String> firstNameCol = new TableColumn<Person,String>("First Name"); firstNameCol.setCellValueFactory(new Callback<CellDataFeatures<Person, String>, ObservableValue<String>>() { public ObservableValue<String> call(CellDataFeatures<Person, String> p) { // p.getValue() returns the Person instance for a particular TableView row return p.getValue().firstNameProperty(); } });
- 이 코드에서 중요한 부분은
p.getValue().firstNameProperty()
임- p.getValue()는
Person
인스턴스인데firstNameProperty()
는 아마String
을 감싸고 있는StringProperty
일 것임
- p.getValue()는
- 이 코드의 이점은 외부에 있을
Person
인스턴스의firstName
값이 변경되면 자동으로 TableView의 해당 Cell의 데이터도 같이 변경된다는 것임- 그 이유는
StringProperty
가 TableView에 바인딩이 되어 감싸고 있는 값이 바뀌면 바인딩이 된 TableView에도 값이 바뀌는 것임
- 그 이유는
- 이 코드에서 중요한 부분은
- Column Header에 표시될 Text를 정의하는 것
TableView 만들어보기
- 지루한 설명이 끝났다. 이제 직접 한번 만들어보자
1. FXML
Table.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<fx:root style="-fx-background-color: #A2A5AC;" type="AnchorPane" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" stylesheets="@../../fx.css" prefWidth="800">
<TableView fx:id="tableView" focusTraversable="false" AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="20.0">
<placeholder><Label text="No Content" /></placeholder>
</TableView>
</fx:root>
2. Data 클래스
- TableView에 전시될 Data 클래스를 만들어보자.
TableData.java
public class TableData {
private String id;
private ZonedDateTime dateTime;
private String content;
private boolean isButtonVisible;
public TableData(String id, ZonedDateTime dateTime, String content, boolean isButtonVisible) {
... 생략 ...
}
public String getId() { return id;}
public ZonedDateTime getDateTime() { return dateTime; }
public String getContent() { return content; }
public boolean isButtonVisible() { return isButtonVisible; }
}
- 만약 데이터가 변경되었을 때 TableView에도 적용되길 원한다면 Property로 이루어진 아래 코드를 쓰자.
TableDataWithProperty.java
public class TableDataWithProperty {
private StringProperty id;
private ObjectProperty<ZonedDateTime> dateTime;
private StringProperty content;
private BooleanProperty isButtonVisible;
public TableDataWithProperty(StringProperty id, ObjectProperty<ZonedDateTime> dateTime, StringProperty content, BooleanProperty isButtonVisible) {
this.id = id;
this.dateTime = dateTime;
this.content = content;
this.isButtonVisible = isButtonVisible;
}
public TableDataWithProperty(String id, ZonedDateTime dateTime, String content, boolean isButtonVisible) {
this.id.set(id);
this.dateTime.set(dateTime);
this.content.set(content);
this.isButtonVisible.set(isButtonVisible);
}
public StringProperty idProperty() { return id;}
public ObjectProperty<ZonedDateTime> dateTimeProperty() { return dateTime; }
public StringProperty contentProperty() { return content; }
public BooleanProperty isButtonVisibleProperty() { return isButtonVisible; }
}
3. Display 클래스
- 이 클래스는 TableView에 Display되는 기능을 담당하기 위해 분리된 클래스이다.
- 쉽게 말해서 TableColumn을 정의하기 위한 클래스로 알아두면 좋을 것 같음
- 아래 코드의 형태는 TableColumn을 정의한 뒤에 TableView에 Data가 삽입되었을 때 Data의 어떤 값을 Column에 전시할 것인지를 정의한다.
DisplayTableData.java
public class DisplayTableData {
public TableColumn[] getColumns() {
// ID 칼럼
final TableColumn<TableData, String> idColumn = new TableColumn<>("ID");
idColumn.setCellValueFactory(item -> new ReadOnlyStringWrapper(item.getValue().getId()));
idColumn.setPrefWidth(40);
//Content 칼럼
final TableColumn<TableData, String> contentColumn = new TableColumn<>("Content");
contentColumn.setCellValueFactory(item -> new ReadOnlyStringWrapper(item.getValue().getContent()));
contentColumn.setPrefWidth(10);
//DateTime 칼럼
final TableColumn<TableData, String> dateTimeColumn = new TableColumn<>("DateTime");
dateTimeColumn.setCellValueFactory(item -> new ReadOnlyStringWrapper(
//ZonedDateTime Formatting 하여 전시 (예: 2020-02-01 13:00:11.22)
item.getValue().getDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))));
dateTimeColumn.setPrefWidth(220);
//Action 칼럼`
final TableColumn<TableData, Boolean> actionColumn = new TableColumn<>("Action");
actionColumn.setCellValueFactory(item -> new ReadOnlyBooleanWrapper(item.getValue().isButtonVisible()));
actionColumn.setCellFactory(item -> new TableCell<TableData, Boolean>() {
@Override
protected void updateItem(Boolean isButtonVisible, boolean empty) {
super.updateItem(isButtonVisible, empty);
if (!empty && isButtonVisible) {
Button actionButton = new Button("Action");
actionButton.setOnAction(event -> {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.getDialogPane().setPrefWidth(200);
alert.setTitle("Test");
alert.setHeaderText("Action button clicked!");
alert.showAndWait();
});
setGraphic(actionButton);
}
}
});
contentColumn.setPrefWidth(200);
return new TableColumn[]{idColumn, contentColumn, dateTimeColumn, actionColumn};
}
}
- 만약 TableDataWithProperty를 사용했다면 아래 코드 참고
DisplayTableDataWithProperty.java
public class DisplayTableDataWithProperty {
public TableColumn[] getColumns() {
// ID 칼럼
final TableColumn<TableDataWithProperty, String> idColumn = new TableColumn<>("ID");
idColumn.setCellValueFactory(item -> item.getValue().idProperty());
idColumn.setPrefWidth(40);
//Content 칼럼
final TableColumn<TableDataWithProperty, String> contentColumn = new TableColumn<>("Content");
idColumn.setCellValueFactory(item -> item.getValue().contentProperty());
contentColumn.setPrefWidth(10);
//DateTime 칼럼
final TableColumn<TableDataWithProperty, ZonedDateTime> dateTimeColumn = new TableColumn<>("DateTime");
dateTimeColumn.setCellValueFactory(item -> item.getValue().dateTimeProperty());
dateTimeColumn.setCellFactory(col -> new TableCell<TableDataWithProperty, ZonedDateTime>() {
@Override
protected void updateItem(ZonedDateTime item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
setText(item.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));
}
}
});
dateTimeColumn.setPrefWidth(220);
//Action 칼럼`
final TableColumn<TableDataWithProperty, Boolean> actionColumn = new TableColumn<>("Action");
actionColumn.setCellValueFactory(item -> item.getValue().isButtonVisibleProperty());
actionColumn.setCellFactory(item -> new TableCell<TableDataWithProperty, Boolean>() {
@Override
protected void updateItem(Boolean isButtonVisible, boolean empty) {
super.updateItem(isButtonVisible, empty);
if (!empty && isButtonVisible) {
Button actionButton = new Button("Action");
actionButton.setOnAction(event -> {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.getDialogPane().setPrefWidth(200);
alert.setTitle("Test");
alert.setHeaderText("Action button clicked!");
alert.showAndWait();
});
setGraphic(actionButton);
}
}
});
contentColumn.setPrefWidth(200);
return new TableColumn[]{idColumn, contentColumn, dateTimeColumn, actionColumn};
}
}
4. TableController 클래스
- Display클래스를 통해서 TableColumn을 세팅하고 Data를 받아 TableView에 전시하는 형태이다.
- FxUtil.loadFxml(this)는 FXML 파일을 로딩하는 코드를 Util 클래스로 분리한 것으로 이 곳을 참고
TableController.java
public class TableController extends AnchorPane {
@FXML
private TableView<TableData> tableView;
public TableController(List<TableData> tableDataList) {
FxUtil.loadFxml(this);
tableView.getColumns().setAll(new DisplayTableData().getColumns());
tableView.getItems().setAll(tableDataList);
}
}
5. Test 클래스
TableTest.java
public class TableTest extends Application {
@Test
public void test() {
launch();
}
private List<TableData> generateTableData() {
List<TableData> tableDataList = new ArrayList<>();
tableDataList.add(new TableData("1", ZonedDateTime.now().minusSeconds(1), "I'm 1", true));
tableDataList.add(new TableData("2", ZonedDateTime.now().minusSeconds(2), "I'm 2", false));
tableDataList.add(new TableData("3", ZonedDateTime.now().minusSeconds(3), "I'm 3", true));
tableDataList.add(new TableData("4", ZonedDateTime.now().minusSeconds(4), "I'm 4", false));
tableDataList.add(new TableData("5", ZonedDateTime.now().minusSeconds(5), "I'm 5", true));
tableDataList.add(new TableData("6", ZonedDateTime.now().minusSeconds(6), "I'm 6", true));
tableDataList.add(new TableData("7", ZonedDateTime.now().minusSeconds(7), "I'm 7", false));
tableDataList.add(new TableData("8", ZonedDateTime.now().minusSeconds(8), "I'm 8", false));
tableDataList.add(new TableData("9", ZonedDateTime.now().minusSeconds(9), "I'm 9", true));
return tableDataList;
}
@Override
public void start(Stage primaryStage) throws IOException {
TableController controller = new TableController(generateTableData());
primaryStage.setScene(new Scene(controller));
primaryStage.setTitle("Table Test");
primaryStage.show();
}
}
결과
- TableView가 전시되는 것을 볼 수 있다. (
디자인은 신경쓰지 않겠다)
- Action 버튼을 클릭하면 Alert이 잘 전시되는 것을 볼 수 있다.
관련 글
끝으로
이 글이 도움이 되었다면, 하단의 Google 광고 👎👎👎 한번씩 클릭 부탁 드립니다. 🙏🙏🙏
광고 클릭은 많은 힘이 됩니다!
반응형
'프로그래밍 > JavaFX' 카테고리의 다른 글
[JavaFX] Window Close(X 버튼 클릭) 시에 Application 종료 방법 (프로세스 종료) (0) | 2020.04.29 |
---|---|
[JavaFX] Chart 사용시 메모리 누수 문제 해결방법 (0) | 2020.04.29 |
[JavaFX] JavaFX UI Test Code 작성 방법 (0) | 2020.03.14 |
[JavaFX] 실시간 업데이트 되는 Timer(시계) 컨트롤 구현 방법 (0) | 2020.03.14 |
(JavaFX) FXML 작성 시 "<fx:root>" 를 사용하는 이유 (0) | 2020.02.27 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- JavaFX Window Close
- 배낭여행
- 일본여행
- intelij
- 배낭 여행
- 일본 여행
- git
- 이펙티브
- windows
- 텐트
- springboot
- effective java
- 자전거 여행
- 일본 자전거 여행
- 스프링부트
- TableView
- 자전거
- JavaFX
- JavaFX Table View
- Java UI
- JavaFX 종료
- 인텔리제이
- 이펙티브자바
- 방통대 과제물
- 자바
- 이펙티브 자바
- 일본 배낭여행
- JavaFX 테이블뷰
- effectivejava
- java
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함