초안
파워포인트로 만든 화면
이런 식으로 만들려고 했다. 버튼을 클릭하면 창이 새로 뜨기보다는 밑에서 다 확인할 수 있도록 한다.
이를 위해 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
코드설명
# 버튼 누르면 페이지 이동하기
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)
사진자료
만든 사진
출처: 광주관광재단
광주시티버스 사진과 광주캐릭터 오메나를 피피티로 만들었다.
고민한 내용
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
코드 시연화면
기록용 파일
'개발공부 > Pyqt 파이큐티' 카테고리의 다른 글
[PyQt] 파이큐티 QTableWidget 공부하기 (0) | 2023.05.07 |
---|---|
파이큐티공부_1 로그인창 (0) | 2023.05.07 |
[PyQt] qt designer에서 함수 지정하는 방법 (0) | 2023.05.05 |
[PyQt] 파이큐티와 qt designer활용해 행맨 만들기 (0) | 2023.05.05 |
[PyQt] 파이큐티 콘솔창에서 다운로드하기 (0) | 2023.05.04 |