인프런 커뮤니티 질문&답변

윤태영님의 프로필 이미지
윤태영

작성한 질문수

남박사의 파이썬 기초부터 실전 100% 활용

파일 배포하기에서 질문있습니다!

작성

·

364

1

배포파일을 만들었는데 실행이안됩니다

라이브러리는 다 설치했는데 인코딩문제인지 구글링해보니

reload(sys) 등등 하라고 해서 메인함수에 추가해봐도 reload(sys)가 정의되지 않았다고 에러가뜨고

뭐가문제인지 잘 모르겠습니다

아래는 코드입니다

from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5.QtWidgets import QToolButton, QSizePolicy
import datetime
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import cv2
import os

class MainDialog(QtWidgets.QWidget):
    '''메인 윈도우가 되는 위젯. 이 창에서 나머지 기능들을 팝업시킵니다.'''
    def __init__(self):
        super().__init__()
        self.layout_s = QtWidgets.QVBoxLayout(self#전체틀
        self.start_layout = QtWidgets.QHBoxLayout() #버튼을 담을 틀
        self.setFixedSize(300200)

        self.btn_watch = self.createButton("공부 시작",self.clickWatch)#버튼watch
        self.btn_graph = self.createButton("공부량 보기",self.clickGraph)#버튼graph
    
        self.btn_watch.resize(self.btn_watch.sizeHint())#sizeHint=holds the recommended size for the widget
        self.btn_graph.resize(self.btn_graph.sizeHint())

        self.start_layout.addWidget(self.btn_watch)#틀에 버튼 담음
        self.start_layout.addWidget(self.btn_graph)

        self.layout_s.addLayout(self.start_layout)#전체틀에 버튼을 담은 틀을 담음
        self.setLayout(self.layout_s)

       
        self.show()

    def clickWatch(self):
        '''공부 시작이 눌리면 동작하는 함수'''
        # MyClock 객체가 생성되어 newWindow 변수에 저장
        self.newWindow = MyClock()
        # 새로운 위젯 show
        self.newWindow.show()
        
    def clickGraph(self):
        try:
            image = cv2.imread("C:\\study\\chart.png", cv2.IMREAD_ANYCOLOR)
            cv2.imshow("study time", image)
            cv2.waitKey(0)#cv2.waitkey(time)이며 time마다 키 입력상태를 받아옵니다. 
                          #0일 경우, 지속적으로 검사하여 해당 구문을 넘어가지 않습니다.
            cv2.destroyAllWindows()#창 닫기
        except:
            QtWidgets.QMessageBox.about(self"알림""공부하세요!")
        

    def createButton(selftextfunction):
        button = Button(text)
        button.clicked.connect(function)
        return button

class MyClock(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        # 스톱와치 용 변수
        self.createFolder("C:\\study")
        self.watch_start_time = 0
        self.mouseClick = False
        self.setWindowTitle("시계")
        self.setFixedSize(250100)#사이즈고정
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)#타이틀바 없앰
        self.initWidgets()
        self.show()
        self.days = datetime.date.today().day
        self.months=datetime.date.today().month
        

    def createFolder(self,directory):
        try:
            if not os.path.exists(directory):
                os.makedirs(directory)
        except OSError:
            print("error")

    def keyPressEvent(selfe):#esc누르면 종료
        if e.key() == QtCore.Qt.Key_Escape:
            day = str(self.months)+"/"+str(self.days)
            try:#이미 파일을 만들었으면
                data = pd.read_csv('C:\\study\\graph.csv')
                
                if data.loc[len(data)-1"day"]==day:#같은 날짜면 시간 누적
                    data.loc[data["day"]==day, "time"]+=self.watch_start_time
                    data.to_csv('C:\\study\\graph.csv',header=Trueindex=False)
                else:#새로운 날짜,시간 append
                    data2=pd.DataFrame({"day":[day],"time":[self.watch_start_time]})
                    data=pd.concat([data,data2], ignore_index=True)
                    data.to_csv('C:\\study\\graph.csv',header=Trueindex=False)
            except:#파일이없으면
                df=pd.DataFrame({"day":[day],"time":[self.watch_start_time]})
                df.to_csv('C:\\study\\graph.csv',header=Trueindex=False)#header:column이름 정보

            data=pd.read_csv('C:\\study\\graph.csv')

            group_by_day=data.groupby('day').time.sum()#day별로 time의 합을 구함
            y=list(group_by_day)
            x = np.arange(len(y))
            xlabel = list(data["day"])
            plt.title("Amount",fontsize=20)
            plt.bar(x, y)
            plt.xticks(x, xlabel)
            plt.yticks(sorted(y))
            plt.xlabel("Date",fontsize=10)
            plt.ylabel("Study Time(s)",fontsize=10)
            plt.savefig('C:\\study\\chart.png')#그래프 저장
            
            self.close()

    def mousePressEvent(selfe):#마우스로 창 누를때
        if e.button() == QtCore.Qt.LeftButton:#좌클릭시
            self.mouseClick = True
            self.oldPos = e.globalPos()#x,y가 튜플형태로 넘어옴
            #globalPos=윈도우상의 x,y좌표

    def mouseReleaseEvent(selfe):
        self.mouseClick = False

    def mouseMoveEvent(selfe):#마우스로 창 누른뒤 이동시킬때
        if self.mouseClick:
            delta = QtCore.QPoint(e.globalPos() - self.oldPos)
            self.move(self.x() + delta.x(), self.y() + delta.y())
            self.oldPos = e.globalPos()
    

    def initWidgets(self):
        self.layout = QtWidgets.QVBoxLayout(self#QV=가로 QH=세로

        # 시작, 초기화 버튼 2개를 HBoxLayout 에 추가합니다.
        self.button_layout = QtWidgets.QHBoxLayout() # 버튼을 담기위한 레이아웃
        self.btn_start = QtWidgets.QPushButton("중지"self)
        self.btn_reset = QtWidgets.QPushButton("초기화"self)
        self.btn_start.resize(self.btn_start.sizeHint())
        self.btn_reset.resize(self.btn_start.sizeHint())
        self.button_layout.addWidget(self.btn_start)
        self.button_layout.addWidget(self.btn_reset)
        
        self.lcd = QtWidgets.QLCDNumber()#시계디자인 위젯
        self.lcd.setSegmentStyle(QtWidgets.QLCDNumber.Flat)#글자평평하게
        self.lcd.setDigitCount(8)#글자 총 8개까지 보여줌(hh:mm:ss)
        self.lcd.setFrameStyle(QtWidgets.QFrame.NoFrame)#박스없앰
        
        self.timer = QtCore.QTimer()    # 타이머 생성
        
        # 스탑와치용 출력 함수 연결
        self.timer.timeout.connect(self.showWatch)  # 타임아웃 이벤트를 showWatch와 연결
        # 정한 시간이 지날때마다 show_time 실행
        self.timer.start(1000)#1초에 한번씩

        self.resetWatch()
        self.layout.addWidget(self.lcd)
        # 버튼 레이아웃을 기본 레이아웃에 추가합니다.
        self.layout.addLayout(self.button_layout)
        self.setLayout(self.layout)

        self.btn_start.clicked.connect(self.startWatch)
        self.btn_reset.clicked.connect(self.resetWatch)
        
    def startWatch(self):
        '''스탑와치를 시작하는 함수 입니다.
        버튼 클릭시 시작과 중지를 한 버튼으로 처리하기 위해
        버튼의 글자를 가져와서 각 상황에 맞게 동작합니다.'''
        text = self.btn_start.text()
        if text == "시작":
            self.btn_start.setText("중지")
            self.timer.start(1000)
        elif text == "중지":
            self.btn_start.setText("시작")
            self.timer.stop()
     
    def resetWatch(self):
        '''스탑와치를 초기화 합니다.'''
        text = "00:00:00"
        self.watch_start_time = 0
        self.lcd.display(text)
    
    def showWatch(self):
        '''스탑와치의 현재시간 - 시작시간을 계산해서 화면에 출력하는 함수'''
        # 현재시간 - 스탑와치 시작시간을 total_seconds() 로 변환해서 초만 받습니다.
        self.watch_start_time+=1
        # 진행된 초를 시:분:초로 출력하기 위해서 계산합니다.
        hour = self.watch_start_time // 3600
        minute = self.watch_start_time % 3600 // 60
        second = self.watch_start_time % 60
        # 시:분:초 형태로 문자열 포맷팅을 합니다.
        text = '{:02d}:{:02d}:{:02d}'.format(hour, minute, second)
        # 출력
        self.lcd.display(text)

class Button(QToolButton):
    def __init__(selftext):
        super().__init__()
        buttonStyle = '''
        QToolButton:hover {border:1px solid #0078d7; background-color:#e5f1fb;}
        QToolButton:pressed {background-color:#a7c8e3}
        QToolButton {font-size:11pt; font-family:나눔고딕; border:1px solid #d6d7d8; background-color:#f0f1f1}
        '''
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        self.setText(text)
        self.setStyleSheet(buttonStyle)

    def sizeHint(self):
        size = super(Button, self).sizeHint()
        size.setHeight(size.height() + 30)
        size.setWidth(max(size.width(), size.height()))
        return size

if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    win=MainDialog()
    app.exec_()
freeze 결과입니다
(stopwatch) PS C:\python\스톱워치\dist> pip freeze
altgraph==0.17 cycler==0.10.0 DateTime==4.3 future==0.18.2 kiwisolver==1.1.0 matplotlib==3.1.3
numpy==1.18.1 opencv-python==4.2.0.32 pandas==1.0.1 pefile==2019.4.18 PyInstaller==3.6
pyparsing==2.4.6 PyQt5==5.14.1 PyQt5-sip==12.7.1 python-dateutil==2.8.1 pytz==2019.3
pywin32-ctypes==0.2.0 six==1.14.0 zope.interface==4.7.1

답변 2

1

남박사님의 프로필 이미지
남박사
지식공유자

pyinstaller 를 이용해서 배포 파일을 만들때 여러가지 오류의 상황을 만날 수 있습니다. 또한 너무 방대한 범주의 이야기라 명확하게 답변을 드리기가 힘듭니다만 일단 대부분은 라이브러리가 포함되지 않아서 생기는 오류도 많고 설치가 잘못 되어 생기는 오류도 많습니다. 구글링을 해보면 이와 비슷한 문제를 볼 수 있는데...  일단 아래 링크를 참고해 공식 문서를 참고해보시길 바라며...

https://pythonhosted.org/PyInstaller/when-things-go-wrong.html#listing-hidden-imports

--hidden-import

pyinstaller 실행 시 위 옵션을 주어서 임포트 시키는 방법..

pip uninstall pyinstaller
pip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip

pyinstaller 를 지우고 위의 방법으로 다시 설치하는 방법 등으로 해결하신 분들이 있는걸 확인했습니다. 또한 경로문제가 발생할 수도 있으니 참고 하시어 되도록 한글 경로는 사용하지 않는걸 추천드리며 테스트 해보시고 또 문제가 되면 질문 주시기 바랍니다.

0

윤태영님의 프로필 이미지
윤태영
질문자

감사합니다

재설치뒤 pip install tornado를 하여 해결했습니다!

윤태영님의 프로필 이미지
윤태영

작성한 질문수

질문하기