목차
- 개발환경
- 개발완료보고서
- 요구사항보고서
- 일정표
- db 테이블 구조화, ERD
- 순서도
- 목업 이미지, QT디자인
- 파일 첨부
- 실행 화면(캡쳐, 영상)
- 소스코드 전문
- 서버 관련 코드
- 클라이언트 관련 코드
- 메인 함수
- 운영체제: Window OS, Window 10
- 개발언어: Python 3.11
- 개발 툴: Pycharm
- DBSM: PostgreSQL
- 추가 패키지: PyQt, Qt Desinger
개발완료보고서
요구사항분석서
일정표
DB 테이블 구조화, ERD
순서도
목업이미지, QT 제작 이미지
목업 이미지
QT 제작 이미지
파일 첨부
https://github.com/guaba98/TeamCollaborationTool/tree/main
GitHub - guaba98/TeamCollaborationTool: 팀 일정 협업 프로그램 제작
팀 일정 협업 프로그램 제작. Contribute to guaba98/TeamCollaborationTool development by creating an account on GitHub.
github.com
실행 화면
실행영상
관리자 화면 실행 영상
소스코드 전문
서버 관련
class server.py
import json
import sqlite3
import select
from socket import *
from threading import *
from main_code.domain.class_db_connector import DBConnector
from main_code.domain.class_db_connector import DBConnector
# 사용할 구분자
header_split = chr(1)
list_split_1 = chr(2)
list_split_2 = chr(3)
class Server():
'''
실습실 소연: 10.10.20.103
실습실 종혁: 10.10.20.109
기숙사 독서실 : 192.168.0.88
'''
# HOST = '10.10.20.103'#gethostbyname(gethostname())
HOST = gethostbyname(gethostname())
PORT = 5050
BUFFER = 50000
FORMAT = 'utf-8'
connected_member = list()
def __init__(self, db_conn: DBConnector):
self._serverSocket = socket(AF_INET, SOCK_STREAM)
self.db_conn = db_conn
self.server_socket = None
self.config = None
self.sockets_list = list()
self.clients = dict()
self.thread_for_run = None
self.run_signal = True
def start(self):
if self.thread_for_run is not None: # 실행중이면 종료 시키기
return
self.server_socket = socket(AF_INET, SOCK_STREAM) # AF_INET(ipv4를 의미)
self.server_socket.bind((self.HOST, self.PORT)) # 바인딩
self.server_socket.listen() # 리슨 시작
self.sockets_list.clear() # 소켓리스트 클리어
self.sockets_list.append(self.server_socket)
self.run_signal = True
self.thread_for_run = Thread(target=self.run)
self.thread_for_run.start()
def stop(self):
self.run_signal = False
if self.thread_for_run is not None:
self.thread_for_run.join()
self.server_socket.close()
self.thread_for_run = None
def run(self):
while True:
if self.run_signal is False:
break
try:
read_sockets, _, exception_sockets = select.select(self.sockets_list, [], self.sockets_list, 0.1)
except Exception:
continue
for notified_socket in read_sockets:
if notified_socket == self.server_socket:
client_socket, client_address = self.server_socket.accept()
user = self.receive_message(client_socket)
if user is False:
continue
self.sockets_list.append(client_socket)
self.clients[client_socket] = user
else:
message = self.receive_message(notified_socket)
if message is False:
self.sockets_list.remove(notified_socket)
del self.clients[notified_socket]
continue
for notified_socket in exception_sockets:
self.sockets_list.remove(notified_socket)
del self.clients[notified_socket]
def send_message(self, client_socket: socket, result):
client_socket.send(result)
def receive_message(self, client_socket: socket):
try:
recv_message = client_socket.recv(self.BUFFER)
decode_msg = recv_message.decode(self.FORMAT).strip() # recv 메시지
header = decode_msg.split(header_split)[0] # recv 메시지의 header
if header == 'login': # client에서 유저 id pw를 받아와 db에서 조회후 client에 결과값을 보낸다
substance = decode_msg.split(header_split)[1]
data = substance.split(list_split_1)
id, pw = data
result = self.db_conn.log_in(id, pw)
if result is False: # 아이디와 비밀번호가 없으면 False를 보낸다
response_header = f"{f'login{header_split}{False}':{self.BUFFER}}".encode(self.FORMAT)
self.send_message(client_socket, response_header)
else: # 아이디와 비밀번호가 맞으면 유저정보를 보내준다
user_info = json.dumps(result)
self.db_conn.insert_login_log(login_id=id) # 로그인 기록 저장
response_header = f"{f'login{header_split}{user_info}'}"
client_socket.send(bytes(response_header, "UTF-8"))
elif header == 'duple': # 회원가입 아이디 중복확인
substance = decode_msg.split(header_split)[1]
join_username = substance
result = self.db_conn.duple_reg_id(join_username) # DB에 연결해 아이디 중복확인
if result: # 사용 가능한 아이디일 때
response_header = f"{f'duple{header_split}{True}':{self.BUFFER}}".encode(self.FORMAT)
self.send_message(client_socket, response_header)
else: # 사용 불가능한 아이디일 때 (중복일 때)
response_header = f"{f'duple{header_split}{False}':{self.BUFFER}}".encode(self.FORMAT)
self.send_message(client_socket, response_header)
elif header == 'insertuser': # 회원가입
register_user_info = decode_msg.split(header_split)[1]
register_user_info =eval(register_user_info)
result = self.db_conn.insert_user(register_user_info)
if result is True:
response_header = f"{f'insertuser{header_split}{True}':{self.BUFFER}}".encode(self.FORMAT)
self.send_message(client_socket, response_header)
elif result is False:
response_header = f"{f'insertuser{header_split}{False}':{self.BUFFER}}".encode(self.FORMAT)
self.send_message(client_socket, response_header)
elif header == 'send_chat': # 채팅 받기
send_chat = decode_msg.split(header_split)[1] # 데이터 받아오기
send_chat2 = send_chat.split(list_split_1)
user_no, team_no, name, chat = send_chat2
result = self.db_conn.insert_chat_log(user_no, chat)
response_header = f"{f'recv_chat{header_split}{user_no}{list_split_1}{team_no}{list_split_1}{name}{list_split_1}{chat}'}" # 헤더만들기
clients = self.clients.copy()
for i in clients:
try:
i.send(bytes(response_header, "UTF-8"))
except:
continue
elif header == 'get_notice': # 공지 client에 보내주기
recv_msg = decode_msg.split(header_split)[1]
recv_msg = recv_msg.split(list_split_1)
user_no, user_nn = recv_msg
if '관리자' in user_nn:
result = self.db_conn.return_notice_all_data()
else:
result = self.db_conn.get_notice_list(user_no)
result = json.dumps(result)
response_header = f"{f'recv_get_notice{header_split}{result}'}"
client_socket.send(bytes(response_header, "UTF-8"))
elif header == 'get_todolist': #
todolist_info = decode_msg.split(header_split)[1] # 데이터 받아오기
todolist_info = todolist_info.split(list_split_1)
user_no, team_name = todolist_info
# 투두 리스트 받아오기
todo_result = self.db_conn.get_todo_list(user_no)
# 멤버 받아오기
member_result = self.db_conn.return_team_members(user_no)
# 합치기
result = todo_result ,member_result
result = json.dumps(result)
response_header = f"{f'recv_get_todolist{header_split}{result}'}"
client_socket.send(bytes(response_header, "UTF-8"))
elif header == 'get_todolist2': #
todolist_info = decode_msg.split(header_split)[1] # 데이터 받아오기
todolist_info = todolist_info.split(list_split_1)
user_id, user_name, user_no = todolist_info
# 투두 리스트 받아오기
result = self.db_conn.get_todo_list(user_no)
# 합치기
result = json.dumps(result)
response_header = f"{f'recv_get_member_todo_list_for_admin{header_split}{result}{list_split_1}{user_id}{list_split_1}{user_name}'}"
client_socket.send(bytes(response_header, "UTF-8"))
elif header == 'update_user_message':
proflie_message = decode_msg.split(header_split)[1]
proflie_message = proflie_message.split(list_split_1)
user_no, user_message = proflie_message
self.db_conn.update_profile_message(user_no, user_message)
response_header = f"{f'update_user_message{header_split}{user_message}':{self.BUFFER}}".encode(self.FORMAT)
self.send_message(client_socket, response_header)
elif header == 'update_todo_checked':
proflie_message = decode_msg.split(header_split)[1]
proflie_message = proflie_message.split(list_split_1)
todo_id, checked = proflie_message
self.db_conn.update_todo_list(todo_id, int(checked))
elif header == 'insert_todo':
proflie_message = decode_msg.split(header_split)[1]
proflie_message = eval(proflie_message)
title, contents, user_no = proflie_message
self.db_conn.insert_todo_list(user_no, title, contents)
response_header = f"{f'recv_insert_todo{header_split}':{self.BUFFER}}".encode(self.FORMAT)
self.send_message(client_socket, response_header)
elif header == 'insert_notice':
proflie_message = decode_msg.split(header_split)[1]
proflie_message = eval(proflie_message)
title, contents, team = proflie_message
title_no = self.db_conn.return_team_num(team)
self.db_conn.insert_notice_data(title_no, title, contents)
response_header = f"{f'recv_insert_notice{header_split}':{self.BUFFER}}".encode(self.FORMAT)
self.send_message(client_socket, response_header)
# 팀목록 요청받음
elif header == 'get_team_name_list':
result = self.db_conn.return_team_name()
response_header = f"{f'recv_get_team_name_list{header_split}{result}':{self.BUFFER}}".encode(self.FORMAT)
self.send_message(client_socket, response_header)
elif header == 'get_team_name_list2':
result = self.db_conn.return_team_name()
response_header = f"{f'recv_get_team_name_list2{header_split}{result}':{self.BUFFER}}".encode(self.FORMAT)
self.send_message(client_socket, response_header)
# 팀이름을 인자로 멤버들 받아오기
elif header == 'get_team_member':
team_name = decode_msg.split(header_split)[1]
result = self.db_conn.return_team_members_for_admin(team_name)
result = json.dumps(result)
response_header = f"{f'recv_get_team_member{header_split}{result}'}"
client_socket.send(bytes(response_header, "UTF-8"))
elif header == 'delete_notice':
notice_title = decode_msg.split(header_split)[1]
result = self.db_conn.delete_notice_data(notice_title)
elif header == 'admin_del_todo_list_send':
result = decode_msg.split(header_split)[1]
self.db_conn.delete_todo_data(result)
elif header == 'admin_todo_checked_send':
result = decode_msg.split(header_split)[1]
todo_id, checked = result.split(list_split_1)
result = self.db_conn.update_todo_list(todo_id, checked)
# 그래프 만드는 값 보내기
elif header == 'get_matplotlib':
result = decode_msg.split(header_split)[1]
result = self.db_conn.return_todo_list_dict(result)
result = json.dumps(result)
response_header = f"{f'get_matplotlib{header_split}{result}'}"
client_socket.send(bytes(response_header, "UTF-8"))
elif header == 'admin_todo_list_plus':
result = decode_msg.split(header_split)[1]
title, contents, user_id = result.split(list_split_1)
user_no = self.db_conn.return_user_no(user_id)
self.db_conn.insert_admin_todo_list(user_no, title, contents)
result = self.db_conn.return_todo_list_by_title(title)
result = json.dumps(result)
response_header = f"{f'recv_get_member_todo_list_for_admin2{header_split}{result}'}"
client_socket.send(bytes(response_header, "UTF-8"))
elif header == 'get_chatin_log':
result = decode_msg.split(header_split)[1]
user_id = result
chat_log = self.db_conn.return_chat_log(user_id)
result = json.dumps(chat_log)
response_header = f"{f'recv_get_chatin_log{header_split}{result}'}"
client_socket.send(bytes(response_header, "UTF-8"))
except:
pass
클라이언트 관련
class_clinet.py
from threading import *
from socket import *
# import socket
# _SERVER_IP = '10.10.20.109'
_SERVER_IP = gethostbyname(gethostname())
_SERVER_PORT = 5050
BUFFER = 50000
FORMAT = "utf-8"
_CONNECT = (_SERVER_IP, _SERVER_PORT)
header_split = chr(1)
list_split_1 = chr(2)
list_split_2 = chr(3)
class ClientApp:
def __init__(self, client_controller=None):
super().__init__()
self.client_controller = client_controller
self.client_socket = None
self._connected = None
self.connect_server()
self.listeningThread = Thread(target=self.check_server_response, daemon=True)
self.listeningThread.start()
# client 로그인 유저 정보 저장
self.user_no = None
self.user_id = None
self.user_name = None
self.user_pw = None
self.user_nickname = None
self.user_message = None
self.user_create_date = None
self.user_team = None
self.team_no = 1
def connect_server(self):
self.client_socket = socket(AF_INET, SOCK_STREAM)
self.client_socket.connect(_CONNECT)
message = f"{f'enter{header_split}접속한다':{BUFFER}}".encode(FORMAT)
self.client_send_message(message)
self._connected = True
def client_send_message(self, message):
self.client_socket.send(message)
def client_send_chat_message(self, input_chat):
team_no = 1
message = f"{f'send_chat{header_split}{self.user_no}{list_split_1}{team_no}{list_split_1}{self.user_name}{list_split_1}{input_chat}':{BUFFER}}".encode(
FORMAT)
self.client_socket.send(message)
def client_send_get_todolist(self):
message = f"{f'get_todolist{header_split}{self.user_no}{list_split_1}{self.team_no}':{BUFFER}}".encode(
FORMAT)
self.client_socket.send(message)
def client_send_json_message(self, message):
self.client_socket.send((bytes(message, "UTF-8")))
def check_server_response(self):
while self._connected:
try:
response = self.client_socket.recv(BUFFER).decode(FORMAT).strip()
self._parse_packet(response)
except Exception as e:
pass
def _parse_packet(self, p: str):
parsed = p.split(header_split)
header = parsed[0].strip()
if header == 'login':
result = parsed[1]
if result == 'False':
self.client_controller.emit_login(False)
else:
result = eval(result)
result = result[0]
self.user_no, self.user_name, self.user_id, self.user_pw, self.user_nickname, self.user_message, self.user_create_date, self.user_team = result
self.client_controller.emit_login(True)
elif header == 'duple':
result = parsed[1]
if result == 'False':
self.client_controller.emit_duple(False)
else:
self.client_controller.emit_duple(True)
elif header == 'insertuser':
result = parsed[1]
if result == 'False':
self.client_controller.emit_insertuser(False)
else:
self.client_controller.emit_insertuser(True)
if header == 'recv_chat':
result = parsed[1]
result = result.split(list_split_1)
self.client_controller.emit_recv_chat(result)
elif header == 'recv_get_notice':
result = parsed[1]
result = eval(result)
self.client_controller.emit_recv_get_notice(result)
elif header == 'recv_get_todolist':
result = parsed[1]
result = eval(result)
self.client_controller.emit_recv_get_todolist(result)
elif header == 'recv_get_member_todo_list_for_admin':
result = parsed[1]
result = result.split(list_split_1)
todo_list, user_id, user_name = result
todo_list = eval(todo_list)
result = todo_list, user_id, user_name
self.client_controller.emit_member_todo_list_for_admin(result)
elif header == 'recv_get_member_todo_list_for_admin2':
result = parsed[1]
todo_list = eval(result)
self.client_controller.emit_member_todo_list_for_admin2(todo_list)
elif header == 'update_user_message':
result = parsed[1]
self.user_message = result
self.client_controller.emit_update_user_message()
elif header == 'recv_insert_todo':
result = parsed[1]
self.client_controller.emit_refresh_todolist()
elif header == 'recv_insert_notice':
result = parsed[1]
self.client_controller.emit_refresh_notice()
elif header == 'recv_get_team_name_list':
result = parsed[1]
result = eval(result)
self.client_controller.emit_admin_login(result)
elif header == 'recv_get_team_name_list2':
result = parsed[1]
result = eval(result)
self.client_controller.emit_set_combobox(result)
elif header == 'recv_get_team_member':
result = parsed[1]
result = eval(result)
self.client_controller.emit_get_team_member(result)
elif header == 'get_matplotlib':
result = parsed[1]
result = eval(result)
self.client_controller.emit_set_matplotlib(result)
elif header == 'recv_get_chatin_log':
result = parsed[1]
result = eval(result)
self.client_controller.emit_get_chatin_log(result)
client_controller.py
import random
import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import QPoint, Qt, pyqtSignal
from class_client.class_client import ClientApp
# ui 임풜트 예아
from main_code.front.main_window import NoticeBorad
header_split = chr(1)
list_split_1 = chr(2)
list_split_2 = chr(3)
BUFFER = 50000
FORMAT = "utf-8"
def set_main_window(clientcontroller):
main_window = NoticeBorad(clientcontroller)
return main_window
class ClientController(QtWidgets.QWidget):
def __init__(self, client_app=ClientApp):
super().__init__()
self.client_app = ClientApp(self)
# self.client_app.set_widget(self)
# ui 인슬퉐트화
self.main_window = NoticeBorad(self)
# ui 동작 관련 변수
self.list_widget_geometry_x = None
self.list_widget_geometry_y = None
self.drag_start_position = QPoint(0, 0)
self.main_window = None
# 좌상단 프로필
def emit_update_user_message(self):
self.main_window.update_user_message_signal.emit()
def emit_get_team_member(self, p):
self.main_window.get_team_member_signal.emit(p)
# 그래프
def emit_set_matplotlib(self, p):
self.main_window.set_matplotlib_signal.emit(p)
# 투두 ==============================
def emit_recv_get_todolist(self, p):
self.main_window.recv_get_todolist_signal.emit(p)
def emit_member_todo_list_for_admin(self, p):
self.main_window.member_todo_list_for_admin_signal.emit(p)
def emit_member_todo_list_for_admin2(self, p):
self.main_window.member_todo_list_for_admin_signal2.emit(p)
def emit_refresh_todolist(self):
self.main_window.refresh_todolist_signal.emit()
# 공지 ==============================
def emit_recv_get_notice(self, p):
self.main_window.recv_get_notice_signal.emit(p)
def emit_refresh_notice(self):
self.main_window.refresh_notice_signal.emit()
# 클라이언트에 send메시지 보내기======================================================================
# main_window에서 만든 구분자 send
def controller_send_message(self, message):
self.client_app.client_send_message(message)
# 메시지 send
def controller_send_chat_message(self, input_chat):
self.client_app.client_send_chat_message(input_chat)
def controller_send_get_todolist(self):
self.client_app.client_send_get_todolist()
# 데이터가 많아 list로 보낼때
def controller_send_json_message(self, message):
self.client_app.client_send_json_message(message)
# widget 이동 함수============================================================
def mousePressEvent(self, widget, event):
self.drag_start_position = QPoint(widget.x(), widget.y())
if event.button() == Qt.LeftButton:
self.drag_start_position = event.globalPos() - widget.frameGeometry().topLeft()
event.accept()
def mouseMoveEvent(self, widget, event):
if event.buttons() == Qt.LeftButton:
widget.move(event.globalPos() - self.drag_start_position)
event.accept()
# 런처 실행시 나오는 window ===========================================================================
def run(self): # 시작화면 show
self.main_window = set_main_window(self)
# self.main_window.show()
self.main_window.show()
def re_(self):
self.main_window = set_main_window(self)
self.main_window.show()
# self.main_window.show()
# 로그인 ===============================================================
def emit_login(self, p):
# 로그인 결과값 main에 전달 False면 실패창 True면 성공창 main화면 전환
if p:
self.main_window.recv_login_signal.emit(p)
else:
self.main_window.recv_login_signal.emit(p)
def emit_admin_login(self, p):
self.main_window.admin_login_signal.emit(p)
# 회원가입 ============================================================
def emit_duple(self, result): # 아이디 중복 확인 결과 보내기
self.main_window.reg_id_lab_signal.emit(result)
def emit_set_combobox(self, result):
self.main_window.set_combobox_signal.emit(result)
def emit_insertuser(self, result): # 회원가입 성공 결과 보내기
self.main_window.recv_emit_insertuser.emit(result)
def send_register_user_info(self):
pass
# 채팅=====================================================================
# 서버에서 받은 메시지을 누가 보낸것 인지 구분
def emit_recv_chat(self, result):
user_no, team_no, name, chat = result
if user_no == str(self.client_app.user_no): # 본인이 보낸 메시지면
self.main_window.emit_signal_my_chat.emit(result)
else: # 다른 유저가 보낸 메시지면
self.main_window.emit_signal_chat.emit(result)
def emit_get_chatin_log(self, result):
for i in result:
self.main_window.emit_signal_chat.emit(i)
메인 윈도우
main_window.py
# 모듈
import json
import sys
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.font_manager as fm
from PyQt5.QtWidgets import QMainWindow, QLayout, QLabel, QPushButton, QLineEdit, QTextEdit, QGraphicsDropShadowEffect, \
QApplication
from PyQt5.QtCore import Qt, pyqtSignal, QSize, QTimer
from PyQt5.QtGui import QFontDatabase, QIcon, QColor, QPixmap
# UI
from main_code.front.message import YourMsg, MyMsg # 메세지
# from main_code.front.client_controller import ClientController
from main_code.front.ui.ui_class_notice_board import Ui_NoticeBoard # 메인 화면
from main_code.front.profile_widget import ProFile # 프로필 변경
from main_code.front.category_list import CtgList # 카테고리 리스트
from main_code.front.Warning_dialog import DialogWarning # 경고창
from main_code.front.Font import Font # 폰트 클래스
from main_code.front.notice import Notice # 공지 캐러셀
from main_code.front.todolist import TodoList # 투두리스트 캐러셀
from main_code.front.notice_dialog import DialogNoticeAdd, DialogToDoAdd # 공지 다이얼로그, 투두리스트 다이얼로그
from main_code.front.team_process_list import MemberList # 관리자 창에서 보이는 멤버 리스트 캐럿셀
from main_code.front.admin_todo_edit_dialog import AdminTodoAdd # 관리자가 개인별 투두리스트 조회 및 추가하는 창
# 전역변수
header_split = chr(1)
list_split_1 = chr(2)
list_split_2 = chr(3)
BUFFER = 50000
FORMAT = "utf-8"
# def character_page_event(img):
# mywindow2 = AdminTodoAdd(img) # 캐릭터 버튼 프래스 이밴트 다이얼 로그
# mywindow2.exec()
class NoticeBorad(QMainWindow, Ui_NoticeBoard):
# 시그널 선언
reg_id_lab_signal = pyqtSignal(bool)
recv_emit_insertuser = pyqtSignal(bool)
emit_signal_my_chat = pyqtSignal(list)
emit_signal_chat = pyqtSignal(list)
recv_login_signal = pyqtSignal(bool)
recv_get_notice_signal = pyqtSignal(list)
recv_get_todolist_signal = pyqtSignal(list)
member_todo_list_for_admin_signal = pyqtSignal(tuple)
member_todo_list_for_admin_signal2 = pyqtSignal(list)
refresh_todolist_signal = pyqtSignal()
refresh_notice_signal = pyqtSignal()
admin_login_signal = pyqtSignal(list)
set_combobox_signal = pyqtSignal(list)
update_user_message_signal = pyqtSignal()
get_team_member_signal = pyqtSignal(list)
set_matplotlib_signal = pyqtSignal(list)
def __init__(self, client_controller):
super().__init__()
self.adminadd = None
self.ctg_clicked = None
self.user_role = None # 로그인한 유저의 역할
self.setupUi(self)
self.client_controller = client_controller
self.Warn = DialogWarning()
self.font = Font()
self.team_list = None
self.Notice_add = None
self.Todo_add = None
# window frame 설정
self.setAttribute(Qt.WA_TranslucentBackground, True)
self.setWindowFlags(Qt.FramelessWindowHint)
# 변수
self.init_var()
# 버튼 트리거 함수 호출
self.set_btn_trigger()
self.init_func()
def create_donut_chart(self, todo_people: list, todo_cnt: list):
sizes = todo_cnt
labels = todo_people
colors = ['#0F9B58', '#0FBC74', '#53B83A', '#3EC56B', '#1AA867', '#0FAF52', '#0FAF6B', '#53AF37']
# 비율에 따라 도넛 모양으로 그래프 그리기
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', startangle=90, wedgeprops=dict(width=0.4))
# 도넛 모양으로 그래프 그리기
centre_circle = plt.Circle((0, 0), 0.70, fc='white')
fig = plt.gcf()
fig.gca().add_artist(centre_circle)
# 모두 동일한 비율로 그리기
plt.axis('equal')
plt.tight_layout()
# 변수
def init_var(self):
self.ctg_clicked = None # 카테고리 버튼 클릭 확인(공지, 투두리스트)
self.update_timer = QTimer(self)
self.update_timer.setInterval(10)
self.vsb = self.chat_scrollarea.verticalScrollBar()
# widget 이동 함수=======================================================================
def mousePressEvent(self, event):
self.client_controller.mousePressEvent(self, event)
def mouseMoveEvent(self, event):
self.client_controller.mouseMoveEvent(self, event)
# 시그널======================================================================
def init_func(self):
"""클라이언트 - 서버 받는 시그널"""
self.reg_id_lab_signal.connect(self.set_reg_id_lab)
self.recv_emit_insertuser.connect(self.insertuser)
self.emit_signal_my_chat.connect(self.recv_my_chat)
self.emit_signal_chat.connect(self.recv_chat)
self.recv_login_signal.connect(self.login)
self.recv_get_notice_signal.connect(self.set_notice)
self.recv_get_todolist_signal.connect(self.set_todolist)
self.member_todo_list_for_admin_signal.connect(self.show_member_todo_list_for_admin2)
self.member_todo_list_for_admin_signal2.connect(self.show_member_todo_list_for_admin3)
self.refresh_todolist_signal.connect(self.get_todolist)
self.refresh_notice_signal.connect(self.get_notice)
self.admin_login_signal.connect(self.set_admin_ctg)
self.update_timer.timeout.connect(self.set_scrollbar)
self.set_combobox_signal.connect(self.set_combobox)
self.update_user_message_signal.connect(self.set_user_message)
self.get_team_member_signal.connect(self.set_team_member)
self.set_matplotlib_signal.connect(self.set_matplotlib)
self.update_timer.start()
def set_main_page_profil(self):
user_team = self.client_controller.client_app.user_name
user_name = self.client_controller.client_app.user_team
self.user_team.setText(user_team)
self.user_name.setText(user_name)
def set_user_message(self):
state = self.client_controller.client_app.user_message
self.user_state.setText(state)
def set_scrollbar(self):
if self.vsb.value() != self.vsb.maximum():
self.vsb.setValue(self.vsb.maximum())
def set_btn_trigger(self):
"""UI 버튼 시그널 연결"""
self.login_btn.clicked.connect(lambda state: self.click_login_btn()) # 로긴 버튼
self.register_btn.clicked.connect(lambda state: self.click_register_btn()) # 회원가입 화면 이동 버튼
self.reg_register_btn.clicked.connect(lambda state: self.click_reg_register_btn()) # 회원가입 버튼
self.send_btn.clicked.connect(lambda state: self.click_send_btn()) # 채팅 전송 버튼
self.chat_edit.returnPressed.connect(self.click_send_btn)
self.plus_button.clicked.connect(lambda state: self.click_plus_button())
def set_font(self):
"""기본 폰트 적용하는 부분"""
# 로그인 창
self.login_title_lab.setFont(Font.title(1))
self.login_id_lab.setFont(Font.text(3))
self.login_pw_lab.setFont(Font.text(3))
self.login_id_edit.setFont(Font.text(3, False))
self.login_pw_edit.setFont(Font.text(3, False))
self.login_btn.setFont(Font.button(2))
self.register_btn.setFont(Font.button(2))
# 회원가입 창
reg_lab = self.register_page.findChildren(QLabel)
reg_edit = self.register_page.findChildren(QLineEdit)
[lab.setFont(Font.text(3)) for lab in reg_lab]
self.comboBox.setFont(Font.text(3))
[edit.setFont(Font.text(3, False)) for edit in reg_edit]
self.reg_title_lab.setFont(Font.title(2))
self.reg_sub_title.setFont(Font.text(3))
self.reg_register_btn.setFont(Font.button(1))
# -- 메인창
# 프로필창
profile_lab = self.profile_widget.findChildren(QLabel)
[lab.setFont(Font.text(3)) for lab in profile_lab]
# 채팅
self.chat_edit.setFont(Font.text(2))
# 관리자 페이지창
self.team_process_lab.setFont(Font.text(1))
self.team_todo_label.setFont(Font.text(1))
self.label.setFont(Font.title(3))
def ctg_list_show(self):
"""카테고리 넣어주기"""
self.ctg_dict = {
'프로필 수정': ['user.png', None],
'채팅': ['send_black.png', self.chat_page],
'공지': ['bell.png', self.notice_page],
'투두리스트': ['heart.png', self.notice_page],
'로그아웃': ['out.png', self.notice_page]
}
self.ctg_list = list(self.ctg_dict.keys())
self.event_dict = {'채팅': [None, self.pass_, self.plus_button.hide],
'공지': [self.notice_v_lay, self.get_notice, self.plus_button.hide],
'투두리스트': [self.notice_v_lay, self.get_todolist, self.plus_button.show],
'로그아웃': [None, self.logout_, self.plus_button.show],
'....': [self.team_mem_v_lay, self.plus_button.hide]
}
for ctg in self.ctg_list: # 카테고리 이미지, 카테고리 이름 넣어주기
img_name = self.ctg_dict[ctg][0]
ctg_ = CtgList(img_name=img_name, c_name=ctg, parent=self, role=self.user_role)
self.category_v_lay.addWidget(ctg_)
def pass_(self):
pass
def click_plus_button(self):
actions = {
'공지': self.Notice_add.exec_,
'투두리스트': self.Todo_add.exec_
}
action = actions.get(self.ctg_clicked)
if action:
action()
def ctg_list_trigger(self, ctg_name):
"""카테고리에 따라 페이지 변경 혹은 창 띄우기"""
name = self.client_controller.client_app.user_name
state = self.client_controller.client_app.user_message
self.ctg_clicked = ctg_name
for c in self.ctg_list:
if ctg_name == '프로필 수정':
img_path = 'user_green.png'
p_ = ProFile(self, img=img_path, name=name, state=state)
p_.show_dialog()
break
elif ctg_name == c:
self.clear_layout(self.event_dict[ctg_name][0]) # 레이아웃 비우기
self.event_dict[ctg_name][1]()
self.event_dict[ctg_name][2]()
self.inner_stackedWidget.setCurrentWidget(self.ctg_dict[c][1])
def admin_ctg_list_show(self, result):
"""카테고리 넣어주기"""
self.admin_ctg_dict = {
'프로필 수정': ['user.png', None],
'채팅': ['send_black.png', self.chat_page],
'공지': ['bell.png', self.notice_page],
}
# 팀카테고리 이미지, 화면 딕셔너리에 저장
for i in result:
self.admin_ctg_dict[i] = ['user.png', self.team_page]
self.admin_ctg_dict['로그아웃'] = ['out.png', self.notice_page]
self.admin_ctg_list = list(self.admin_ctg_dict.keys())
self.adminevent_dict = {'채팅': [None, self.pass_, self.plus_button.hide],
'공지': [self.notice_v_lay, self.get_notice, self.plus_button.show],
'투두리스트': [self.notice_v_lay, self.get_todolist, self.plus_button.show],
'로그아웃': [None, self.logout_, self.plus_button.show]
}
# 팀카테고리별 클릭 이벤트 설정
for i in result:
self.adminevent_dict[i] = [None, self.get_team_member, self.plus_button.hide]
for ctg in self.admin_ctg_list: # 카테고리 이미지, 카테고리 이름 넣어주기
img_name = self.admin_ctg_dict[ctg][0]
ctg_ = CtgList(img_name=img_name, c_name=ctg, parent=self, role=self.user_role)
self.category_v_lay.addWidget(ctg_)
def logout_(self):
self.close()
self.client_controller.re_()
# self.stackedWidget.setCurrentWidget(self.login_page)
def admin_ctg_list_trigger(self, ctg_name):
"""카테고리에 따라 페이지 변경 혹은 창 띄우기(관리자)"""
name = self.client_controller.client_app.user_name
state = self.client_controller.client_app.user_message
self.ctg_clicked = ctg_name
for c in self.admin_ctg_list:
if ctg_name == '프로필 수정':
p_ = ProFile(self, img=None, name=name, state=state)
p_.show_dialog()
break
# 클릭한 카테고리의 이름이 팀이름중 하나이면
if ctg_name in self.team_list:
self.get_matplotlib(ctg_name)
self.get_team_member(ctg_name)
break
elif ctg_name == c:
self.clear_layout(self.adminevent_dict[ctg_name][0]) # 레이아웃 비우기
self.adminevent_dict[ctg_name][1]()
self.adminevent_dict[ctg_name][2]()
self.inner_stackedWidget.setCurrentWidget(self.admin_ctg_dict[c][1])
def get_matplotlib(self, ctg_name):
message = f"{f'get_matplotlib{header_split}{ctg_name}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
# people, cnt = self.data.return_todo_list_dict('개발부') # db에서 값 가져오기(서버에서 연결하는 부분으로 추가 예정)
def set_matplotlib(self, result):
# 캔버스 만들어서 그래프 그리기
self.clear_layout(self.v_lay_graph)
canvas = FigureCanvas(plt.figure())
self.v_lay_graph.addWidget(canvas)
people, cnt = result
self.create_donut_chart(people, cnt)
def set_admin_ctg(self, result):
self.admin_ctg_list_show(result)
def show_member_todo_list_for_admin(self, user_id, user_no, user_name):
message = f"{f'get_todolist2{header_split}{user_id}{list_split_1}{user_name}{list_split_1}{user_no}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
def show_member_todo_list_for_admin3(self, result):
self.adminadd.test(result)
# 유저 프로필 상메 업데이트
def update_user_message(self, user_message):
message = f"{f'update_user_message{header_split}{self.client_controller.client_app.user_no}{list_split_1}{user_message}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
# 레이아웃 비우기
def clear_layout(self, layout: QLayout):
"""레이아웃 안의 모든 객체를 지웁니다."""
if layout is None or not layout.count():
return
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.setParent(None)
# 아이템이 레이아웃일 경우 재귀 호출로 레이아웃 내의 위젯 삭제
else:
self.clear_layout(item.layout())
# 팀 화면============================================
# 팀이름을 인자로 멤버들 반환요청
def get_team_member(self, ctg_name):
self.label.setText(ctg_name)
message = f"{f'get_team_member{header_split}{ctg_name}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
# 팀원 목록 반환받음
def set_team_member(self, result):
self.inner_stackedWidget.setCurrentWidget(self.team_page)
self.clear_layout(self.team_mem_v_lay)
members = result
for i in members:
user = MemberList(self, i)
self.team_mem_v_lay.addWidget(user)
def admin_del_todo_list_send2(self, todo_title):
message = f"{f'admin_del_todo_list_send{header_split}{todo_title}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
def admin_todo_checked_send2(self, todo_id, checked):
message = f"{f'admin_todo_checked_send{header_split}{todo_id}{list_split_1}{checked}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
def admin_todo_list_plus2(self, title, contents, user_id):
message = f"{f'admin_todo_list_plus{header_split}{title}{list_split_1}{contents}{list_split_1}{user_id}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
pass
# 투루리스트==========================================
def insert_todo_list(self, title, contents):
msg = title, contents, self.client_controller.client_app.user_no
message = f"{f'insert_todo{header_split}{msg}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
def get_todolist(self):
self.clear_layout(self.notice_v_lay) # 레이아웃 비우기
self.client_controller.controller_send_get_todolist()
def set_todolist(self, result):
"""
받아온 유저의 투두리스트들을 캐러셀로 만들어 집어넣는다
:param result:
:return:
"""
people_lab = result[1]
if len(people_lab) == 0:
people_lab = None
else:
pass
for i in result[0]:
todo = TodoList(self, i, people_lab, self.user_role)
self.notice_v_lay.addWidget(todo)
def send_todo_list_checked(self, todo_id, btn_checked):
message = f"{f'update_todo_checked{header_split}{todo_id}{list_split_1}{btn_checked}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
# 공지 화면 =====================================================================================
def insert_notice(self, title, contents, team):
msg = title, contents, team
message = f"{f'insert_notice{header_split}{msg}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
def set_notice(self, result):
for i in result:
notice = Notice(self, i, self.user_role)
self.notice_v_lay.addWidget(notice)
def del_notice(self, title):
msg = title
message = f"{f'delete_notice{header_split}{msg}':{BUFFER}}".encode(FORMAT)
self.client_controller.controller_send_message(message)
# 공지를 db에요청 함수
def get_notice(self):
self.clear_layout(self.notice_v_lay) # 레이아웃 비우기
# 유저가 입력한 로그인 정보 encode
user_no = self.client_controller.client_app.user_no
user_nn = self.client_controller.client_app.user_nickname
message = f"{f'get_notice{header_split}{user_no}{list_split_1}{user_nn}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
# window widget show=======================================================================
def show(self):
message = f"{f'get_team_name_list2{header_split}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
self.stackedWidget.setCurrentWidget(self.login_page)
self.inner_stackedWidget.setCurrentWidget(self.chat_page)
self.set_font() # 폰트 설정
self.style_init() # ui 설정
super().show()
def style_init(self):
# 카테고리 바 그림자 넣기
self.set_background_color(self.category_bar)
def set_background_color(self, obj):
effect = QGraphicsDropShadowEffect()
effect.setColor(QColor(0, 0, 0, 150))
effect.setBlurRadius(5)
effect.setOffset(5, 5) # 객체와 그림자 사이의 거리 또는 변위
obj.setGraphicsEffect(effect)
# 채팅 =========================================================================================
# 전송버튼 클릭시 채팅을 서버에 보내는 함수
def get_chat(self): # 로그인 할때 채팅 기록 불러오기
user_id = self.client_controller.client_app.user_id
message = f"{f'get_chatin_log{header_split}{user_id}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
def click_send_btn(self):
if len(self.chat_edit.text()) >= 1:
input_chat = self.chat_edit.text()
self.chat_edit.clear() # 채팅바 클리어
self.client_controller.controller_send_chat_message(input_chat) # 입력된 채팅 client_controller에 보내기
# 서버에서 채팅 메시지 받는 함수
def recv_my_chat(self, result): # 본인이 보낸 메시지라면
user_no, team_no, name, chat = result
message_widget = MyMsg(name, chat)
self.chat_v_lay.addWidget(message_widget)
def recv_chat(self, result): # 다른 사람이 보낸 메시지라면
if len(result) > 2:
user_no, team_no, name, chat = result
else:
name, chat = result
message_widget = YourMsg(name, chat)
self.chat_v_lay.addWidget(message_widget)
# 채팅방 입장시 db에 저장된 채팅 요청
def send_det_chat(self):
message = f"{f'get_chat{header_split}{user_input_id}':{BUFFER}}".encode(FORMAT)
self.client_controller.controller_send_message(message)
# 로그인 함수=======================================================================
def click_login_btn(self):
user_input_id = self.login_id_edit.text() # 유저가 입력한 id
user_input_pw = self.login_pw_edit.text() # 유저가 입력한 pw
self.login_id_edit.clear()
self.login_pw_edit.clear()
# 유저가 입력한 로그인 정보 encode
message = f"{f'login{header_split}{user_input_id}{list_split_1}{user_input_pw}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
# 로그인 결과 알림 및 화면 전환
def login(self, result):
self.user_role = self.client_controller.client_app.user_nickname
if result:
if '관리자' in self.client_controller.client_app.user_nickname:
# db에 있는 팀명 리스트 요청 리스트 받아올때 카테고리 집어넣기
# 유저가 입력한 로그인 정보 encode
message = f"{f'get_team_name_list{header_split}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
else:
self.ctg_list_show() # 카테고리 넣어주기
self.set_main_page_profil()
self.set_user_message()
self.get_chat()
self.Warn.set_dialog_type(bt_cnt=1, t_type='login_cmplt') # 알림창 띄우기
self.Warn.show_dialog()
self.user_role = self.client_controller.client_app.user_nickname
# self.login_user_role(user_role)
self.stackedWidget.setCurrentWidget(self.main_page) # 화면전환
else:
self.Warn.set_dialog_type(bt_cnt=1, t_type='loginfailed') # 알림창 띄우기
# 회원 가입 함수=======================================================================
def insertuser(self, result):
if result:
self.Warn.set_dialog_type(bt_cnt=1, t_type='register_cmplt')
self.Warn.show_dialog()
self.stackedWidget.setCurrentWidget(self.login_page)
else:
self.Warn.set_dialog_type(bt_cnt=1, t_type='register_failed')
self.Warn.show_dialog()
def set_combobox(self, result):
self.team_list = result
self.Notice_add = DialogNoticeAdd(self, self.team_list)
self.Todo_add = DialogToDoAdd(self, self.team_list)
for i in result:
self.comboBox.addItem(i)
# 회원 가입 화면 으로 이동 하는 함수
def click_register_btn(self):
self.stackedWidget.setCurrentWidget(self.register_page)
# 아이디 중복 검사
def click_reg_register_btn(self):
self.send_duple()
# 아이디 중복검사후 pw name nickname 검사
def click_reg_register_btn2(self):
if self.register_check():
self.register_user()
# 유저가 입력한 아이디 server에 보내서 중복확인
def send_duple(self):
input_reg_id = self.reg_id_edit.text()
message = f"{f'duple{header_split}{input_reg_id}':{BUFFER}}".encode(
FORMAT)
self.client_controller.controller_send_message(message)
# 조건 충족 회원가입 진행
def register_user(self):
input_reg_id = self.reg_id_edit.text()
input_reg_pw = self.reg_pw_edit.text()
input_reg_name = self.reg_name_edit.text()
input_reg_nn = self.reg_nn_edit.text()
input_reg_team = self.comboBox.currentText()
result = [input_reg_id, input_reg_pw, input_reg_name, input_reg_nn, input_reg_team]
user_info = json.dumps(result)
message = f"{f'insertuser{header_split}{user_info}'}"
self.client_controller.controller_send_json_message(message)
# 아이디 중복검사 결과에따른 이벤트
def set_reg_id_lab(self, result):
if result is True:
self.reg_id_lab.setText('ID 사용가능')
self.reg_id_lab.setStyleSheet('color:blue;')
self.click_reg_register_btn2()
else:
self.reg_id_lab.setText('ID 사용불가')
self.reg_id_lab.setStyleSheet('color:red;')
def set_reg_name_lab(self):
self.reg_name_lab.setText('이름은 두 글자 이상이여야 합니다.')
self.reg_name_lab_lab.setStyleSheet('color:red;')
def set_reg_nn_lab(self):
self.reg_nn_lab.setText('닉네임은 두 글자 이상이여야 합니다.')
self.reg_nn_lab.setStyleSheet('color:red;')
def set_reg_pw_lab(self):
self.reg_pw_lab.setText('비밀번호가 같지 않습니다.')
self.reg_pw_lab.setStyleSheet('color:red;')
def set_reg_pw_lab2(self):
self.reg_pw_lab.setText('비밀번호를 6자리 이상 적어주세요.')
self.reg_pw_lab.setStyleSheet('color:red;')
# 유저가 입력한 회원가입조건 검사
def register_check(self):
self.reg_name_lab.setText('이름')
self.reg_nn_lab.setText('닉네임')
self.reg_pw_lab.setText('비밀번호')
if len(self.reg_name_edit.text()) < 2:
self.set_reg_name_lab()
return False
else:
self.reg_name_lab.setStyleSheet('color:black;')
if len(self.reg_nn_edit.text()) < 2:
self.set_reg_nn_lab()
return False
else:
self.reg_nn_lab.setStyleSheet('color:black;')
if len(self.reg_pw_edit.text()) < 6:
self.set_reg_pw_lab2()
return False
else:
self.reg_pw_lab.setStyleSheet('color:black;')
if self.reg_pw_edit.text() != self.reg_pw_check_edit.text():
self.set_reg_pw_lab()
return False
if self.reg_id_lab.text() != 'ID 사용가능':
return False
return True
def log_out(self):
"""로그아웃 함수"""
self.user_role = None
self.stackedWidget.setCurrentWidget(self.login_page)
'공부_백업용 > 프로젝트 모음' 카테고리의 다른 글
[팀프로젝트 주제발표] 머신러닝과 딥러닝을 활용한 출결관리 시스템 주제 발표 (0) | 2023.08.31 |
---|---|
[팀프로젝트] (23.7.31 ~ 8.12) 빅데이터 분석을 활용한 프렌차이즈(올리브영) 창업 지역 추천 프로그램 (0) | 2023.08.21 |
[팀프로젝트] (23.7.10 ~ 7.16) 채팅 프로그램 만들기 개발완료보고서 (2) | 2023.08.19 |
[팀프로젝트] (23.7.3 ~ 7.8) 서울 관광 프로그램 개발완성보고서 (0) | 2023.08.19 |
[개인프로젝트] (23.6.13 ~ 6.23) 메가커피 키오스크 만들기 개발완료보고서 (5) | 2023.08.18 |