소연의_개발일지
article thumbnail

 

초안

파워포인트로 만든 화면

이런 식으로 만들려고 했다. 버튼을 클릭하면 창이 새로 뜨기보다는 밑에서 다 확인할 수 있도록 한다. 

 

이를 위해 qt stackedWidget을 공부했다.

참고 사이트: https://youtu.be/RYdAf2NH0TY

이 영상이 큰 도움이 되었다. 자막은 없지만 천천히 돌려보니 아주 굿이었다.

 

 

코드 및 qt디자이너로 만든 부분

코드

bus_stop.py

import operator
import os
import sys

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5 import uic
from bus_data import *


def resource_path(relative_path):
    base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)


form = resource_path('bus.ui')
form_class = uic.loadUiType(form)[0]


class WindowClass(QMainWindow, form_class):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        # 버튼 누르면 페이지 이동하기
        self.btn_page_0.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.page_0))
        self.btn_page_1.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.page_1))
        self.btn_page_2.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.page_2))
        self.btn_page_3.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.page_3))
        self.btn_page_4.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.page_4))

        # 색변환 함수 연결
        self.btn_page_1.clicked.connect(self.color_changed_1)
        self.btn_page_2.clicked.connect(self.color_changed_2)
        self.btn_page_3.clicked.connect(self.color_changed_3)
        self.btn_page_4.clicked.connect(self.color_changed_4)

        #타이틀 변환
        self.setWindowTitle("광주버스안내도")
        self.setWindowIcon(QIcon('광주.png'))



        # 창전환 모음
        # 버스 노선 검색창
        self.pushButton.clicked.connect(self.bus_route)

        # 버스 상세 정보 안내
        self.pushButton_2.clicked.connect(self.bus_detail_info)

        # 특정 정류장에 지나가는 버스 알려줌
        self.pushButton_3.clicked.connect(self.bus_stop_search)

        # 버스 인기순위 알려줌
        self.pushButton_4.clicked.connect(self.show_bus_stop_ranked)



    # 색변환 함수
    def color_changed_1(self):
        self.btn_page_2.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
        self.btn_page_3.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
        self.btn_page_4.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
        self.btn_page_1.setStyleSheet(
            "color: black;"
            "background-color:rgb(255, 217, 61);"
            "border-radius:5px;"
        )

    def color_changed_2(self):
        self.btn_page_2.setStyleSheet(
            "color: black;"
            "background-color:rgb(255, 217, 61);"
            "border-radius:5px;"
        )
        self.btn_page_3.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
        self.btn_page_4.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
        self.btn_page_1.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
    def color_changed_3(self):
        self.btn_page_2.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
        self.btn_page_3.setStyleSheet(
            "color: black;"
            "background-color:rgb(255, 217, 61);"
            "border-radius:5px;"
        )
        self.btn_page_4.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
        self.btn_page_1.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
    def color_changed_4(self):
        self.btn_page_2.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
        self.btn_page_3.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
        self.btn_page_4.setStyleSheet(
            "color: black;"
            "background-color:rgb(255, 217, 61);"
            "border-radius:5px;"
        )
        self.btn_page_1.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )

    # 버튼 색변환 함수(이것도 내일)
    # def change_color(self):
    #     current_color = self.btn_page_1.palette().button().color()
    #
    #     if current_color == QColor("yellow"):
    #         self.btn_page_1.setStyleSheet("background-color: blue")
    #     else:
    #         self.btn_page_1.setStyleSheet("background-color: yellow")

    def bus_route(self):
        bus_number = self.lineEdit.text()
        route = ""
        if bus_number not in Gwanju_Bus.keys():
            reply = QMessageBox()
            reply.setText("그런 버스가 존재하지 않습니다!\n다시 입력하세요.")
            reply.setWindowTitle("!!")
            # print("없다.")
            reply.exec_()
        else:
            route += f"{bus_number} 버스의 노선은 총 {len(Gwanju_Bus[bus_number])}개 입니다.\n\n"
            for i, j in enumerate(Gwanju_Bus[bus_number]):
                if j == Gwanju_Bus[bus_number][len(Gwanju_Bus[bus_number]) - 1]:
                    route += f"{j:<7}"
                else:
                    if i % 5 == 0:
                        route += "\n"
                    route += f"{j:<5}→"
            self.label_3.setText(route)
        # self.label_3.setAlignment(Qt.AlignTop)
        # self.scrollArea.setWidget(self.label_3) #스크롤바를 만들고 싶은데 일단 포기.

    def bus_detail_info(self):
        bus_number = self.lineEdit_2.text()
        if bus_number not in bus_timetable.keys():
            reply = QMessageBox()
            reply.setText("그런 버스가 존재하지 않습니다!\n다시 입력하세요.")
            reply.setWindowTitle("!!")
            reply.exec_()
        else:
            info = ''
            info += f"운행날짜: {bus_timetable[bus_number]['운행날짜']}\n"
            info += f"첫차출발시간: {bus_timetable[bus_number]['첫차출발시간']}\n"
            info += f"막차출발시간: {bus_timetable[bus_number]['막차출발시간']}\n"
            info += f"주행시간: {bus_timetable[bus_number]['주행시간']}\n"
            info += f"주행간격: {bus_timetable[bus_number]['주행간격']}\n"
            info += f"운행횟수: {bus_timetable[bus_number]['운행횟수']}\n"

            info_time = ''
            info_time += '상행출발시간'
            cnt = 0
            for i in bus_timetable[bus_number]['상행출발시간']:
                if cnt == len(bus_timetable[bus_number]['상행출발시간']) - 1:
                    info_time += f"{i:<5}"
                else:
                    if cnt % 7 == 0:
                        info_time += '\n'
                    info_time += f"{i:<5}→"
                cnt += 1
            # cnt = 0
            # for i in bus_timetable[bus_num]['하행출발시간']:
            #     if cnt == len(bus_timetable[bus_num]['하행출발시간']) - 1:
            #         print(f"{i:<5}")
            #     else:
            #         if cnt % 6 == 0:
            #             print(" ")
            #         print(f"{i:<5}→", end=" ")
            #     cnt += 1
            #print(info_time)

            self.label_6.setText(info)
            self.label_11.setText(info_time)

    def bus_stop_search(self):
        """정류장 입력하면 어떤 버스들이 그 정류장을 지나는지 알려주는 함수"""
        bus_stop_name = self.lineEdit_3.text()
        bus_stop_list = []
        info = ''

        for j, i in enumerate(Gwanju_Bus.values()):
            if bus_stop_name in i:
                bus_stop_list.append(list(Gwanju_Bus.keys())[j])
        #print(bus_stop_list)
        info += f"{bus_stop_name}를 지나는 버스는 {', '.join(bus_stop_list)}입니다."
        #print(info)
        self.label_7.setText(info)

    def show_bus_stop_ranked(self):
        """버스 정류장 순위 알려주는 함수"""
        user_choice = self.lineEdit_4.text()
        rank = ''
        if not user_choice.isdigit():
            reply = QMessageBox()
            reply.setText("숫자만 입력하세요.")
            reply.exec_()
        else:
            empty_dict = {}
            empty_list = []
            for i in Gwanju_Bus.values():
                if type(i) == list:
                    for j in i:
                        empty_list.append(j)
            for m in empty_list:
                if m not in empty_dict:
                    empty_dict[m] = 1
                else:
                    empty_dict[m] += 1
            # print(empty_dict)
            sorted_dict = sorted(empty_dict.items(), key=operator.itemgetter(1), reverse=True)
            # print(sorted_dict)
            cnt = 0
            for m in sorted_dict:
                if cnt < int(user_choice):
                    rank += f"{cnt+1}위: {m[0]}정류장 {m[1]}개의 버스\n"
                cnt += 1

            self.label_9.setText(rank if rank else ' ')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    myWindow = WindowClass()
    myWindow.show()
    app.exec_()

