파이썬 프로그래밍 14주차 실습문제
tkinter와 파일처리를 배우고 전화번호부 프로그램을 만들었다.
※요구 사항
- PhoneBook.txt파일을 읽어와 그 내용을 튜플과 리스트로 출력
- 전화번호부 GUI
- 좌우 아이템 넘기기 버튼 기능
- 변동 아이템의 인덱스 번호
- 아이템 데이터 표시
- 수정버튼
- 추가 버튼
- 저장버튼: 변동내용(수정, 추가 등)이 파일에 저장되도록 만들기
내가 추가한 디테일
- 마지막 페이지에서 오른쪽버튼을 누르면 아이템추가를 위한 빈 창이 나오도록 함
- 첫번째 페이지에서 왼쪽버튼을 누르면 마지막 페이지로 이동
- GUI구성 수정
- 삭제 버튼 (20220808수정)
완성된 화면
※PhoneBook.txt파일 형식
이름1 전화번호1 직업1
이름2 전화번호2 직업2
이름3 전화번호3 직업3
※구현할 코드
- PhoneBook.txt파일에 있는 아이템 읽어와서 리스트에 저장하는 함수
- 리스트에 있는 값들 인덱스에 맞게 Entry칸에 적는 함수
- left, right버튼 누르면 페이지가 넘어가는 것처럼 보여지게 하는 함수
- 저장버튼, 추가버튼, 삭제버튼 기능
- tkinter활용해서 GUI만들기
- read함수
def read(): global words global wordlist global person_num #PhoneBook의 내용을 리스트에 초기화, 저장 infile = open("PhoneBook.txt", "r", encoding='UTF-8') wordlist =[] person_num = [] for line in infile: #한줄씩 읽어오기 line = line.rstrip() #\n기호 삭제하고 읽어오기 words = line.split() #공백문자로 단어들 분리 t= tuple(words) person_num.append(t) for word in words: #분리된 단어 wordlist에 저장 wordlist.append(word) infile.close()
infile에서 한줄씩 line으로 읽어온 다음['이름1', '전화1', '직장1'] 의 형태로 words에 저장한다. 이 words한줄을 튜플로 만들고 person_num리스트에 저장한다.
person_num은 [('이름1', '전화1', '직장1'), ('이름2', '전화2', '직장2'), ('이름3', '전화3', '직장3'), ('이름4', '전화4', '직장4'), ('이름5', '전화5', '직장5'), ('이름6', '전화6', '직장6')] 의 형태로 이 리스트의 길이는 PhoneBook에 저장된 사람 수가 된다. 이 리스트로 인덱스를 표시한다.
- per함수
def per(num): initialization() nameEntry.insert(END, wordlist[num*3-3]) callEntry.insert(END, wordlist[num*3-2]) jobEntry.insert(END, wordlist[num*3-1]) index.config(text ="%s/%s" %(page, len(person_num)))
read함수로 읽어와서 wordlist에 저장된 아이템들은 num*3-3, num*3-2, num*3-1이 num번째 사람의 이름, num번째 사람의 전화번호, num번째 사람의 직장이 되어서 entry칸에 넣어주었다.
- right&left 함수
def left(): global page if page == 1: page = len(person_num) per(page) else: page -=1 per(page) def right(): global page if page >= len(person_num): plus() else: page += 1 per(page)
왼쪽, 오른쪽 버튼을 눌렀을 때, 페이지가 넘어가는 것처럼 보이기 위해 page변수에 따라 보여지는 사람의 정보가 바뀌게 하였다. 즉, page == 인덱스 번호 , page=3 == 3번째 사람의 정보가 나타나는 페이지 이다.
per함수는 매개변수로 받은 숫자번째에 있는 사람의 정보를 entry칸에 입력해 나타나게하는 함수이다.
왼쪽 버튼을 누르면 page가 1감소한걸 저장하고 per(page)가 page-1의 번째의 사람의 정보를 보여준다. 똑같은 논리로 오른쪽도 적용했다.
- save함수
def save(): #각 entry칸 에 있는 값들을 변수로 저장 newName = nameEntry.get() newCall = callEntry.get() newJob = jobEntry.get() #텍스트파일 형식을 변수로 저장하여 맞춰주고 파일에 추가로 저장 new = '\n' + newName + ' ' + newCall + ' ' + newJob with open("PhoneBook.txt", "a", encoding='UTF-8') as infile: infile.write(str(new)) read() per(page)
entry칸을 직접 수정하고 저장하기 버튼을 눌렀을때 파일에도 저장하게 해주는 함수이다.
수정된 내용이 바로 가시적으로 보이게 하기 위해(인덱스 업데이트) 마지막에 per(page)를 넣어주었다.
- delete함수
def delete(): global wordlist global page wordlist.remove(wordlist[page*3-1]) wordlist.remove(wordlist[page*3-2]) wordlist.remove(wordlist[page*3-3]) with open("PhoneBook.txt", "w", encoding='UTF-8') as infile: for i in range(0, len(wordlist), 3): if i ==0: inputlist = wordlist[i] + ' ' + wordlist[i+1] + ' ' + wordlist[i+2] infile.write(str(inputlist)) else: inputlist = '\n' + wordlist[i] + ' ' + wordlist[i+1] + ' ' + wordlist[i+2] infile.write(str(inputlist)) read() per(page)
기말고사 시험에 나온 부분 .. 너무 정신이없어서 뭐가 잘못된건지도 모르고 그냥 무지성제출눌러버림
일단 worldlist에서 아이템을 삭제한 다음 현재페이지의 내용이 삭제된wordlist의 내용을 그대로 파일에 써서 다시 read함수를 써서 읽는 과정으로 코드를 짯다.(구조를 더 단순하게 만들수 있으면 좋겠다)
근데 문제는 삭제하고 현재의 per(page)자리에 right()함수를 써서 버튼을 눌렀을때 삭제된 페이지의 인덱스가 1씩 늘어났다 .. 그 부분을 수정하였다 .
코드전체
from tkinter import*
global page
page = 1
def delete():
global wordlist
global page
wordlist.remove(wordlist[page*3-1])
wordlist.remove(wordlist[page*3-2])
wordlist.remove(wordlist[page*3-3])
with open("PhoneBook.txt", "w", encoding='UTF-8') as infile:
for i in range(0, len(wordlist), 3):
if i ==0:
inputlist = wordlist[i] + ' ' + wordlist[i+1] + ' ' + wordlist[i+2]
infile.write(str(inputlist))
else:
inputlist = '\n' + wordlist[i] + ' ' + wordlist[i+1] + ' ' + wordlist[i+2]
infile.write(str(inputlist))
read()
per(page)
def read():
global words
global wordlist
global person_num
infile = open("PhoneBook.txt", "r", encoding='UTF-8')
wordlist =[]
person_num = []
for line in infile: #한줄씩 읽어오기
line = line.rstrip() #\n기호 삭제하고 읽어오기
words = line.split() #공백문자로 단어들 분리
t= tuple(words)
person_num.append(t)
for word in words: #분리된 단어 wordlist에 저장
wordlist.append(word)
infile.close()
def save():
newName = nameEntry.get()
newCall = callEntry.get()
newJob = jobEntry.get()
new = '\n' + newName + ' ' + newCall + ' ' + newJob
with open("PhoneBook.txt", "a", encoding='UTF-8') as infile:
infile.write(str(new))
read()
per(page)
def plus():
global page
page =len(person_num)+1
index.config(text ="%s/%s" %(page, page))
initialization()
def initialization():
nameEntry.delete(0, END)
callEntry.delete(0, END)
jobEntry.delete(0, END)
def per(num):
initialization()
nameEntry.insert(END, wordlist[num*3-3])
callEntry.insert(END, wordlist[num*3-2])
jobEntry.insert(END, wordlist[num*3-1])
index.config(text ="%s/%s" %(page, len(person_num)))
def left():
global page
if page == 1:
page = len(person_num)
per(page)
else:
page -=1
per(page)
def right():
global page
if page >= len(person_num):
plus()
else:
page += 1
per(page)
window = Tk()
name = Label(window, text = "이름")
name.grid(row = 0, column = 1)
call = Label(window, text = "전화번호")
call.grid(row = 1, column = 1)
job= Label(window, text = "직장")
job.grid(row = 2, column = 1)
nameEntry = Entry(window)
nameEntry.grid(row = 0, column = 2, columnspan=2)
callEntry = Entry(window)
callEntry.grid(row = 1, column = 2, columnspan=2)
jobEntry = Entry(window)
jobEntry.grid(row = 2, column = 2, columnspan=2)
leftButton = Button(window, text = "<", padx=5, pady=5, command=left)
leftButton.grid(row = 1, column = 0, padx=20)
rightButton = Button(window, text = ">", padx=5, pady=5, command=right)
rightButton.grid(row = 1, column = 4, padx=20)
index = Label(window)
index.grid(row = 4, column = 1, columnspan=3)
saveButton = Button(window, text="삭제하기", command=delete)
saveButton.grid(row = 3, column = 1)
saveButton = Button(window, text="저장하기", command=save)
saveButton.grid(row = 3, column = 2)
plusButton = Button(window, text="추가하기", command=plus)
plusButton.grid(row = 3, column = 3)
read()
per(1)
보완, 추가해야 할 점
- 텍스트파일에서 이름이나 직장에 띄어쓰기를 사용하지 못한다.
- 삭제하기 버튼의 비효율성
- wordlist 리스트에서 불러올때 wordlist[num*3-2]란 식으로 구분해 적어서 아이템을 쉽게 알아볼수 없고 헷갈린다.
- name, number, job의 리스트를 따로 만들어 name[num]의 형태로도 코드를 짤 수 있는지 시도해봐야겠다.
배운 점, 느낀 점
파이썬에서 버튼을 누르면 다음사람의 아이템이 적혀있는 페이지가 나오도록 어떻게 구현을 해야하나 고민을 하였는데 넘길 수 있는 페이지 자체를 구현한다는 생각보다는 페이지처럼 보여지게 구현해야겠다는 생각이 떠올랐다.
처음 막연히 생각나는 것부터 코드를 써가니 중복되는 코드가 많고 난잡했다. 중복되는 코드를 함수로 만들고 변수를 사용하여 정리하다보니 구조를 논리적으로 파악할 수 있었다.
다음부터는 무작정 코드를 짜기전에 전체적으로 필요한 함수를 생각하고, 틀을 먼저 구상하는 등의 준비를 하고 코드를 작성해나가야 겠다는 생각이 들었다.
'학교생활!' 카테고리의 다른 글
[230414] 자료구조 과제4: LinkedList클래스 (0) | 2023.04.17 |
---|---|
[230325]컴퓨터 구조: Bit-Level Representations and Manipulations in C (0) | 2023.04.07 |
[230402]고급C++프로그래밍: 구조체 과제 (0) | 2023.04.07 |
[230330]자료구조 과제3: Print (0) | 2023.04.02 |
[230325]자료구조 과제2: BankAccount (1) | 2023.03.25 |