import socket
import threading
import tkinter as tk
from tkinter import scrolledtext, messagebox, simpledialog
class ChatClientGUI:
def __init__(self, host='127.0.0.1', port=5555):
self.host = host
self.port = port
self.client_socket = None
self.nickname = None
self.running = False
# Создаём главное окно
self.root = tk.Tk()
self.root.title("Мессенджер")
self.root.geometry("600x500")
self.root.resizable(True, True)
# Настройка стилей
self.setup_ui()
# Подключаемся к серверу
self.connect_to_server()
def setup_ui(self):
"""Настройка интерфейса"""
# Верхняя панель с информацией
self.top_frame = tk.Frame(self.root, bg='gray', height=40)
self.top_frame.pack(fill=tk.X, padx=5, pady=5)
self.status_label = tk.Label(
self.top_frame,
text="Не подключён",
bg='gray',
fg='white',
font=('Arial', 10)
)
self.status_label.pack(side=tk.LEFT, padx=10)
# Кнопки управления
self.disconnect_btn = tk.Button(
self.top_frame,
text="Отключиться",
command=self.disconnect,
bg='red',
fg='white'
)
self.disconnect_btn.pack(side=tk.RIGHT, padx=5)
# Область отображения сообщений
self.chat_area = scrolledtext.ScrolledText(
self.root,
wrap=tk.WORD,
font=('Arial', 11),
bg='white',
fg='black'
)
self.chat_area.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# Нижняя панель для ввода сообщений
self.bottom_frame = tk.Frame(self.root)
self.bottom_frame.pack(fill=tk.X, padx=5, pady=5)
# Поле ввода сообщения
self.message_entry = tk.Entry(
self.bottom_frame,
font=('Arial', 11),
state='disabled'
)
self.message_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
self.message_entry.bind('<Return>', self.send_message_event)
# Кнопка отправки
self.send_button = tk.Button(
self.bottom_frame,
text="Отправить",
command=self.send_message,
state='disabled',
bg='#4CAF50',
fg='white',
width=10
)
self.send_button.pack(side=tk.RIGHT)
# Меню
self.setup_menu()
def setup_menu(self):
"""Настройка меню"""
menubar = tk.Menu(self.root)
self.root.config(menu=menubar)
# Меню "Файл"
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Файл", menu=file_menu)
file_menu.add_command(label="Подключиться заново", command=self.reconnect)
file_menu.add_separator()
file_menu.add_command(label="Выход", command=self.on_closing)
# Меню "Справка"
help_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Справка", menu=help_menu)
help_menu.add_command(label="О программе", command=self.show_about)
help_menu.add_command(label="Команды", command=self.show_commands)
def connect_to_server(self):
"""Подключение к серверу"""
try:
# Запрашиваем ник
self.nickname = simpledialog.askstring(
"Никнейм",
"Введите ваш никнейм:",
parent=self.root
)
if not self.nickname:
self.root.quit()
return
# Подключаемся к серверу
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client_socket.connect((self.host, self.port))
# Получаем запрос на ввод ника
initial = self.client_socket.recv(1024).decode('utf-8')
if initial == "NICK":
self.client_socket.send(self.nickname.encode('utf-8'))
# Обновляем интерфейс
self.status_label.config(text=f"Подключён как: {self.nickname}")
self.message_entry.config(state='normal')
self.send_button.config(state='normal')
self.disconnect_btn.config(text="Отключиться")
# Запускаем поток для приёма сообщений
self.running = True
receive_thread = threading.Thread(target=self.receive_messages, daemon=True)
receive_thread.start()
# Добавляем сообщение о подключении
self.add_message("Система", f"Вы подключились к серверу как {self.nickname}")
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось подключиться к серверу:\n{str(e)}")
self.root.quit()
def receive_messages(self):
"""Получение сообщений от сервера"""
while self.running:
try:
message = self.client_socket.recv(1024).decode('utf-8')
if message:
# Разбираем сообщение для форматирования
if ": " in message and not message.startswith("Система"):
# Обычное сообщение от пользователя
parts = message.split(": ", 1)
if len(parts) == 2:
self.add_message(parts[0], parts[1])
else:
self.add_message("Сообщение", message)
else:
# Системное сообщение
self.add_message("Система", message)
else:
break
except OSError:
if self.running:
self.add_message("Система", "Соединение с сервером потеряно")
self.disconnect()
break
def send_message(self):
"""Отправка сообщения"""
message = self.message_entry.get().strip()
if message and self.client_socket:
try:
if message == '/quit':
self.disconnect()
else:
self.client_socket.send(message.encode('utf-8'))
self.message_entry.delete(0, tk.END)
except OSError:
self.add_message("Система", "Ошибка при отправке сообщения")
self.disconnect()
def send_message_event(self, event):
"""Обработчик события Enter"""
self.send_message()
def add_message(self, sender, message):
"""Добавление сообщения в чат"""
self.chat_area.config(state='normal')
# Форматируем сообщение
if sender == "Система":
self.chat_area.insert(tk.END, f"\n🔔 {message}\n", "Система")
self.chat_area.tag_config("Система", foreground="red", font=('Arial', 9, 'italic'))
else:
self.chat_area.insert(tk.END, f"\n{sender}: ", "sender")
self.chat_area.insert(tk.END, f"{message}\n", "message")
self.chat_area.tag_config("sender", foreground="blue", font=('Arial', 10, 'bold'))
self.chat_area.tag_config("message", foreground="black", font=('Arial', 10))
self.chat_area.see(tk.END)
self.chat_area.config(state='disabled')
def disconnect(self):
"""Отключение от сервера"""
self.running = False
if self.client_socket:
try:
self.client_socket.close()
except OSError:
pass
self.client_socket = None
self.status_label.config(text="Отключён")
self.message_entry.config(state='disabled')
self.send_button.config(state='disabled')
self.disconnect_btn.config(text="Подключиться", command=self.reconnect)
self.add_message("Система", "Вы отключились от сервера")
def reconnect(self):
"""Переподключение к серверу"""
if self.client_socket:
self.disconnect()
self.connect_to_server()
def show_about(self):
"""Показать информацию о программе"""
about_text = """Мессенджер с графическим интерфейсом
Версия: 1.0
Язык: Python + tkinter
Функции:
• Поддержка множества пользователей
• Системные уведомления
• Отключение/подключение
• Команды: /quit
Для работы требуется сервер (server.py)"""
messagebox.showinfo("О программе", about_text)
def show_commands(self):
"""Показать доступные команды"""
commands_text = """Доступные команды:
/quit - Выход из чата (отключение)
Примечание:
Для приватных сообщений нужна доработка сервера."""
messagebox.showinfo("Команды", commands_text)
def on_closing(self):
"""Обработка закрытия окна"""
self.running = False
if self.client_socket:
try:
self.client_socket.close()
except OSError:
pass
self.root.destroy()
def run(self):
"""Запуск приложения"""
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
self.root.mainloop()
if __name__ == "__main__":
app = ChatClientGUI()
app.run()
import socket
import threading
import tkinter as tk
from tkinter import scrolledtext, messagebox, simpledialog
class ChatClientGUI:
def __init__(self, host='127.0.0.1', port=5555):
self.host = host
self.port = port
self.client_socket = None
self.nickname = None
self.running = False
# Создаём главное окно
self.root = tk.Tk()
self.root.title("Мессенджер")
self.root.geometry("600x500")
self.root.resizable(True, True)
# Настройка стилей
self.setup_ui()
# Подключаемся к серверу
self.connect_to_server()
def setup_ui(self):
"""Настройка интерфейса"""
# Верхняя панель с информацией
self.top_frame = tk.Frame(self.root, bg='gray', height=40)
self.top_frame.pack(fill=tk.X, padx=5, pady=5)
self.status_label = tk.Label(
self.top_frame,
text="Не подключён",
bg='gray',
fg='white',
font=('Arial', 10)
)
self.status_label.pack(side=tk.LEFT, padx=10)
# Кнопки управления
self.disconnect_btn = tk.Button(
self.top_frame,
text="Отключиться",
command=self.disconnect,
bg='red',
fg='white'
)
self.disconnect_btn.pack(side=tk.RIGHT, padx=5)
# Область отображения сообщений
self.chat_area = scrolledtext.ScrolledText(
self.root,
wrap=tk.WORD,
font=('Arial', 11),
bg='white',
fg='black'
)
self.chat_area.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# Нижняя панель для ввода сообщений
self.bottom_frame = tk.Frame(self.root)
self.bottom_frame.pack(fill=tk.X, padx=5, pady=5)
# Поле ввода сообщения
self.message_entry = tk.Entry(
self.bottom_frame,
font=('Arial', 11),
state='disabled'
)
self.message_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
self.message_entry.bind('<Return>', self.send_message_event)
# Кнопка отправки
self.send_button = tk.Button(
self.bottom_frame,
text="Отправить",
command=self.send_message,
state='disabled',
bg='#4CAF50',
fg='white',
width=10
)
self.send_button.pack(side=tk.RIGHT)
# Меню
self.setup_menu()
def setup_menu(self):
"""Настройка меню"""
menubar = tk.Menu(self.root)
self.root.config(menu=menubar)
# Меню "Файл"
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Файл", menu=file_menu)
file_menu.add_command(label="Подключиться заново", command=self.reconnect)
file_menu.add_separator()
file_menu.add_command(label="Выход", command=self.on_closing)
# Меню "Справка"
help_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Справка", menu=help_menu)
help_menu.add_command(label="О программе", command=self.show_about)
help_menu.add_command(label="Команды", command=self.show_commands)
def connect_to_server(self):
"""Подключение к серверу"""
try:
# Запрашиваем ник
self.nickname = simpledialog.askstring(
"Никнейм",
"Введите ваш никнейм:",
parent=self.root
)
if not self.nickname:
self.root.quit()
return
# Подключаемся к серверу
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client_socket.connect((self.host, self.port))
# Получаем запрос на ввод ника
initial = self.client_socket.recv(1024).decode('utf-8')
if initial == "NICK":
self.client_socket.send(self.nickname.encode('utf-8'))
# Обновляем интерфейс
self.status_label.config(text=f"Подключён как: {self.nickname}")
self.message_entry.config(state='normal')
self.send_button.config(state='normal')
self.disconnect_btn.config(text="Отключиться")
# Запускаем поток для приёма сообщений
self.running = True
receive_thread = threading.Thread(target=self.receive_messages, daemon=True)
receive_thread.start()
# Добавляем сообщение о подключении
self.add_message("Система", f"Вы подключились к серверу как {self.nickname}")
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось подключиться к серверу:\n{str(e)}")
self.root.quit()
def receive_messages(self):
"""Получение сообщений от сервера"""
while self.running:
try:
message = self.client_socket.recv(1024).decode('utf-8')
if message:
# Разбираем сообщение для форматирования
if ": " in message and not message.startswith("Система"):
# Обычное сообщение от пользователя
parts = message.split(": ", 1)
if len(parts) == 2:
self.add_message(parts[0], parts[1])
else:
self.add_message("Сообщение", message)
else:
# Системное сообщение
self.add_message("Система", message)
else:
break
except OSError:
if self.running:
self.add_message("Система", "Соединение с сервером потеряно")
self.disconnect()
break
def send_message(self):
"""Отправка сообщения"""
message = self.message_entry.get().strip()
if message and self.client_socket:
try:
if message == '/quit':
self.disconnect()
else:
self.client_socket.send(message.encode('utf-8'))
self.message_entry.delete(0, tk.END)
except OSError:
self.add_message("Система", "Ошибка при отправке сообщения")
self.disconnect()
def send_message_event(self, event):
"""Обработчик события Enter"""
self.send_message()
def add_message(self, sender, message):
"""Добавление сообщения в чат"""
self.chat_area.config(state='normal')
# Форматируем сообщение
if sender == "Система":
self.chat_area.insert(tk.END, f"\n🔔 {message}\n", "Система")
self.chat_area.tag_config("Система", foreground="red", font=('Arial', 9, 'italic'))
else:
self.chat_area.insert(tk.END, f"\n{sender}: ", "sender")
self.chat_area.insert(tk.END, f"{message}\n", "message")
self.chat_area.tag_config("sender", foreground="blue", font=('Arial', 10, 'bold'))
self.chat_area.tag_config("message", foreground="black", font=('Arial', 10))
self.chat_area.see(tk.END)
self.chat_area.config(state='disabled')
def disconnect(self):
"""Отключение от сервера"""
self.running = False
if self.client_socket:
try:
self.client_socket.close()
except OSError:
pass
self.client_socket = None
self.status_label.config(text="Отключён")
self.message_entry.config(state='disabled')
self.send_button.config(state='disabled')
self.disconnect_btn.config(text="Подключиться", command=self.reconnect)
self.add_message("Система", "Вы отключились от сервера")
def reconnect(self):
"""Переподключение к серверу"""
if self.client_socket:
self.disconnect()
self.connect_to_server()
def show_about(self):
"""Показать информацию о программе"""
about_text = """Мессенджер с графическим интерфейсом
Версия: 1.0
Язык: Python + tkinter
Функции:
• Поддержка множества пользователей
• Системные уведомления
• Отключение/подключение
• Команды: /quit
Для работы требуется сервер (server.py)"""
messagebox.showinfo("О программе", about_text)
def show_commands(self):
"""Показать доступные команды"""
commands_text = """Доступные команды:
/quit - Выход из чата (отключение)
Примечание:
Для приватных сообщений нужна доработка сервера."""
messagebox.showinfo("Команды", commands_text)
def on_closing(self):
"""Обработка закрытия окна"""
self.running = False
if self.client_socket:
try:
self.client_socket.close()
except OSError:
pass
self.root.destroy()
def run(self):
"""Запуск приложения"""
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
self.root.mainloop()
if __name__ == "__main__":
app = ChatClientGUI()
app.run()