bus_data.py

bus_data.py
0.40MB
bus_stop.py
0.01MB

코드설명

# 버튼 누르면 페이지 이동하기
        self.btn_page_0.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.page_0))
        self.btn_page_1.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.page_1))
        self.btn_page_2.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.page_2))
        self.btn_page_3.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.page_3))
        self.btn_page_4.clicked.connect(lambda: self.stackedWidget.setCurrentWidget(self.page_4))

버튼을 누르면 페이지 이동하게 만드는 부분. lambda는 유튭 영상을 보고 따라했다.

        # 색변환 함수 연결
        self.btn_page_1.clicked.connect(self.color_changed_1)
        self.btn_page_2.clicked.connect(self.color_changed_2)
        self.btn_page_3.clicked.connect(self.color_changed_3)
        self.btn_page_4.clicked.connect(self.color_changed_4)

색변환 함수로 연결되는 부분. 원래 함수 하나로만 연결되게 하고 싶었는데, 그렇게 하면 다른 탭을 누를 때 색 초기화를 하지 못해 그냥 함수 4개로 만들었다. 연결된 함수는 다음과 같다.

    def color_changed_1(self):
        self.btn_page_2.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
        self.btn_page_3.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
        self.btn_page_4.setStyleSheet(
            "color: black;"
            "background-color:white;"
            "border-radius:5px;"
        )
        self.btn_page_1.setStyleSheet(
            "color: black;"
            "background-color:rgb(255, 217, 61);"
            "border-radius:5px;"
        )

