728x90
반응형

icon.ico
0.16MB

이번엔 저번에 만든 가위바위보 게임 프로그램을 pyinstaller 사용해서 exe파일로 만들어봤다.

가위바위보 게임: https://jinho-study.tistory.com/1078 

 

파이썬으로 가위바위보 게임 구현하기(Tkinter)

저번에는 tkinter(window, label, button, canvas)에 대해 알아보고 간단한 제비뽑기 프로그램을 만들었는데 https://jinho-study.tistory.com/1077 파이썬 GUI 기초 1(Tkinter ) 1 GUI란? GUI: 소프트웨어의 조..

jinho-study.tistory.com

 

아래는 전체 코드인데 파일 경로 부분에서 조금 추가된 것이 있다.

import tkinter
import random
# from functools import partial
from PIL import ImageTk
import os


# PyInstaller에 의해 임시폴더에서 실행될 경우 임시폴더로 접근하는 함수
def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

def click_btn(user_choice):
    # 가위, 바위, 보 중 랜덤으로 하나 선택하고 com_rps_label에 출력
    computer_choice = random.choice(["가위", "바위", "보"])
    com_rps_label["text"] = computer_choice
    com_rps_label.update()
    
    # 사용자가 선택한 것을 user_rps_label에 출력
    user_rps_label["text"] = user_choice
    user_rps_label.update()
    
    # 승패를 판별하고 result_label에 출력
    res = ""
    if computer_choice == user_choice:
        res = "비김!" 
    else:
        if user_choice == "가위":
            res = "승리!" if computer_choice == "보" else "패배!"
        elif user_choice == "바위":
            res = "승리!" if computer_choice == "가위" else "패배!"
        elif user_choice == "보":
            res = "승리!" if computer_choice == "바위" else "패배!"
    result_label["text"] = res
    result_label.update()
    
if __name__ == "__main__":
    root = tkinter.Tk() 
    root.title("가위바위보 프로그램")
    root.resizable(False, False) 
    canvas = tkinter.Canvas(root, width=800, height=480)
    canvas.pack()

    # 이미지 파일에 따라 tkinter.PhotoImage가 잘 작동하지 않는 것 같다.
    # ImageTk.PhotoImage 명령을 대신 사용했다.
    # gazou = tkinter.PhotoImage(file="alphago.png")
    gazou = ImageTk.PhotoImage(file=resource_path("alphago.png"))
    canvas.create_image(400, 240, image=gazou)
    
    # 컴퓨터, 사용자 라벨
    com_label = tkinter.Label(root, text="컴퓨터", font=("Times New Roman", 55),
                            bg="white")
    user_label = tkinter.Label(root, text="사용자", font=("Times New Roman", 55),
                            bg="white")
    # 컴퓨터 가위, 바위, 보 라벨
    com_rps_label = tkinter.Label(root, text="??", font=("Times New Roman", 55),
                            bg="white")
    # 사용자 가위, 바위, 보 라벨
    user_rps_label = tkinter.Label(root, text="??", font=("Times New Roman", 55),
                            bg="white")
    # 승패 결과 라벨
    result_label = tkinter.Label(root, text="승패", font=("Times New Roman", 60),
                            bg="white")
    com_label.place(x=350, y=25)
    com_rps_label.place(x=600, y=25)
    user_label.place(x=350, y=145)
    user_rps_label.place(x=600, y=145)
    result_label.place(x=470, y=250)

    # 가위, 바위, 보 버튼 3개
    # 버튼 명령에 인수를 전달하기 위해 lambda를 사용했다.
    # partial(clict_btn, "가위") 같은 방식으로도 사용할 수 있다.
    s_button = tkinter.Button(root, text="가위", font=("Times New Roman", 36),
                            fg="skyblue", command=lambda: click_btn("가위"))
    r_button = tkinter.Button(root, text="바위", font=("Times New Roman", 36),
                            fg="skyblue", command=lambda: click_btn("바위"))
    p_button = tkinter.Button(root, text="보", font=("Times New Roman", 36),
                            fg="skyblue", command=lambda: click_btn("보"))
    s_button.place(x=350, y=365)
    r_button.place(x=520, y=365)
    p_button.place(x=690, y=365)

    root.mainloop() 

 

