利用python socket+tkinter构建简陋聊天窗口

今天在之前socket 通信的基础上,使用tpython 自带的tkinter构建了简单的聊天工具,界面相当简陋,只能在局域网下实现双方通信。

平台

  • windows10
  • python 3.6.5

代码

其实就两个程序,TCPserver.pyTCPclient.py,分别实现服务端和客户端的聊天界面,先运行服务端,再运行客户端,客户端运行之后需要输入服务端的ip,本地运行的话使用环回地址即可。

from socket import *
import tkinter as tk
import tkinter.scrolledtext as tst
import time
import tkinter.messagebox
import threading

class Application(tk.Frame):
	def __init__(self,master):
		tk.Frame.__init__(self,master)
		self.grid()
		self.createWidgets()
	def createWidgets(self):
		#显示聊天窗口
		self.textEdit=tst.ScrolledText(self,width=50,height=15)
		self.textEdit.grid(row=0,column=0,rowspan=1,columnspan=4)
		#定义标签,改变字体颜色
		self.textEdit.tag_config('server',foreground='red')
		self.textEdit.tag_config('guest',foreground='blue')

		#编辑窗口
		self.inputText=tk.Text(self,width=40,height=5)
		self.inputText.grid(row=1,column=0,columnspan=1)
		#定义快捷键,按下回车即可发送消息
		self.inputText.bind("<KeyPress-Return>",self.textSendReturn)
		#发送按钮
		self.btnSend=tk.Button(self,text='send',command=self.textSend)
		self.btnSend.grid(row=1,column=3)
		#开启一个线程用于接收消息并显示在聊天窗口
		t=threading.Thread(target=self.getInfo)
		t.start()

	def textSend(self):
		#获取Text的所有内容
		str=self.inputText.get('1.0','end-1c')
		if str!="" :
			#显示发送时间和发送消息
			timemsg='服务端'+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())+'\n'
			self.textEdit.config(state='normal')
			self.textEdit.insert(tk.END,timemsg,'server')
			self.textEdit.insert(tk.END,str+'\n')
			#将滚动条拉到最后显示最新消息
			self.textEdit.see(tk.END)
			self.textEdit.config(state='disabled')
			self.inputText.delete(0.0,tk.END)	#删除输入框的内容
			#发送数据到服务端
			sendMessage=bytes(str,encoding='utf8')
			#发送输入的数据,与UDP有点不同,使用的是send方法,不需要指定服务器和端口,因为已经建立了一条tcp连接
			connectionSocket.send(sendMessage)
		else:
			tk.messagebox.showinfo('警告',"不能发送空白信息!")

	def getInfo(self):
		while True:
			recMsg=connectionSocket.recv(1024).decode("utf-8")+'\n'
			revTime='客户端'+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())+'\n'
			#通过设置state属性设置textEdit可编辑
			self.textEdit.config(state='normal')
			self.textEdit.insert(tk.END,revTime,'guest')
			self.textEdit.insert(tk.END,recMsg)
			#将滚动条拉到最后显示最新消息
			self.textEdit.see(tk.END)
			#通过设置state属性设置textEdit不可编辑
			self.textEdit.config(state='disabled')

	def textSendReturn(self,event):
		if event.keysym=="Return":
			self.textSend()

root=tk.Tk()
root.title('服务端')

#指定服务器使用的端口
serverPort=12000
serverSocket=socket(AF_INET,SOCK_STREAM)
#绑定端口
serverSocket.bind(('',serverPort))
#定义最大连接数
serverSocket.listen(1)
print('等待连接....')
#接受请求则建立一个连接
connectionSocket,addr=serverSocket.accept()
print('一个连接')
app=Application(master=root)
app.mainloop()

from socket import *
import tkinter as tk
import tkinter.scrolledtext as tst
import time
import tkinter.messagebox
import threading

#定义输入服务器ip地址的类
class inputIPdialog(tk.Frame):

	def __init__(self,master):
		tk.Frame.__init__(self,master)
		self.ipInput=tk.Text(self,width=30,height=5)
		self.ipInput.grid(row=0,column=0,columnspan=3)
		self.okbtn=tk.Button(self,text='确定',command=self.setIP).grid(row=1,column=3)
		self.grid()

	def setIP(self):
		#这个global变量作为类变量的话没有效果,原因不知
		global servername
		servername=self.ipInput.get('1.0','end-1c')
		#销毁窗口
		ipRootFrame.destroy()