만약 btn_page_1을 클릭하면 그 버튼만 색이 노랗게 바뀌고 다른 버튼은 흰색을 유지하도록 한다.

원래 파란색으로 하려고 color:whilte로 했는데 노란색으로 수정한 후 black으로 바꾸었다. 지금보니 딱히 폰트를 검정색이라고 지정할 필요는 없었는데.. 

색변환 함수는 나머지는 동일하므로 생략하겠습니다.

 

        #타이틀 변환
        self.setWindowTitle("광주버스안내도")
        self.setWindowIcon(QIcon('광주.png'))



        # 창전환 모음
        # 버스 노선 검색창
        self.pushButton.clicked.connect(self.bus_route)

        # 버스 상세 정보 안내
        self.pushButton_2.clicked.connect(self.bus_detail_info)

        # 특정 정류장에 지나가는 버스 알려줌
        self.pushButton_3.clicked.connect(self.bus_stop_search)

        # 버스 인기순위 알려줌
        self.pushButton_4.clicked.connect(self.show_bus_stop_ranked)

창 이름 바뀌는 부분과, 창 아이콘 바꾸는 부분과

버튼을 클릭했을 때 각종 함수로 연결되는 곳이다.

 

    def bus_route(self):
        bus_number = self.lineEdit.text()
        route = ""
        if bus_number not in Gwanju_Bus.keys():
            reply = QMessageBox()
            reply.setText("그런 버스가 존재하지 않습니다!\n다시 입력하세요.")
            reply.setWindowTitle("!!")
            # print("없다.")
            reply.exec_()
        else:
            route += f"{bus_number} 버스의 노선은 총 {len(Gwanju_Bus[bus_number])}개 입니다.\n\n"
            for i, j in enumerate(Gwanju_Bus[bus_number]):
                if j == Gwanju_Bus[bus_number][len(Gwanju_Bus[bus_number]) - 1]:
                    route += f"{j:<7}"
                else:
                    if i % 5 == 0:
                        route += "\n"
                    route += f"{j:<5}→"
            self.label_3.setText(route)
        # self.label_3.setAlignment(Qt.AlignTop)
        # self.scrollArea.setWidget(self.label_3) #스크롤바를 만들고 싶은데 일단 포기.

버스 노선 갯수와 버스 노선도 알려주는 함수. 예외처리도 만들어봤다.

버스 노선을 5개씩 보여준다. 여기는 프린트문이 필요하지 않으므로 route=''을 만들어서 데이터를 저장하고

라벨에 setText로 그 값을 더해주는 방식으로 만들었다.