파일 경로 문제

처음에 exe파일로 만드는 것은 바로 성공했는데 계속~~ 실행이 안됬었는데 이유를 찾아보니 파일 경로 문제였다.

pyinstaller로 만든 exe파일은 실행 시에 필요한 모든 파일을 임시 폴더에 풀어낸 후에 실행되는데,

이때 이 임시 폴더는 실행시마다 경로가 달라진다. 그래서 필요한 파일에 그냥 접근하면 오류가 나기에 

sys._MEIPASS 라는 변수를 사용해서 접근해야 한다. 아래 글 덕분에 알게 되었다!

https://www.inflearn.com/questions/57133

 

이미지가 onefile로 안들어간거 같아요 - 인프런 | 질문 & 답변

[사진] 안녕하세요 강의 몇번씩 보고 있어요 pyautogui exe만들려고하는데요 이미지가 함께 안들어가는거 같아요 onefile로 했는데요 - 질문 & 답변 | 인프런...

www.inflearn.com

아래 함수를 사용해서 이미지를 불러오면 OK다.

def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

 

pyinstaller 명령어

pyinstaller 명령어를 알아보자면 

-w: 콘솔 윈도우 표시 안 함

-F: 1개의 exe파일로 변환

-i: 아이콘 설정

--add-data <SRC;DEST or SRC:DEST>: 파일 추가 

등이 있는데 여기서 특히 --add-data는 데이터 유형에 따라 DEST가 다르다.

  • Single file: "alphago.png:." -> DEST = .
  • multiple files: "images/*.png:sfx" -> DEST = sfx
  • folder: "images:data" -> DEST = data

추가로 직접 사용은 안 해봤지만 아래 같은 옵션들도 존재한다.

-n: 이름 지정

-D: 한 개 폴더로 변환

--hidden-import: 코드에서 직접적으로 보이지 않는 모듈 이름을 지정 

아래 글을 참고했다!

https://stackoverflow.com/questions/41870727/pyinstaller-adding-data-files

 

Pyinstaller adding data files

I'm struggling with pyinstaller. Whenever I build this specific script with a kivy GUI and a .kv file, and run the .exe after the build, I get a fatal error: IOError: [Errno 2] No such file or dire...

stackoverflow.com

 

pyinstaller -w -F --add-data "alphago.png;." -i "icon.ico" rps_game.py

 

이제 위의 명령어를 실행하면 dist 폴더 안에 rps_game.exe 파일이 생긴 것을 확인할 수 있다. 

아래 같이 아이콘도 잘 적용되었다. 아이콘 파일은 맨 위에 첨부했다! 

exe 파일

 

만약 exe파일이 실행이 안된다면 필요한 데이터가 잘 추가되었는지, 현재 환경에 코드에 필요한 라이브러리가

다 설치가 되어있는 상태인지, resource_path 함수를 사용해서 데이터를 불러왔는지 등을 확인해주면 될 것 같다.

여기서 데이터가 잘 추가되었는지는 pyinstaller 명령어를 실행했을 때 생기는 .spec 파일을

열어보면 알 수 있는데, datas 쪽을 확인해주면 된다! 

코드로 치기 귀찮으면 그냥 여기서 데이터를 직접 추가해줘도 된다.

spec 파일 내부

 

추가로 아나콘다 환경에서 pyinstaller를 사용하면 exe파일의 용량이 엄청 커진다.

예를 들어 위의 가위바위보 게임을 exe파일로 생성했을 때 아나콘다에서는 74Mb인데 

그냥 cmd에서 생성하면 12Mb이다. 이거에 대한 정확한 이유는 모르겠다만

내 아나콘다 환경에 쓸데없는 라이브러리가 많이 포함되어있어서 그런 것 같기도 하다.

 

github: https://github.com/kimjinho1/Python-Game

 

kimjinho1/Python-Game

Contribute to kimjinho1/Python-Game development by creating an account on GitHub.

github.com

728x90
반응형

+ Recent posts