View
2
Download
0
Category
Preview:
Citation preview
순천향대학교 컴퓨터공학과 1
7. 파이썬 GUI 응용: GUI 채팅 프로그래밍
순천향대학교 컴퓨터공학과
이 상 정
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
학습 내용
GUI 채팅 프로그램• GUI 기반 채팅 프로그램
• 클라이언트와 서버가 하나의 프로그램
• 참조 사이트Python Chat Programhttps://github.com/chprice/Python-Chat-Program
새로이 소개되는 파이썬 언어 기능• 새로운 위젯: 프레임/Toplevel, 스크롤바, 메뉴
• 이벤트와 바인딩
• 파일 대화상자
• 클래스 기반 스레드 생성
• 람다 함수 (lambda function)
순천향대학교 컴퓨터공학과 2
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
프레임/Topleve 위젯 (Frame Widget)
프레임 위젯은 다른 위젯을 포함(그룹화)하는 사각형 영역
• fr = Frame(app)
프레임 위젯에 버튼, Label 위젯 포함 예
app = Tk() # 윈도우 생성
fr = Frame(app) # 프레임 생성
Label(fr, text="Frame Label").pack() # Label 생성
Button(fr, text="frame test").pack() # Button 생성
Toplevel 위젯
• 프레임 위젯과 유사하나 윈도우가 부모 윈도우와 독립적으로 표시
순천향대학교 컴퓨터공학과 3
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
스크롤바 위젯 (Scrollbar Widget)
스크롤바 생성• sb = Scrollbar(app)
sb.pack(side=RIGHT, fill=Y)
• 오른쪽에 표시, 윈도우의 세로 방향에 채움
• fill 속성은 위젯을 공간(윈도우, 프레임) 전체에 채움을 표시
– 가로 채움 X, 세로 채움 Y, 모두 채움 BOTH
스크롤바는 다른 위젯(Text, ListBox, Canvas)과 연동하여동작• 텍스트 위젯과 연동 예
txt = Text(app) # 텍스트 위젯 생성sb.config(command=txt.yview)
# 스크롤바에 텍스트 위젯의 세로 방향 연동 지정txt.config(yscrollcommand=sb.set)
# 텍스트 위젯에 스크롤바 위젯의 세로 방향 연동 지정
순천향대학교 컴퓨터공학과 4
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
이벤트와 바인딩 (Event and Binding)
GUI 프로그래밍은 이벤트 구동(event-driven) 방식 동작• 이벤트 루프에서 이벤트 기다림
이벤트 바인딩 (Binding)• 위젯의 이벤트를 사용자가 지정
• 이벤트와 이벤트 처리 함수 지정
• 이벤트 객체 인수 전달
• 모든 위젯은 bind 메서드를 사용하여 이벤트 처리 지정
• 엔트리 위젯에 리턴 키 누른 경우 dispalyText 함수 실행 예text_input = Entry(root, width=60) # 60 텍스트text_input.bind("<Return>", printText) # <Return> 이벤트 처리 지정text_input.pack()
def printText(event): # 이벤트 처리 함수, event 객체 인수
.....
순천향대학교 컴퓨터공학과 5
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
바인딩 이벤트 – 마우스
마우스 버튼 이벤트• <Button-1>, <Button-2> <Button-2>
• 마우스 버튼 클릭 이벤트 / 1 왼쪽 2 중간 3 오른쪽 버튼
• 위치 정보는 event 객체의 x, y 속성
• <B1-Motion>, <B2-Motion>, <B3-Motion>
• 마우스 버튼 드래그 (drag) 이벤트
• 위치 정보는 event 객체의 x, y 속성
• <ButtonRelease-1>, <ButtonRelease-2>, <ButtonRelease-3>
• 마우스 버튼 누름 해제 이벤트
• 위치 정보는 event 객체의 x, y 속성
• <Double-Button-1>, <Double-Button-2>, <Double-Button-3>
• 마우스 버튼 더블 클릭 이벤트
• <Enter> : 마우스 포인트가 위젯 상으로 이동 이벤트
• <Leave> : 마우스 포인트가 위젯을 벗어남 이벤트
순천향대학교 컴퓨터공학과 6
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
바인딩 이벤트 – 키보드
키보드 이벤트• <Key>
• 임의 키 누름 이벤트
• 누른 키 값은 event 객체의 char 속성
• <Return> <Tab> <Escape> <Insert> <Delete> <Left> <Right> <Up> <Down> <F1> .........
• 특수 키 누름 이벤트
• a – z, 0 – 9, !, #, $, .......
• 키 누름 이벤트
• <Shift-Up>
• 시프트 키 누른 상태에서 위 화살표 누름 이벤트
• Alt, Shift, Control 등에 적용
• <Configure>
• 위젯의 크기 변동 이벤트
• 위젯의 크기는 이벤트 객체의 width, height 속성순천향대학교 컴퓨터공학과 7
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
프레임 예
엔트리 위젯에 입력된 값을 텍스트 위젯에 표시하는 예• 프레임에 텍스트 위젯과 스크롤바 위젯 포함
순천향대학교 컴퓨터공학과 8
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅순천향대학교 컴퓨터공학과 9
from tkinter import *
# Entry 위젯 이벤트 처리 함수
def displayText(event): # 이벤트 처ㅇ리 함수, event 객체 인수
data = etr.get() # Entry 위젯 텍스트 입력
frtext.config(state=NORMAL) # 텍스트 위젯 활성화 상태
frtext.insert(END, '₩n') # 다음 줄로 넘어감
frtext.insert(END, data) # 텍스트에 표시
frtext.yview(END) # 마지막 줄이 보이도록 지정
frtext.config(state=DISABLED) # 비활성화
etr.delete(0, END) # Entry 위젯의 텍스트 삭제
root = Tk()
root.title("Frame Example")
# 프레임 생성
fr = Frame(root)
# 텍스트 위젯 생성
frtext = Text(fr)
frtext.pack(side=LEFT, fill=Y)
프레임 예 코드 (1)
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
프레임 예 코드 (2)
순천향대학교 컴퓨터공학과 10
# 스크롤바 생성
frscroll = Scrollbar(fr)
frscroll.pack(side=RIGHT, fill=Y)
# 스크롤바와 텍스트 위젯 연동
frscroll.config(command=frtext.yview)
frtext.config(yscrollcommand=frscroll.set)
fr.pack()
# 텍스트에 첫 출력
frtext.insert(END, "환영합니다!")
frtext.config(state=DISABLED) # 텍스트 비활성화
# 입력 텍스트(엔트리) 위젯 객체 생성
etr = Entry(root, width=60)
# 엔트리 위젯 이벤트(엔터) 바인딩
etr.bind("<Return>", displayText)
etr.pack()
root.mainloop()
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
파일 대화상자 (File Dialog)
파일을 오픈하고 저장하는 데 사용하는 대화상자(dialog)• tkinter.filedialog 모듈
• askopenfilename([oprions]) : 파일 오픈, 오픈된 파일이름 리턴
• asksaveasfilename([options]) : 파일 저장, 저장된 파일이름 리턴
• 옵션
• defaultextension : 저장 시 자동으로 지정되는 파일 확장자
• filetypes : (라벨, 패턴) 튜플 형식으로 파일 타입 지정
• title : 대화상자 타이틀
• initialdir : 초기 디렉토리
• initialfile : 저장 시 초기 파일
• parent : 대화상자 상위의 부모 윈도우
순천향대학교 컴퓨터공학과 11
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
파일 대화상자 예
파일 오픈 예from tkinter import *from tkinter.filedialog import *filename = askopenfilename(title="test", filetypes=[("텍스트", "*.txt")])
순천향대학교 컴퓨터공학과 12
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
메뉴 위젯 (Menu Widget)
윈도우의 메뉴를 생성
메뉴 생성 절차• 메뉴바 생성: Menu()
app = Tk()menubar = Menu(app)app.configure(menu=menubar)
• 메뉴 생성: Menu() filemenu = Menu(menubar)
• 메뉴바에 메뉴 연결: add_cascade() 메서드menubar.add_cascade(label="File", menu=filemenu)
• 메뉴 항목 추가: add_command() 메서드filemenu.add_command(label="New", command=menu_new)filemenu.add_command(label="Open", command=menu_open)
순천향대학교 컴퓨터공학과 13
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
메뉴 프로그램 예
순천향대학교 컴퓨터공학과 14
from tkinter import *
# 메뉴 이벤트 처리 함수
def menu_new():
lb.config(text="New called")
def menu_open():
lb.config(text="Open called")
def menu_about():
lb.config(text="About called")
def menu_exit():
app.destroy()
app = Tk()
app.title("Menu Example")
# 메뉴바 생성
menubar = Menu(app)
app.config(menu=menubar)
# 메뉴 생성 및 메뉴바 연결
filemenu = Menu(menubar) # File 메뉴
menubar.add_cascade(label="File", menu=filemenu)
helpmenu = Menu(menubar) # Help 메뉴
menubar.add_cascade(label="Help", menu=helpmenu)
# 메뉴 항목 추가
filemenu.add_command(label="New", command=menu_new)
filemenu.add_command(label="Open", command=menu_open)
filemenu.add_separator() # 분리선 삽입
filemenu.add_command(label="Exit", command=menu_exit)
helpmenu.add_command(label="About",command=menu_about)
# 레이블 생성
lb = Label(app, text="hello, World!", width=50, height=3)
lb.pack()
app.mainloop()
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
시험주행
순천향대학교 컴퓨터공학과 15
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
클래스 기반 스레드 생성
클래스 기반 스레드 생성• Thread 클래스로 부터 상속 받고 run() 메서드를 오버라이드
class userThread(threading.Thread):
....
# 스레드 오버라이드 메서드
def run(self):
....
# 스레드 생성 및 실행
th = userThread() # 객체 생성
th.start() # 스레드 실행 시작
순천향대학교 컴퓨터공학과 16
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
클래스 기반 스레드 예
순천향대학교 컴퓨터공학과 17
import threading
class Mythread(threading.Thread):
m=0
n=0
# 생성자
def __init__(self, s, e=5):
threading.Thread.__init__(self)
self.m = s
self.n = e
# 스레드 오버라이드 메서드
def run(self):
for i in range(self.m, self.n):
print(" %d" %i)
# 스레드 생성 및 실행
th = Mythread(2) # 객체 생성
th.start() # # 스레드 실행
print("mainPrint ")
for i in range(100,106):
print(" %d" %i)
# 스레드 생성 및 실행
Mythread(30,35).start() # 스레드 실행
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
시험주행
순천향대학교 컴퓨터공학과 18
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
람다 함수 (Lambda function)
람다 함수• 이름이 없는 한 줄 짜리 함수
lambda <인수들> : <반환할 식>
• 예f = lambda : 1x = f()g = lambda x, y : x + yy = g(1,2)print(x, y) # 1 3 출력
• 인수를 포함한 위젯의 이벤트 처리 함수 지정 시 사용
go = Button(app, text="시작", command=lambda: btclick(900, top))
순천향대학교 컴퓨터공학과 19
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 프로그램
GUI 기반 채팅 프로그램• 클라이언트와 서버가 하나의 프로그램
• 여러 개 윈도우 생성
• 메인 윈도우, 서버/클라이언트 연결 윈도우, 사용자 이름 지정 윈도우, 에러 윈도우
• 메인 윈도우
– 메인 스크린 텍스트 위젯, 스크롤바 위젯, 메시지 입력 엔트리위젯
– 서버/클라이언트 지정 라디오 버튼 위젯, 연결 버튼 위젯
• 서버/클라이언트 연결 윈도우
– IP 주소, 포트번호 입력 엔트리 위젯, 시작 버튼 위젯
• 사용자 이름 지정 윈도우
– 사용자 이름 입력 엔트리 위젯, 변경 버튼 위젯
• 에러 윈도우
– 에러 표시 라벨 위젯, OK 버튼 위젯
• 파일 저장 대화상자
순천향대학교 컴퓨터공학과 20
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 - 서버 메인, 연결 윈도우
순천향대학교 컴퓨터공학과 21
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 - 클라이언트 메인, 연결 윈도우
순천향대학교 컴퓨터공학과 22
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅순천향대학교 컴퓨터공학과 23
GUI 기반 채팅 - 파일 메뉴,파일 저장 다이얼로그
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 - 파일 메뉴, 사용자 이름 지정/에러 표시 윈도우
순천향대학교 컴퓨터공학과 24
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 메뉴 생성
순천향대학교 컴퓨터공학과 25
# 루트 애플리케이션 윈도우 생성
root = Tk()
root.title("GUI 채팅")
# 메뉴바 생성
menubar = Menu(root)
root.config(menu=menubar)
# 파일 메뉴 생성 및 메뉴바 연결
file_menu = Menu(menubar, tearoff=0) # tearoff = 0, 점선표시 제거
menubar.add_cascade(label="파일", menu=file_menu)
# 파일 메뉴 항목 추가
file_menu.add_command(label="저장", command=lambda: saveHistory())
file_menu.add_command(label="사용자 이름",
command=lambda: username_options_window(root))
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 메뉴, 저장 이벤트 함수
순천향대학교 컴퓨터공학과 26
def saveHistory():
# 파일 저장 대화상자 생성
file_name = asksaveasfilename(
title="채팅 내용 저장",
filetypes=[('Plain text', '*.txt'), ('Any File', '*.*')])
try:
filehandle = open(file_name + ".txt", "w")
except IOError:
print("채팅 내용 저장 실패.")
return
# 메인 스크린 텍스트 위젯 내용 읽기
contents = main_body_text.get(1.0, END)
# 각 라인 읽어들여 파일에 저장
for line in contents:
filehandle.write(line)
filehandle.close()
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 메뉴, 사용자 이름 지정 이벤트 함수 (1)
순천향대학교 컴퓨터공학과 27
# 사용자 이름 지정 옵션 윈도우 생성 함수
def username_options_window(master):
top = Toplevel(master)
top.title("사용자 이름 옵션")
top.grab_set() # 발생되는 이벤트를 현재 윈도우(Toplevel)에 한정
Label(top, text="사용자 이름:").grid(row=0)
name = Entry(top)
name.focus_set() # 키보드 입력 포커스
name.grid(row=0, column=1) # 0 행, 1열 그리드 배치
go = Button(top, text="변경", command=lambda:username_options_go(name.get(), top))
go.grid(row=1, column=0, columnspan=2, sticky=W+E) # 1행 중앙에 배치
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 메뉴, 사용자 이름 지정 이벤트 함수 (2)
순천향대학교 컴퓨터공학과 28
# 사용자 이름 지정 이벤트 함수
def username_options_go(name, window):
for letter in [name]:
if letter == " " or letter == "₩n":
error_window(root, "잘못된 사용자 이름. 공백문자 허용 안됨.") # 에러 표시 윈도우 생성
return
global username
username = name
writeToScreen("변경된 사용자 이름: " + name, "시스템") # 메인 스크린 텍스트 위젯에 출력
window.destroy()
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
grid 메서드
grid 메서드• pack 메서드와 같이 위젯을 공간(윈도우, 프레임, Toplevel)에 표시
• 공간을 2차원 테이블의 행(row), 열(column)로 분할하여 표시
• 옵션
• row, column : 행, 열 위치
• sticky : 셀 내의 정렬 위치 / S, N, E, W, NW SE …, W+E …….
• rowspan, columnspan: 여러 행, 열로 확장
• padx , pady : 수평, 수직 여백
순천향대학교 컴퓨터공학과 29
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 메인 윈도우 (1)
순천향대학교 컴퓨터공학과 30
# 메인 디스플레이 프레임 생성
main_body = Frame(root)
# 메인 스크린 텍스트 위젯 생성
main_body_text = Text(main_body)
main_body_text.pack(side=LEFT, fill=Y)
# 스크롤바 위젯 객체 생성
body_text_scroll = Scrollbar(main_body)
body_text_scroll.pack(side=RIGHT, fill=Y)
# 스크롤바와 텍스트 위젯 연동
body_text_scroll.config(command=main_body_text.yview)
main_body_text.config(yscrollcommand=body_text_scroll.set)
main_body.pack()
# 텍스트에 환영 인사 출력
main_body_text.insert(END, "GUI 채팅, 환영합니다!")
main_body_text.config(state=DISABLED) # 텍스트 비활성화
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 메인 윈도우 (2)
순천향대학교 컴퓨터공학과 31
# 메시지 입력 엔트리 위젯 생성
text_input = Entry(root, width=60) # 너비 60(텍스트)
text_input.bind("<Return>", processUserText)
text_input.pack()
# 서버/클라이언트 지정 라디오 버튼 위젯 객체 생성
clientType = 1
Radiobutton(root, text="Client", variable=clientType,
value=0, command=toOne).pack(anchor=E)
Radiobutton(root, text="Server", variable=clientType,
value=1, command=toTwo).pack(anchor=E)
# 연결 버튼 위젯 생성
statusConnect = StringVar()
statusConnect.set("연결")
connecter = Button(root, textvariable=statusConnect,
command=lambda: connects(clientType))
connecter.pack()
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 텍스트 입출력
순천향대학교 컴퓨터공학과 32
def processUserText(event):
data = text_input.get() # 엔트리 메시지 입력
placeText(data) # 메인 스크린에 출력하고 전송
text_input.delete(0, END) # 입력 엔트리 클리어
# 텍스트를 스크린에 출력하고 상대방에게 전송
def placeText(text):
writeToScreen(text, username) # 메인 스크린에 출력
netThrow(connectionSocket, text) # 상대방에 메시지 전송
# 텍스트를 메인 스크린에 "[username] text" 형식으로 출력
def writeToScreen(text, username=""):
main_body_text.config(state=NORMAL) # 메인 스크린 활성화
main_body_text.insert(END, '₩n') # 개행문자 출력
if username:
main_body_text.insert(END, "[" + username + "] ") # 사용자 이름 출력
main_body_text.insert(END, text) # 메시지 출력
main_body_text.yview(END) # 수직 방향 뷰 변경 표시
main_body_text.config(state=DISABLED) # 메인 스크린 비활성화
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 네트워크 송수신
순천향대학교 컴퓨터공학과 33
# 메시지 송수신 관련 함수
# 상대방(conn 소켓)에 메시지를 전송
def netThrow(conn, message):
try:
# 문자열 인코드하여 데이터 송신
conn.send(message.encode("utf8"))
except socket.error:
writeToScreen("메시지 송신 실패.", "시스템")
# conn 소켓에서 메시진 수신
def netCatch(conn):
try:
message = conn.recv(80)
return message.decode("utf8")
except socket.error:
writeToScreen("메시지 수신 실패.", "시스템")
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 연결 버튼 이벤트 함수
순천향대학교 컴퓨터공학과 34
# 연결 버튼 및 라디오 버튼 이벤트 관련 함수
# 연결 버튼 이벤트 함수
def connects(clientType):
connecter.config(state=DISABLED) # 버튼 비활성화
if clientType == 0: # 클라이언트
client_options_window(root)
if clientType == 1: # 서버
server_options_window(root)
# 클라이언트 라디오 버튼 이벤트 함수
def toOne():
global clientType
clientType = 0
# 서버 라디오 버튼 이벤트 함수
def toTwo():
global clientType
clientType = 1
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 서버 연결 윈도우 (1)
순천향대학교 컴퓨터공학과 35
# 서버 포트 입력 윈도우 생성 함수
def server_options_window(master):
top = Toplevel(master)
top.title("서버 포트 연결 옵션")
top.grab_set() # 발생되는 이벤트를 현재 윈도우(Toplevel)에 한정
top.protocol("WM_DELETE_WINDOW", lambda: optionDelete(top))
Label(top, text="포트:").grid(row=0)
port = Entry(top)
port.grid(row=0, column=1)
port.focus_set()
go = Button(top, text="시작", command=lambda: server_options_go(port.get(), top))
go.grid(row=1, column=1)
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 서버 연결 윈도우 (2)
순천향대학교 컴퓨터공학과 36
# 서버 연결 처리 이벤트 함수
def server_options_go(port, window):
if options_sanitation(port): # 포트 입력 올바름 조사
window.destroy()
Server(int(port)).start() # 서버 스레드 실행 시작
# 윈도우 닫기 시 처리되는 함수
def optionDelete(window):
connecter.config(state=NORMAL) # 연결 버튼 활성화
window.destroy()
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 클라이언트 연결 윈도우
순천향대학교 컴퓨터공학과 37
# 클라이언트의 서버 주소 입력 윈도우 생성 함수
def client_options_window(master):
top = Toplevel(master)
top.title("클라이언트 연결 옵션")
top.protocol("WM_DELETE_WINDOW", lambda: optionDelete(top))
top.grab_set() # 발생되는 이벤트를 현재 윈도우(Toplevel)에 한정
Label(top, text="서버 IP:").grid(row=0)
location = Entry(top)
location.grid(row=0, column=1)
location.focus_set()
Label(top, text="포트:").grid(row=1)
port = Entry(top)
port.grid(row=1, column=1)
go = Button(top, text="시작", command=lambda: client_options_go(location.get(), port.get(), top))
go.grid(row=2, column=1)
# 클라이언트 연결 처리 이벤트 함수
def client_options_go(dest, port, window):
if options_sanitation(port, dest): # IP 주소, 포트번호 올바름 조사
window.destroy()
Client(dest, int(port)).start() # 클라이언트 스레드 실행 시작
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅순천향대학교 컴퓨터공학과 38
# 포트와 IP 주소의 올바름 검사 함수
def options_sanitation(por, loc=""):
if not por.isnumeric():
error_window(root, "포트 번호를 입력해주세요.")
return False
if int(por) < 0 or 65555 < int(por):
error_window(root, "0 과65555 사이 번호를 입력해주세요.")
return False
if loc != "":
if not ip_process(loc.split(".")):
error_window(root, "올바른 IP 주소를 입력해주세요.")
return False
return True
# 유효한 IP 주소인지를 검사 함수
def ip_process(ipArray):
if len(ipArray) != 4:
return False
for ip in ipArray:
if not ip.isnumeric():
return False
t = int(ip)
if t < 0 or 255 < t:
return False
return True
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 스레드
클래스 기반 서버 스레드• Server 클래스에서 생성
• 서버 연결 윈도우에서 스레드 실행, Server(int(port)).start()
• TCP 서버 연결
• 메시지 수신 스레드 생성
클래스 기반 클라이언트 스레드• Client 클래스에서 생성
• 클라이언트 연결 윈도우에서 스레드 실행, Client(dest, int(port)).start()
• TCP 클라이언트 연결
• 메시지 수신 스레드 생성
메시지 수신 스레드 함수• Runner() 함수
• 메시지를 수신하여 메인 스크린 텍스트 위젯에 출력
순천향대학교 컴퓨터공학과 39
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 서버 클래스
순천향대학교 컴퓨터공학과 40
# Server 클래스: Thread 클래스 상속
class Server (threading.Thread):
# 생성자
def __init__(self, port):
threading.Thread.__init__(self) # 부모 클래스 생성자 호출
self.port = port # 포트 지정
def run(self):
global serv
# 서버 소켓 생성
serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serv.bind(('', self.port)) # 주소와 소켓 결합
serv.listen(1) # 연결 요청 청취
global connectionSocket
writeToScreen("포트 " + str(self.port) + "에서 연결 대기 중 ....", "시스템")
# 연결 요청 수락, 연결 소켓 생성(클라이언트 IP 주소 받음)
connectionSocket, addr = serv.accept()
writeToScreen(str(addr[0]) + " 연결됨.", "시스템")
# 메시지 수신 스레드 생성
threading.Thread(target=Runner, args=(connectionSocket,str(addr[0]))).start()
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 클라이언트 클래스
순천향대학교 컴퓨터공학과 41
# Client 클래스: Thread 클래스 상속
class Client (threading.Thread):
# 생성자
def __init__(self, host, port):
threading.Thread.__init__(self) # 부모 클래스 생성자 호출
self.port = port # 포트 지정
self.host = host # IP 주소 지정
def run(self):
global connectionSocket
# 소켓 생성connectionSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 서버에 연결 요청
connectionSocket.connect((self.host, self.port))
writeToScreen("IP 주소 " + self.host + ", 포트 " + str(self.port) + " 에 연결됨.", "시스템")
# 메시지 수신 스레드 생성
threading.Thread(target=Runner, args=(connectionSocket, self.host)).start()
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 – 메시지 수신 스레드 함수
순천향대학교 컴퓨터공학과 42
# 메시지 수신 스레드 함수
def Runner(conn, addr):
while 1:
data = netCatch(conn) # 메시지 수신
writeToScreen(data, addr)
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
GUI 기반 채팅 코드
순천향대학교 컴퓨터공학과 43
from tkinter import *
from tkinter.filedialog import asksaveasfilename
import threading
import socket
# GLOBALS
username = "나"
connectionSocket = 0
# 메뉴 관련 함수
# 파일 대화상자 사용하여 채팅 내용 저장 함수
def saveHistory():
# 파일 저장 대화상자 생성
file_name = asksaveasfilename(
title="채팅 내용 저장",
filetypes=[('Plain text', '*.txt'), ('Any File', '*.*')])
try:
filehandle = open(file_name + ".txt", "w")
except IOError:
print("채팅 내용 저장 실패.")
return
# 메인 스크린 텍스트 위젯 내용 읽기
contents = main_body_text.get(1.0, END)
# 각 라인 읽어들여 파일에 저장
for line in contents:
filehandle.write(line)
filehandle.close()
# 사용자 이름 지정 옵션 윈도우 생성 함수
def username_options_window(master):
top = Toplevel(master)
top.title("사용자 이름 옵션")
top.grab_set() # 모든 이벤트를 현재 윈도우(Toplevel)에 한정
Label(top, text="사용자 이름:").grid(row=0)
name = Entry(top)
name.focus_set() # 키보드 입력 포커스
name.grid(row=0, column=1)
go = Button(top, text="변경", command=lambda:username_options_go(name.get(), top))
go.grid(row=1, column=0, columnspan=2, sticky=W+E) # 1행 중앙에 배치
# 사용자 이름 지정 이벤트 함수
def username_options_go(name, window):
for letter in [name]:
if letter == " " or letter == "₩n":
error_window(root, "잘못된 사용자 이름. 공백문자 허용 안됨.") # 에러 표시 윈도우 생성
return
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅순천향대학교 컴퓨터공학과 44
global username
username = name
writeToScreen("변경된 사용자 이름: " + name, "시스템") # 메인 스크린 텍스트 위젯에 출력
window.destroy()
# 서버 연결 윈도우
# 서버 포트 입력 윈도우 생성 함수
def server_options_window(master):
top = Toplevel(master)
top.title("서버 포트 연결 옵션")
top.grab_set() # 발생 이벤트를 현재 윈도우에 한정
top.protocol("WM_DELETE_WINDOW", lambda: optionDelete(top))
Label(top, text="포트:").grid(row=0)
port = Entry(top)
port.grid(row=0, column=1)
port.focus_set()
go = Button(top, text="시작", command=lambda: server_options_go(port.get(), top))
go.grid(row=1, column=1)
# 서버 연결 처리 이벤트 함수
def server_options_go(port, window):
if options_sanitation(port): # 포트 입력 올바름 조사
window.destroy()
Server(int(port)).start() # 서버 스레드 실행 시작
# 윈도우 닫기 시 처리되는 함수
def optionDelete(window):
connecter.config(state=NORMAL) # 연결 버튼 활성화
window.destroy()
# 클라이언트 연결 윈도우
# 클라이언트의 서버 주소 입력 윈도우 생성 함수
def client_options_window(master):
top = Toplevel(master)
top.title("클라이언트 연결 옵션")
top.protocol("WM_DELETE_WINDOW", lambda: optionDelete(top))
top.grab_set() # 발생되는 이벤트를 현재 윈도우에 한정
Label(top, text="서버 IP:").grid(row=0)
location = Entry(top)
location.grid(row=0, column=1)
location.focus_set()
Label(top, text="포트:").grid(row=1)
port = Entry(top)
port.grid(row=1, column=1)
go = Button(top, text="시작", command=lambda:
client_options_go(location.get(), port.get(), top))
go.grid(row=2, column=1)
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅순천향대학교 컴퓨터공학과 45
# 클라이언트 연결 처리 이벤트 함수
def client_options_go(dest, port, window):
if options_sanitation(port, dest):
window.destroy()
Client(dest, int(port)).start() # 클라이언트 스레드 실행 시작
# 포트와 IP 주소의 올바름 검사 함수
def options_sanitation(por, loc=""):
if not por.isnumeric():
error_window(root, "포트 번호를 입력해주세요.")
return False
if int(por) < 0 or 65555 < int(por):
error_window(root, "0 과65555 사이 번호를 입력해주세요.")
return False
if loc != "":
if not ip_process(loc.split(".")):
error_window(root, "올바른 IP 주소를 입력해주세요.")
return False
return True
# 유효한 IP 주소인지를 검사 함수
def ip_process(ipArray):
if len(ipArray) != 4:
return False
for ip in ipArray:
if not ip.isnumeric():
return False
t = int(ip)
if t < 0 or 255 < t:
return False
return True
# 에러 표시 윈도우 생성 함수
def error_window(master, texty):
window = Toplevel(master)
window.title("에러")
window.grab_set()
Label(window, text=texty).pack()
go = Button(window, text="OK", command=window.destroy)
go.pack()
go.focus_set()
# 연결 버튼 및 라디오 버튼 이벤트 관련 함수
# 연결 버튼 이벤트 함수
def connects(clientType):
connecter.config(state=DISABLED) # 버튼 비활성화
if clientType == 0: # 클라이언트
client_options_window(root)
if clientType == 1: # 서버
server_options_window(root)
# 클라이언트 라디오 버튼 이벤트 함수
def toOne():
global clientType
clientType = 0
# 서버 라디오 버튼 이벤트 함수
def toTwo():
global clientType
clientType = 1
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅순천향대학교 컴퓨터공학과 46
# 텍스트 입출력 관련 함수
# 엔트리 텍스트 입력 이벤트 함수
def processUserText(event):
data = text_input.get() # 엔트리 메시지 입력
placeText(data) # 메인 스크린에 출력하고 전송
text_input.delete(0, END) # 입력 엔트리 클리어
# 텍스트를 스크린에 출력하고 상대방에게 전송
def placeText(text):
writeToScreen(text, username) # 메인 스크린에 출력
netThrow(connectionSocket, text) # 상대방에 메시지 전송
# 텍스트를 메인 스크린에 "[username] text" 형식으로 출력
def writeToScreen(text, username=""):
main_body_text.config(state=NORMAL) # 메인 스트린 비활성화
main_body_text.insert(END, '₩n') # 개행문자 출력
if username:
main_body_text.insert(END, "[" + username + "] ") # 사용자 이름 출력
main_body_text.insert(END, text) # 메시지 출력
main_body_text.yview(END) # 수직 방향 뷰 변경 표시
main_body_text.config(state=DISABLED) # 메인 스크린 비활성화
# 메시지 송수신 관련 함수
# 상대방(conn 소켓)에 메시지를 전송
def netThrow(conn, message):
try:
# 문자열 인코드하여 데이터 송신
conn.send(message.encode("utf8"))
except socket.error:
writeToScreen("메시지 송신 실패.", "시스템")
# conn 소켓에서 메시진 수신
def netCatch(conn):
try:
message = conn.recv(80)
return message.decode("utf8")
except socket.error:
writeToScreen("메시지 수신 실패.", "시스템")
# Server 클래스: Thread 클래스 상속
class Server (threading.Thread):
# 생성자
def __init__(self, port):
threading.Thread.__init__(self) # 부모 클래스 생성자 호출
self.port = port # 포트 지정
def run(self):
global serv
# 서버 소켓 생성
serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serv.bind(('', self.port)) # 주소와 소켓 결합
serv.listen(1) # 연결 요청 청취
global connectionSocket
writeToScreen("포트 " + str(self.port) +"에서 연결 대기 중 ....", "시스템")
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅순천향대학교 컴퓨터공학과 47
# 연결 요청 수락연결 소켓 생성, (클라이언트 IP 주소 받음)
connectionSocket, addr = serv.accept()
writeToScreen(str(addr[0]) + " 연결됨.", "시스템")
# 메시지 수신 스레드 생성
threading.Thread(target=Runner, args=(connectionSocket,str(addr[0]))).start()
# Client 클래스: Thread 클래스 상속
class Client (threading.Thread):
# 생성자
def __init__(self, host, port):
threading.Thread.__init__(self) # 부모 클래스 생성자 호출
self.port = port # 포트 지정
self.host = host # IP 주소 지정
def run(self):
global connectionSocket
# 소켓 생성
connectionSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 서버에 연결 요청
connectionSocket.connect((self.host, self.port))
writeToScreen("IP 주소 " + self.host + ", 포트 " + str(self.port) + " 에 연결됨.", "시스템")
# 메시지 수신 스레드 생성
threading.Thread(target=Runner, args=(connectionSocket, self.host)).start()
# 메시지 수신 스레드 함수
def Runner(conn, addr):
while 1:
data = netCatch(conn) # 메시지 수신
writeToScreen(data, addr)
# 루트 애플리케이션 윈도우 생성
root = Tk()
root.title("GUI 채팅")
# 메뉴바 생성
menubar = Menu(root)
root.config(menu=menubar)
# 파일 메뉴 생성 및 메뉴바 연결
file_menu = Menu(menubar, tearoff=0)# tearoff = 0, 점선표시 제거
menubar.add_cascade(label="파일", menu=file_menu)
# 파일 메뉴 항목 추가
file_menu.add_command(label="저장", command=lambda: saveHistory())
file_menu.add_command(label="사용자 이름",
command=lambda:username_options_window(root))
# 메인 디스플레이 프레임 생성
main_body = Frame(root)
# 메인 스크린 텍스트 위젯 생성
main_body_text = Text(main_body)
main_body_text.pack(side=LEFT, fill=Y)
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅순천향대학교 컴퓨터공학과 48
# 스크롤바 위젯 객체 생성
body_text_scroll = Scrollbar(main_body)
body_text_scroll.pack(side=RIGHT, fill=Y)
# 스크롤바와 텍스트 위젯 연동
body_text_scroll.config(command=main_body_text.yview)
main_body_text.config(yscrollcommand=body_text_scroll.set)
main_body.pack()
# 텍스트에 환영 인사 출력
main_body_text.insert(END, "GUI 채팅, 환영합니다!")
main_body_text.config(state=DISABLED) # 텍스트 비활성화
# 메시지 입력 엔트리 위젯 생성
text_input = Entry(root, width=60) # 너비 60(텍스트)
text_input.bind("<Return>", processUserText)
text_input.pack()
# 서버/클라이언트 지정 라디오 버튼 위젯 객체 생성
clientType = 1
Radiobutton(root, text="Client", variable=clientType,
value=0, command=toOne).pack(anchor=E)
Radiobutton(root, text="Server", variable=clientType,
value=1, command=toTwo).pack(anchor=E)
# 연결 버튼 위젯 생성
statusConnect = StringVar()
statusConnect.set("연결")
connecter = Button(root, textvariable=statusConnect,
command=lambda: connects(clientType))
connecter.pack()
root.mainloop()
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
과제
1. 앞에서 소개된 GUI 기반 채팅 프로그램을 작성하고 실행
2. 앞에서 배운 GUI 기반 채팅 프로그램의 기능을 추가한프로그램 작성프로그램 소스
• 기능 추가 예
• 연결 종료 메뉴
• 상대방 주소가 아닌 사용자 이름 표시
• 메뉴 추가 (연결 메뉴, 종료 메뉴, ……)
• 메시지 암호화
• 대화상대 관리…………
순천향대학교 컴퓨터공학과 49
GUI 설계기법
7. 파이썬 GUI 응용: GUI 채팅
참고 사이트
Python Chat Programhttps://github.com/chprice/Python-Chat-Program
• 다중 채팅 프로그램
• 대화 상대 관리
• 암호화
순천향대학교 컴퓨터공학과 50
Recommended