스크롤바를 만들고 싶었는데 이건 공부가 조금 더 필요해 보인다. 일단 포기.

 

    def bus_detail_info(self):
        bus_number = self.lineEdit_2.text()
        if bus_number not in bus_timetable.keys():
            reply = QMessageBox()
            reply.setText("그런 버스가 존재하지 않습니다!\n다시 입력하세요.")
            reply.setWindowTitle("!!")
            reply.exec_()
        else:
            info = ''
            info += f"운행날짜: {bus_timetable[bus_number]['운행날짜']}\n"
            info += f"첫차출발시간: {bus_timetable[bus_number]['첫차출발시간']}\n"
            info += f"막차출발시간: {bus_timetable[bus_number]['막차출발시간']}\n"
            info += f"주행시간: {bus_timetable[bus_number]['주행시간']}\n"
            info += f"주행간격: {bus_timetable[bus_number]['주행간격']}\n"
            info += f"운행횟수: {bus_timetable[bus_number]['운행횟수']}\n"

            info_time = ''
            info_time += '상행출발시간'
            cnt = 0
            for i in bus_timetable[bus_number]['상행출발시간']:
                if cnt == len(bus_timetable[bus_number]['상행출발시간']) - 1:
                    info_time += f"{i:<5}"
                else:
                    if cnt % 7 == 0:
                        info_time += '\n'
                    info_time += f"{i:<5}→"
                cnt += 1
            # cnt = 0
            # for i in bus_timetable[bus_num]['하행출발시간']:
            #     if cnt == len(bus_timetable[bus_num]['하행출발시간']) - 1:
            #         print(f"{i:<5}")
            #     else:
            #         if cnt % 6 == 0:
            #             print(" ")
            #         print(f"{i:<5}→", end=" ")
            #     cnt += 1
            #print(info_time)

            self.label_6.setText(info)
            self.label_11.setText(info_time)

버스 상세정보 보여주는 함수

버스 상행시간의 데이터 양이 너무 많아 하행시간은 넣지 않기로 했다. 스크롤바를 배우면 채워넣을 예정.

이것도 위의 방법과 똑같이 만들었다.

 

    def bus_stop_search(self):
        """정류장 입력하면 어떤 버스들이 그 정류장을 지나는지 알려주는 함수"""
        bus_stop_name = self.lineEdit_3.text()
        bus_stop_list = []
        info = ''

        for j, i in enumerate(Gwanju_Bus.values()):
            if bus_stop_name in i:
                bus_stop_list.append(list(Gwanju_Bus.keys())[j])
        #print(bus_stop_list)
        info += f"{bus_stop_name}를 지나는 버스는 {', '.join(bus_stop_list)}입니다."
        #print(info)
        self.label_7.setText(info)

정류장 입력하면 어떤 버스들이 그 정류장을 지나는지 알려주는 함수.

 

    def show_bus_stop_ranked(self):
        """버스 정류장 순위 알려주는 함수"""
        user_choice = self.lineEdit_4.text()
        rank = ''
        if not user_choice.isdigit():
            reply = QMessageBox()
            reply.setText("숫자만 입력하세요.")
            reply.exec_()
        else:
            empty_dict = {}
            empty_list = []
            for i in Gwanju_Bus.values():
                if type(i) == list:
                    for j in i:
                        empty_list.append(j)
            for m in empty_list:
                if m not in empty_dict:
                    empty_dict[m] = 1
                else:
                    empty_dict[m] += 1
            # print(empty_dict)
            sorted_dict = sorted(empty_dict.items(), key=operator.itemgetter(1), reverse=True)
            # print(sorted_dict)
            cnt = 0
            for m in sorted_dict:
                if cnt < int(user_choice):
                    rank += f"{cnt+1}위: {m[0]}정류장 {m[1]}개의 버스\n"
                cnt += 1

            self.label_9.setText(rank if rank else ' ')

버스 정류장 순위 알려주는 함수. 여기서 조금 애먹었다. input처럼 사용자가 입력한 값은 str값이라는것을 기억하자.

