고급자바프로그래밍 프로젝트 과제
나는 gui를 활용한 캘린더를 만들기로 하였다.
완성된 화면
※구현
- 1. 달력화면 만들기
- 2. 달력 넘기기 구현
- 3. 저장, 로드 구현하기
- 4. 배경색 바꾸는 버튼 구현
코드전체
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;
public class My_Calendar extends JFrame {
private JFrame frame;
private JPanel calendarPanel;
private JButton saveButton;
private JButton loadButton;
private JButton prevButton;
private JButton nextButton;
private JLabel dateLabel;
//private String folderPath = "src/calendar/";
private String[] daysOfWeek = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
private JPanel[] datePanel = new JPanel[32];
private JTextArea[] scheduleArea = new JTextArea[32];
private Calendar calendar;
private LocalDate currtentDate = LocalDate.now();
private JButton[] btnR = new JButton[32];
private JButton[] btnG = new JButton[32];
private JButton[] btnB = new JButton[32];
private JButton[] btnW = new JButton[32];
private String[] ColorList = new String[32];
private static Map<String, Color> ColorTable = new HashMap<>();
public My_Calendar() {
ColorTable.put("WHITE", Color.decode("#FFFFFF"));
ColorTable.put("RED", Color.decode("#FCACAC"));
ColorTable.put("GREEN", Color.decode("#98FB98"));
ColorTable.put("BLUE", Color.decode("#87CEFA"));
frame = new JFrame("myCalendar");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1500, 1000);
JPanel topPanel = new JPanel();
JPanel infoCenterPanel = new JPanel();
JPanel infoMenuPanel = new JPanel();
//infoCenterPanel
dateLabel = new JLabel();
prevButton = new JButton("<");
prevButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
saveButton.doClick();
calendar.add(Calendar.MONTH, -1); //calendar날자를 이전달으로 설정
updateCalendar(calendar.getTime());
loadButton.doClick();
}
});
nextButton = new JButton(">");
nextButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
saveButton.doClick();
calendar.add(Calendar.MONTH, 1); //calendar날자를 다음달 으로 설정
updateCalendar(calendar.getTime());
loadButton.doClick();
}
});
infoCenterPanel.add(prevButton);
infoCenterPanel.add(dateLabel);
infoCenterPanel.add(nextButton);
//infoMenuPanel
saveButton = new JButton("Save");
saveButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
File directory = new File(Paths.get("").toAbsolutePath() + "/CalendarDate"); //프로젝트가 저장된 상대경로에 CalendarDate디렉토리를 만듦
if (!directory.exists()) directory.mkdir();
File file = new File(directory, calendar.get(Calendar.YEAR) + "_" + (calendar.get(Calendar.MONTH) + 1) + ".txt");
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
for (int i = 1; i <= calendar.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {
writer.write(
i + "\n" +
ColorList[i] + "\n" +
scheduleArea[i].getText() + "\n");
}
writer.write("-1"); //마지막날자의 반복문을 끝내기 위한 넘버
writer.close();
//JOptionPane.showMessageDialog(frame, "파일이 성공적으로 저장되었습니다.", "Success", JOptionPane.INFORMATION_MESSAGE);
} catch (IOException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(frame, "파일열기에 실패하였습니다.\n파일명을 확인해주세요.", "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
loadButton = new JButton("load");
loadButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
File directory = new File(Paths.get("").toAbsolutePath() + "/CalendarDate");
File file = new File(directory, calendar.get(Calendar.YEAR) + "_" + (calendar.get(Calendar.MONTH) + 1) + ".txt");
if (file.exists()) { //저장한 적이 있는 달의 내용을 불러온다
BufferedReader reader = new BufferedReader(new FileReader(file));
String text = reader.readLine(); //맨 처음 적힌 숫자 1을 읽는다.
for (int i = 1; i<=calendar.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {
text = reader.readLine(); //배경 색상 읽기
clickColorButton(i, text); //날자랑, 색상을 사용하여 ColorButton을 클릭한다
while (true) {
text = reader.readLine();
if (isNumberic(text)) break; //읽은 값이 숫자라면 다음 날자로 넘어감
if (!text.equals("")) scheduleArea[i].append(text+"\n"); //읽은값이 String형식 이라면 날자 칸에 데이터를 추가함
}
}
reader.close();
}
} catch (IOException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(frame, "파일 읽기 오류", "Error", JOptionPane.ERROR_MESSAGE);
} catch (ArrayIndexOutOfBoundsException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(frame, "파일 형식 오류", "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
infoMenuPanel.add(saveButton);
infoMenuPanel.add(loadButton);
JPanel infoPanel = new JPanel(new BorderLayout());
infoPanel.add(infoCenterPanel, BorderLayout.CENTER);
infoPanel.add(infoMenuPanel, BorderLayout.EAST);
JPanel weekPanel = new JPanel(new GridLayout(1, 7));
for (String dayOfWeek : daysOfWeek) {
weekPanel.add(new JLabel(dayOfWeek, SwingConstants.CENTER)); // 요일 레이블을 weekPanel에 추가
}
calendarPanel = new JPanel(new GridLayout(0, 7));
topPanel.setLayout(new BorderLayout());
topPanel.add(infoPanel, BorderLayout.NORTH);
topPanel.add(weekPanel, BorderLayout.SOUTH);
frame.add(topPanel, BorderLayout.NORTH);
frame.add(new JScrollPane(calendarPanel), BorderLayout.CENTER);
calendar = Calendar.getInstance();
calendar.setTime(new Date());
updateCalendar(calendar.getTime());
frame.setVisible(true);
loadButton.doClick();
}
private void CalendarClear() {
for (int i = 1; i < datePanel.length; i++) {
if (datePanel[i] != null) {
calendarPanel.remove(datePanel[i]);
datePanel[i] = null;
}
if (scheduleArea[i] != null) {
scheduleArea[i] = null;
}
}
calendarPanel.removeAll();
calendarPanel.revalidate();
calendarPanel.repaint();
}
private void updateCalendar(Date date) {
CalendarClear();
currtentDate = LocalDate.now(); //
SimpleDateFormat dateFormat;
if (currtentDate.getMonthValue() == (date.getMonth()+1) && currtentDate.getYear() == (date.getYear()+1900)) {
dateFormat = new SimpleDateFormat("yyyy년 MM월 dd일 E요일"); //현재 날자의 달력인 경우 (왜
}
else {
dateFormat = new SimpleDateFormat("yyyy년 MM월"); //다른 달의 달력이라면 년도와 월만 라벨에 출력
}
dateLabel.setText(dateFormat.format(date));
calendar.set(Calendar.DAY_OF_MONTH, 1); //일:1 월:2, 화:3, 수:4, 목:5, 금:6, 토:7
int firstDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); //달이 시작되는 요일을 저장
for (int i = 1; i < firstDayOfWeek; i++) {
calendarPanel.add(new JLabel("")); // 1일의 요일까지 빈칸을 채워넣는다
}
for (int i = 1; i <= calendar.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {
ColorList[i] = "White"; //ColorList를 흰색으로 초기화
calendarPanel.add(createDatePanel(i)); //
}
}
private JPanel createDatePanel(int date) {
datePanel[date] = new JPanel();
datePanel[date].setPreferredSize(new Dimension());
JPanel dateTop = new JPanel();
JPanel dateColor = new JPanel();
btnR[date] = CreateColorSetButton(date, "RED");
btnG[date] = CreateColorSetButton(date, "GREEN");
btnB[date] = CreateColorSetButton(date, "BLUE");
btnW[date] = CreateColorSetButton(date, "WHITE");
dateColor.add(btnR[date]);
dateColor.add(btnG[date]);
dateColor.add(btnB[date]);
dateColor.add(btnW[date]);
dateTop.add(new JLabel(date + ""), BorderLayout.WEST);
dateTop.add(dateColor, BorderLayout.EAST);
datePanel[date].add(dateTop, BorderLayout.NORTH);
scheduleArea[date] = new JTextArea(6, 21);
datePanel[date].add(scheduleArea[date], BorderLayout.CENTER);
return datePanel[date];
}
private boolean isNumberic(String s) {
try {
Double.parseDouble(s);
return true;
} catch (NumberFormatException e) {
return false;
}
}
public static void main(String[] args) {
new My_Calendar();
}
public JButton CreateColorSetButton(int date, String color) {
JButton btn = new JButton();
Dimension btnSize = new Dimension(10, 15);
btn.setPreferredSize(btnSize);
btn.setBackground(ColorTable.get(color));
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
scheduleArea[date].setBackground(ColorTable.get(color));
ColorList[date] = color;
}
});
return btn;
}
private void clickColorButton(int date, String color) {
switch (color) {
case "WHITE":
btnW[date].doClick();
break;
case "RED":
btnR[date].doClick();
break;
case "GREEN":
btnG[date].doClick();
break;
case "BLUE":
btnB[date].doClick();
break;
}
}
}
**코드설명(조잡함)
<MyCalendar(메인함수)>
-infoPanel오늘 날자를 표시하는 라벨, 달력 넘기는 버튼, save, load버튼 ->topPanel
-월~일 요일 라벨을 weekPanel에 붙임-> topPanel
-calendarPanel생성
-topPanel프레임 상단 / calendarPanel프레임 중앙
등 판넬생성, 프레임 설정
**calendar변수: 현재 달력의 날자에 맞게 Calendar날자를 업데이트 해주기 위한 변수
현재날자로 calendar를 업데이트해주고 시작한다. -> load버튼을 눌러 저장된 정보를 가져옴
calendar = Calendar.getInstance();
calendar.setTime(new Date());
updateCalendar(calendar.getTime());
frame.setVisible(true);
loadButton.doClick();
<달력화면 업데이트: updateCalendar()>
-원래 있던 달력을 지움
-상단의 오늘의 날자 업데이트(다른달의 달력이라면 그 달력에 맞는 날자) : dataLabel
currtentDate = LocalDate.now(); //
SimpleDateFormat dateFormat;
if (currtentDate.getMonthValue() == (date.getMonth()+1) && currtentDate.getYear() == (date.getYear()+1900)) {
dateFormat = new SimpleDateFormat("yyyy년 MM월 dd일 E요일"); //현재 날자의 달력인 경우 (왜
}
else {
dateFormat = new SimpleDateFormat("yyyy년 MM월"); //다른 달의 달력이라면 년도와 월만 라벨에 출력
}
dateLabel.setText(dateFormat.format(date));
-달력에 날자칸 집어넣기
1일이 시작되는 요일 전까지 빈 라벨을 집어넣는다.
calendar.set(Calendar.DAY_OF_MONTH, 1); //일:1 월:2, 화:3, 수:4, 목:5, 금:6, 토:7
int firstDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); //달이 시작되는 요일을 저장
for (int i = 1; i < firstDayOfWeek; i++) {
calendarPanel.add(new JLabel("")); // 1일의 요일까지 빈칸을 채워넣는다
}
1일부터 현재 달의 마지막 날 까지 날자 칸(datePanel)을 집어넣는다.
for (int i = 1; i <= calendar.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {
ColorList[i] = "White"; //ColorList를 흰색으로 초기화
calendarPanel.add(createDatePanel(i)); //
}
<날자 칸 생성: createDatePanel()>
-datePanel(dateTop, 일정 입력 창TextArea), dateTop(날자, 색상 변경 버튼), 색상 변경 버튼(빨, 초, 파, 흰) 생성
Label에 매개변수로 받은 날자를 집어넣고 요소들을 추가해 datePanel반환
<날자칸의 배경색 변경: CreateColorSetButton>
버튼 생성->버튼의 크기와 배경 색 변경
버튼 클릭액션: 매개변수로 받은 날자와 색상으로 날자칸의 배경을 변경한다.
배경색을 변경한 뒤, ColorList를 업데이트 해준다.
* Map<String, Color> ColorTable : 색상이름으로 색상코드를 저장해두고 사용함
<Save>
-프로젝트가 저장된 상대경로에 CalendarDate디렉토리를 만든다.
File directory = new File(Paths.get("").toAbsolutePath() + "/CalendarDate");
if (!directory.exists()) directory.mkdir();
-저장하기 전, 경로에 현재 날자의 데이터가 있는지 확인 하고, 없다면 새로운 파일을 만든다.
-파일명은 현재 달력(calendar)의 정보를 사용한다.
-파일에 날자, 칸의 배경 색, 날자 칸(ScheduleArea)의 일정데이터를 차례대로 한줄 씩 쓴다.
1
WHITE
일정1
일정2
<Load>
-현재 달력의 정보(calendar)를 사용하여 파일을 찾고 불러온다
-1부터 현재달력의 마지막 날까지 쓰기반복
String text = reader.readLine(); //맨 처음 적힌 숫자 1을 읽는다.
for (int i = 1; i<=calendar.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {
text = reader.readLine(); //배경 색상 읽기
clickColorButton(i, text); //날자랑, 색상을 사용하여 ColorButton을 클릭한다
while (true) {
text = reader.readLine();
if (isNumberic(text)) break; //읽은 값이 숫자라면 다음 날자로 넘어감
if (!text.equals("")) scheduleArea[i].append(text+"\n"); //읽은값이 String형식 이라면 날자 칸에 데이터를 추가함
}
}
-ArrayIndexOutOfBoundsException 오류가나는 경우(scheduleArea[i])에 쓰지 못하기 때문에 발생)-> 파일 형식 오류
} catch (IOException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(frame, "파일 읽기 오류", "Error", JOptionPane.ERROR_MESSAGE);
} catch (ArrayIndexOutOfBoundsException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(frame, "파일 형식 오류", "Error", JOptionPane.ERROR_MESSAGE);
}
<다음 달(next), 이전 달(prev) 버튼>
-달력을 넘기기 전에 현재 달력의 정보 저장 saveButton.doClick();
calendar.add(Calendar.MONTH, 1);
updateCalendar(calendar.getTime());
-> calendar변수를 다음달로 바꿈 (이전달: -1)
->바꾼 calendar값으로 캘린더 업데이트
-달력을 넘긴 후 laod버튼으로 넘긴 달의 정보 불러오기 loadButton.doClick();
개선할점
-일정 체크박스(-> textArea의 기능으로는 하루 일정이 다 끝나면 그 날 전체에 취소선을 긋는 방법을 사용할 수 있지않을까)
-맨 위 현재날자를 알려주는 dateLabel이 다른달로 넘어 갔다가 현재 달로 넘어오면 날자가 1일으로 고정됨 (대체왜??ㅠ)
-달력 넘길때 딜레이
'학교생활!' 카테고리의 다른 글
[231111] 고급 자료구조 과제3: 그래프 (1) | 2023.11.15 |
---|---|
[231104] 고급 자바프로그래밍 과제: Puzzle (1) | 2023.11.13 |
[230602] 자료구조 과제6: 연결 리스트와 힙 (0) | 2023.07.11 |
[230520] 고급C++프로그래밍: 과제3 (0) | 2023.05.31 |
[230503] 자료구조 과제5: 순환(recursion) (0) | 2023.05.07 |