Я написал p2p-чат, в котором вы общаетесь из окна консоли, а затем решил создать интерфейс для этого.После того, как я сделал интерфейс, я попытался отобразить сообщения на интерфейсе, а не в окне консоли, но что бы я ни пытался, я не смог добиться никакого прогресса.(И интерфейс, и чат отлично работают сами по себе)
это код для интерфейса
from tkinter import *
import time
default_window_size = "400x300"
user_name = "Default"
class ChatInterface(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
# sets default bg for top level windows
self.tl_bg = "#EEEEEE"
self.tl_bg2 = "#EEEEEE"
self.tl_fg = "#000000"
self.font = "Verdana 10"
menu = Menu(self.master)
self.master.config(menu=menu, bd=5)
# Menu bar
# Options
options = Menu(menu, tearoff=0)
menu.add_cascade(label="Options", menu=options)
options.add_command(label="Clear Chat", command=self.clear_chat)
options.add_separator()
options.add_command(label="Exit", command=self.client_exit)
# Chat interface
# frame containing text box with messages and scrollbar
self.text_frame = Frame(self.master, bd=6)
self.text_frame.pack(expand=True, fill=BOTH)
# scrollbar for text box
self.text_box_scrollbar = Scrollbar(self.text_frame, bd=0)
self.text_box_scrollbar.pack(fill=Y, side=RIGHT)
# contains messages
self.text_box = Text(self.text_frame, yscrollcommand=self.text_box_scrollbar.set, state=DISABLED,
bd=1, padx=6, pady=6, spacing3=8, wrap=WORD, bg=None, font="Verdana 10", relief=GROOVE,
width=10, height=1)
self.text_box.pack(expand=True, fill=BOTH)
self.text_box_scrollbar.config(command=self.text_box.yview)
# frame containing user entry field
self.entry_frame = Frame(self.master, bd=1)
self.entry_frame.pack(side=LEFT, fill=BOTH, expand=True)
# entry field
self.entry_field = Entry(self.entry_frame, bd=1, justify=LEFT)
self.entry_field.pack(fill=X, padx=6, pady=6, ipady=3)
# self.users_message = self.entry_field.get()
# frame containing send button
self.send_button_frame = Frame(self.master, bd=0)
self.send_button_frame.pack(fill=BOTH)
# frame containing send button
self.send_button_frame = Frame(self.master, bd=0)
self.send_button_frame.pack(fill=BOTH)
# send button
self.send_button = Button(self.send_button_frame, text="Send", width=6, relief=GROOVE, bg='white',
bd=1, command=lambda: self.send_message(None), activebackground="#FFFFFF",
activeforeground="#000000")
self.send_button.pack(side=LEFT, ipady=5)
self.master.bind("<Return>", self.send_message_event)
def last_sent_label(self, date):
try:
self.sent_label.destroy()
except AttributeError:
pass
self.sent_label = Label(self.entry_frame, font="Verdana 7", text=date, bg=self.tl_bg2, fg=self.tl_fg)
self.sent_label.pack(side=LEFT, fill=X, padx=3)
# File functions
def client_exit(self):
exit()
# clears chat
def clear_chat(self):
self.text_box.config(state=NORMAL)
self.last_sent_label(date="No messages sent.")
self.text_box.delete(1.0, END)
self.text_box.delete(1.0, END)
self.text_box.config(state=DISABLED)
# Send Message
# allows "enter" key for sending msg
def send_message_event(self, event):
self.send_message(user_name)
# joins username with message into publishable format
def send_message(self, username):
user_input = self.entry_field.get()
global user_name
username = user_name + ": "
message = (username, user_input)
readable_msg = ''.join(message)
readable_msg.strip('{')
readable_msg.strip('}')
# clears entry field, passes formatted msg to send_message_insert
if user_input != '':
self.entry_field.delete(0, END)
self.send_message_insert(readable_msg)
# inserts user input into text box
def send_message_insert(self, message):
self.text_box.configure(state=NORMAL)
self.text_box.insert(END, message + '\n')
self.last_sent_label(str(time.strftime( "Last message sent: " + '%B %d, %Y' + ' at ' + '%I:%M %p')))
self.text_box.see(END)
self.text_box.configure(state=DISABLED)
root = Tk()
root.title("Chat GUI")
root.geometry(default_window_size)
print(default_window_size)
root.minsize(360,200)
a = ChatInterface(root)
root.mainloop()
И это код для клиента
import socket
import threading
import errno
import sys
HEADER_LENGTH = 10
IP = "127.0.0.1"
PORT = 5000
current_username = input("Username: ")
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((IP, PORT))
client_socket.setblocking(False)
username = current_username.encode('utf-8')
username_header = f"{len(username):<{HEADER_LENGTH}}".encode('utf-8')
client_socket.send(username_header + username)
def senddata():
while True:
message = input(f'{current_username} > ')
if message == "-Users":
f = open('Connections.txt')
print()
for line in f:
print(line)
f.close()
elif message:
message = message.encode('utf-8')
message_header = f"{len(message):<{HEADER_LENGTH}}".encode('utf-8')
client_socket.send(message_header + message)
def receivedata():
while True:
try:
while True:
username_header = client_socket.recv(HEADER_LENGTH)
if not len(username_header):
print('Connection closed by the server')
sys.exit()
username_length = int(username_header.decode('utf-8').strip())
username = client_socket.recv(username_length).decode('utf-8')
message_header = client_socket.recv(HEADER_LENGTH)
message_length = int(message_header.decode('utf-8').strip())
message = client_socket.recv(message_length).decode('utf-8')
if message[0] == "@":
i = 1
while message[i] != " ":
i += 1
target = message[1:i]
if target == current_username:
realmessage = message[i + 1:len(message)]
sys.stdout.write('\r' + f'{username} > {realmessage}' + '\n')
else:
sys.stdout.write('\r' + f'{username} > {message}' + '\n')
except IOError as e:
if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
print('Reading error: {}'.format(str(e)))
sys.exit()
continue
except Exception as e:
print('Reading error: '.format(str(e)))
sys.exit()
recv_thread = threading.Thread(target=receivedata)
recv_thread.setDaemon(True)
recv_thread.start()
senddata()
И, наконец, это серверный код
import socket
import select
import datetime
HEADER_LENGTH = 10
IP = "127.0.0.1"
PORT = 5000
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((IP, PORT))
server_socket.listen()
# List of sockets
sockets_list = [server_socket]
# List of clients
clients = {}
f = open('Connections.txt', 'w')
f.close()
f = open('Messages.txt', 'w')
f.close()
print(f'Listening for connections on {IP}:{PORT}...')
def receive_message(client_socket):
try:
message_header = client_socket.recv(HEADER_LENGTH)
if not len(message_header):
return False
message_length = int(message_header.decode('utf-8').strip())
return {'header': message_header, 'data': client_socket.recv(message_length)}
except:
return False
while True:
read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)
for notified_socket in read_sockets:
if notified_socket == server_socket:
client_socket, client_address = server_socket.accept()
user = receive_message(client_socket)
# If Client disconnected before he sent his name
if user is False:
continue
sockets_list.append(client_socket)
clients[client_socket] = user
f = open('Connections.txt', 'a')
f.write('IP: {}:{}, Username: {}'.format(*client_address, user['data'].decode('utf-8')) + '\n')
f.close()
print('Accepted new connection from {}:{}, username: {}'.format(*client_address,
user['data'].decode('utf-8')))
else:
message = receive_message(notified_socket)
if message is False:
print('Closed connection from: {}'.format(clients[notified_socket]['data'].decode('utf-8')))
sockets_list.remove(notified_socket)
del clients[notified_socket]
continue
user = clients[notified_socket]
f = open('Messages.txt', 'a')
now = datetime.datetime.now()
now = now.strftime("%H:%M:%S")
f.write(user['data'].decode('utf-8') + ' (' + now + '): ' + message["data"].decode("utf-8") + '\n')
f.close()
print(f'Received message from {user["data"].decode("utf-8")}: {message["data"].decode("utf-8")}')
for client_socket in clients:
# Don't send the message to sender
if client_socket != notified_socket:
client_socket.send(user['header'] + user['data'] + message['header'] + message['data'])
for notified_socket in exception_sockets:
sockets_list.remove(notified_socket)
del clients[notified_socket]
Мне очень жаль, что я делюсь всем кодом, но я не уверен, что мне следует поделиться в этом пункте, так как я не мог понять, что делать.
Я просто хочу выбрать имя пользователя из интерфейса и отправлять / получать сообщения из интерфейса, а не из окна консоли, вот и все.