class Application(tk.Frame):
	def __init__(self,master):
		tk.Frame.__init__(self,master)
		self.grid()
		self.createWidgets()
	def createWidgets(self):
		#显示聊天窗口
		self.textEdit=tst.ScrolledText(self,width=50,height=15)
		self.textEdit.grid(row=0,column=0,rowspan=1,columnspan=4)
		self.textEdit.config(state='disabled')
		#定义标签,改变字体颜色
		self.textEdit.tag_config('server',foreground='red')
		self.textEdit.tag_config('guest',foreground='blue')

		#编辑窗口
		self.inputText=tk.Text(self,width=40,height=5)
		self.inputText.grid(row=1,column=0,columnspan=1)
		#定义快捷键,按下回车即可发送消息
		self.inputText.bind("<KeyPress-Return>",self.textSendReturn)

		#发送按钮
		self.btnSend=tk.Button(self,text='send',command=self.textSend)
		self.btnSend.grid(row=1,column=3)

		#开启一个线程用于接收消息并显示在聊天窗口
		t=threading.Thread(target=self.getInfo)
		t.start()


	def textSend(self):
		#获取Text的所有内容
		#https://stackoverflow.com/questions/14824163/how-to-get-the-input-from-the-tkinter-text-box-widget
		str=self.inputText.get('1.0','end-1c')
		if str!="" and str!=None:
			#显示发送时间和发送消息
			timemsg='客户端'+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())+'\n'
			#通过设置state属性设置textEdit可编辑
			self.textEdit.config(state='normal')

			self.textEdit.insert(tk.INSERT,timemsg,'guest')
			self.textEdit.insert(tk.INSERT,str+'\n')

			#将滚动条拉到最后显示最新消息
			self.textEdit.see(tk.END)
			#通过设置state属性设置textEdit不可编辑
			self.textEdit.config(state='disabled')
			self.inputText.delete(0.0,tk.END)	#删除输入框的内容
			#发送数据到服务端
			sendMessage=bytes(str,encoding='utf8')
			#发送输入的数据,与UDP有点不同,使用的是send方法,不需要指定服务器和端口,因为已经建立了一条tcp连接
			clientSocket.send(sendMessage)
		else:
			tk.messagebox.showinfo('警告',"不能发送空白信息!")

	def getInfo(self):
		global  clientSocket
		while True:
			#接收数据,1024指定缓存长度,使用的是recv方法
			recMessage=clientSocket.recv(1024).decode("utf8")+'\n'
			#接受时间和接收的数据
			recTime='服务端'+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())+'\n'
			self.textEdit.config(state='normal')
			#server作为标签,改变字体颜色
			self.textEdit.insert(tk.END,recTime,'server')
			self.textEdit.insert(tk.END,recMessage)
			#将滚动条拉到最后显示最新消息
			self.textEdit.see(tk.END)
			self.textEdit.config(state='disabled')

	def textSendReturn(self,event):
		if event.keysym=="Return":
			self.textSend()

#指定服务器地址,端口
servername=''
serverport=12000
ipRootFrame=tk.Tk()
ipRootFrame.title('输入服务器ip')
ipDialog=inputIPdialog(ipRootFrame)
ipDialog.mainloop()
#socket第一个参数指定使用IPV4协议,第二个参数指定这是一个TCP套接字
clientSocket=None

try:
	clientSocket=socket(AF_INET,SOCK_STREAM)
except:
	tk.messagebox.showinfo('未知错误','检查服务器地址是否错误!')

#tcp连接需要先经过握手建立连接
clientSocket.connect((servername,serverport))
root=tk.Tk()
root.title('客户端')

app=Application(master=root)
app.mainloop()

界面

  • 输入服务端ip
    服务端ip
  • 聊天界面
    聊天界面

缺陷

  • 只限制单个连接,只能输入文本
  • 不能分列两边显示
  • 一切建立在理想情况下,即使发送不出去也会显示在对话框中,没有异常检测并给出处理机制。
  • 使用回车发送的话在输入框会残留一个回车符。。
  • 太懒了,看以后会不会完善。
发布了163 篇原创文章 · 获赞 21 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/whimewcm/article/details/85041692