알아차린 후 int형으로 바꿔주니 잘 떴다.

 

 

 

qt designer로 만든 부분

메인화면(page0)

 

버스노선검색(page_1)

 

버스상세정보안내(page_2)

 

특정정류장 지나는 버스 검색(page_3)

 

버스정류장 인기순위(page_4)

 

bus.ui
0.02MB

사진자료

 

만든 사진

 

출처: 광주관광재단 

광주시티버스 사진과 광주캐릭터 오메나를 피피티로 만들었다.

 

 

 

 

고민한 내용

1. 버튼 크기를 아래로 늘리고 싶은데 크기조정이 안 되었다. -> minimum size를 조정해서 해결

반장님이 알려주셨다.

이 부분을 수정함으로써 해결했다.

 

2. 버스 정류장 순위를 알려주는 함수를 만들면서

자꾸 실행이 되지 않고 프로그램이 종료되서 for문을 쪼갰는대도 실행이 안 되었다.

 

문제의 코드(원본)

def max_list_bus_stop():
    """버스 정류장 순위 알려주는 함수"""
    print("가장 인기있는 버스 정류장 순위를 알려드립니다.")
    choice = int(input("몇 위까지 볼까요?: "))
    empty_dict = {}
    empty_list = []
    for i in Gwanju_Bus.values():
        if type(i) == list:
            for j in i:
                empty_list.append(j)
                if j not in empty_dict:
                    empty_dict[j] = 0
                    empty_dict[j] += 1
                else:
                    empty_dict[j] += 1

    # max_num = max(list(empty_dict.values()))
    # min_num = min(list(empty_dict.values()))

    sorted_dict = sorted(empty_dict.items(), key=operator.itemgetter(1), reverse=True)

    cnt = 0
    for m, n in sorted_dict:
        if cnt < choice:
            print(f"{cnt + 1}위: {m} 정류장, {n}개의 버스")
            cnt += 1
        else:
            break

 

 

수정후 코드(완)

import operator

def show_bus_stop_ranked(self):
    """버스 정류장 순위 알려주는 함수"""
    user_choice = self.lineEdit_4.text()
    rank = ''
    if not user_choice.isdigit():
        reply = QMessageBox()
        reply.setText("숫자만 입력하세요.")
        reply.exec_()
    else:
        user_choice = int(user_choice)  # 수정된 부분
        empty_dict = {}
        empty_list = []
        for i in Gwanju_Bus.values():
            if type(i) == list:
                for j in i:
                    empty_list.append(j)
        for m in empty_list:
            if m not in empty_dict:
                empty_dict[m] = 1
            else:
                empty_dict[m] += 1
        sorted_dict = sorted(empty_dict.items(), key=operator.itemgetter(1), reverse=True)
        cnt = 0
        for m in sorted_dict:
            if cnt < user_choice:
                rank += f"{m[0]}, {m[1]}\n"
            cnt += 1

        self.label_9.setText(rank if rank else ' ')

lineEdit에 입력한 부분을 int형으로 바꾸어줘야 한다는 것이었다.

 

QLineEdit에서 입력받은 값은 항상 문자열 형태로 반환된다.

따라서, 숫자를 입력해도 lineEdit에서 반환되는 값은 문자열 형태이기 때문에, 이를 int로 변환해주어야 한다.

 

3. setWordWrap () / wordWrap () : 레이블 내 텍스트가 레이블 크기보다 클 경우 띄어쓰기 기준으로 줄바꿈을 할지 여부이다. 큐티 디자이너에 보면 우측 하단에 있어서 체크하면 된다.

요부분

참고 사이트: https://wikidocs.net/162354

 

02-01. 레이블 (QLabel)

##QLabel ※ 본 예시는 ui 파일을 class로 변환 해서 진행되었습니다. 예시 코드를 실행하기 위해서는 반드시 [00-01. 기본설정 Ui파일을 class로 변환](ht…

wikidocs.net


코드 시연화면

 

 

기록용 파일

bus_stop.zip
1.16MB

 

profile

소연의_개발일지

@ssoyxon

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!