43.QQ聊天软件GUI窗口编写

QQ聊天软件代码功能编写


一,Tkinter聊天界面编写

 1,聊天软件客户端界面开发-1

  • Tkinter的模块(“TK接口”)是标准的Python接口从Tk的GUI工具包

  • https://i.cnblogs.com/EditPosts.aspx?opt=1   ###Tkinter官方文档:关于相关函数具体看文档介绍

  • Tkinter模块:自带的,跨平台

    • 做GUI:界面软件

    • 不难,但是复杂,东西多,窗口控件多,设计,美感,抠图

  • 界面开发设计

    • 设置窗口:像素大小

    • 拜访控件:按钮,复选框,文本框

  • root控件流程:

    • 1:导入模块   import tkinter
    • 2:创建主窗口root = tkinter.Tk()
    • 3:创建其他窗口以及控件(按钮,文本框,等等)
    • 4:摆放到root上
    • 5:开启root的事件循环:root.mainloop()
    • 6:如果不需要该窗口,可以使用root.destory()

  • 组件:

  • 文本框

    • tkinter.Text()
      • insert():插入数据
        • tkinter.END,从末尾插入
      • delete(‘0.0’,tkinter.END):删除全部文本框数据
      • tag_config('标签名',foreground='颜色',):标签配置,设置字体颜色, 第一个字符串参数是标签名,第二个是颜色
      • get('0.0',thinter.END):阅读拿出文本框的内容
  • 按钮

    • tkinter.Button()
      • text:按钮名字
      • command:回调函数,按钮点击时的工作任务列表框
  • 列表框

  • tkinter.Listbox()

  • insert(tkinter.END, 追加的数据)

  • 事件绑定

    • 双击事件:<Double-Button-1>

    • 事件绑定的函数必须有一个参数,这个参数就是事件

    • self.right_listbox.curselection()

      • 返回当前选择的列表框索引位置值,返回结果为单个数据的元组

      • index = self.listbox_user.curselection()[0]

    • self.talk_user_name = self.listbox_user.get(index)

      • index   #获取的当前列表框中的索引位置的值

  • root.title('**')

    • 设置上标字符
  • grid()

    • x,y轴的摆放方式

    • row:行

    • column:列

    • rowspan:行宽,跨行数

    • pady:表格间距,x轴

    • padx:y轴的表格间距

  • sticky

    • 对其方向,上北下南左西右东N,S,W,E
  • grid_propagate(0)

    • 0代表禁止容器窗口缩放
  • root.resizable(width=False,height=Flase)

    • 禁止窗口缩放
  • root.winfo_screenwidth()

    • 自动获取用户的屏幕宽度
  • root.winfo_screenheight()

    • 自动获取用户的屏幕高度
  • root.geometry("%dx%d%+d%+d" % (width, height, xoffset, yoffset))

    • 设置控件所处的屏幕位置
  • tkinter.Label(所属的主窗口,text='名字',font=("黑体",9, "bold"))

    • 添加标签lable
  • tkinter.Entry()

    • 单行文本框

    • 获取数据直接使用get() 函数即可,不需要传参。

  • from tkinter import messagebox   ##展示报错信息

    • 'showerror', 'showinfo', 'showwarning'

      • title=None, message=None

    • messagebox.showerror(title='登录失败',message='登录失败')


  • 客户端登录及聊天窗口代码编写整合如下:

    1from tkinter import Tk 2import tkinter 3import time 4from multiprocessing.pool import ThreadPool 5import socket 6from tkinter import messagebox 7import pickle 8import _pickle 9#scroolbar 10class TalkRoot: 11 ''' 12 实现用户聊天的主要界面 13 ''' 14 def __init__(self,user_name,client,user_id): 15 self.root = Tk() 16 self.root.title('欢迎你:%s' % user_name) 17 self.client = client 18 self.user_id = user_id 19 #-----------------创建进程池---------------------- 20 self.thread_pool = ThreadPool(5) #5个线程的线程池 21 #-------功能变量---------------------- 22 self.talk_user_name = '' #你要聊天的人 23 self.client = client #套接字 24 #------------------设置窗口所处的用户界面位置及窗口大小在屏幕中间------------ 25 self.root_width=550 26 self.root_height=420 27 self.user_screen_width = self.root.winfo_screenwidth()#自动获取用户的屏幕宽度 28 self.user_screen_height = self.root.winfo_screenheight()#用户的屏幕高 29 self.root.geometry("%dx%d%+d%+d" % 30 (self.root_width, 31 self.root_height, 32 (self.user_screen_width - self.root_width) / 2, 33 (self.user_screen_height - self.root_height) / 2,) 34 ) 35 #-------容器-------- 36 #上: 输出 37 self.frame_top = tkinter.Frame(width=380,height=270) 38 #中: 输入 39 self.frame_center = tkinter.Frame(width=380,height=100) 40 #下: 按钮 41 self.frame_bottom = tkinter.Frame(width=380,height=30) 42 #右: 列表 43 self.frame_right = tkinter.Frame(width=170,height=400) 44 45 #--------控件-------- 46 #上: 输出 47 self.text_output = tkinter.Text(self.frame_top,height=260) 48 self.text_output.tag_config('time_stamp',foreground='green') #标签配置颜色 49 self.text_output.tag_config('self_msg',foreground='blue')#标签配置颜色 50 self.text_output.tag_config('other_msg',foreground='red')#标签配置颜色 51 #中: 输入 52 self.text_input = tkinter.Text(self.frame_center) 53 self.text_input.bind('<Return>',self.button_send_msg) 54 #下: 按钮 55 self.button_send = tkinter.Button(self.frame_bottom,text='发送',command=self.button_send_msg) #发送按钮 56 self.button_cancle = tkinter.Button(self.frame_bottom,text='取消',command=self.fc_button_cancle) #取消按钮 57 #右: 列表 58 self.listbox_user = tkinter.Listbox(self.frame_right,width=150,height=25) 59 self.listbox_user.bind('<Double-Button-1>',self.get_talk_user)#绑定双击事件 60 #--------摆放生效容器--------- 61 self.frame_top.grid(row=0,column=0,padx=2,pady=5) 62 self.frame_center.grid(row=1,column=0,padx=2,pady=5) 63 self.frame_bottom.grid(row=2,column=0,sticky=tkinter.E) 64 self.frame_right.grid(row=0,column=1,rowspan=3,padx=5,pady=5) 65 66 #--------摆放生效控件--------- 67 self.text_output.grid() 68 self.text_input.grid() 69 self.button_send.grid(row=0,column=1,padx=300) 70 self.button_cancle.grid(row=0,column=0) 71 self.listbox_user.grid() 72 73 #--------禁止容器窗口缩放grid_-------------------- 74 self.frame_top.grid_propagate(0) 75 self.frame_center.grid_propagate(0) 76 self.frame_bottom.grid_propagate(0) 77 self.frame_right.grid_propagate(0) 78 #------------专门开一个接受消息聊天的线程------------ 79 self.thread_pool.apply_async(func=self.check_recv_msg) #非阻塞线程 80 #------------窗口循环--------------------------------------- 81 self.root.mainloop() 82 83 def check_recv_msg(self): 84 while True: #循环窗口聊天 85 try: 86 data = pickle.loads(self.client.recv(1024)) 87 except _pickle.UnpicklingError: 88 messagebox.showinfo(title='服务端消息错误',message='服务端发来无法解析的错误') 89 self.root.destroy() 90 exit() 91 except Exception as e: 92 messagebox.showinfo(title='服务端断开',message='服务端断开') 93 self.root.destroy() 94 exit() 95 if data.get('flag') == 'flush': 96 #服务端返回最新在线用户 97 self.thread_pool.apply_async(func=self.flush_onlien_user,args=(data,)) 98 elif data.get('flag') == 'forward': 99 #服务端返回别人发来的消息 100 self.thread_pool.apply_async(func=self.show_other_msg,args=(data,)) 101 elif not data: 102 #服务端发来空消息,断开连接 103 exit() 104 105 def show_other_msg(self,data): 106 ''' 107 展示别人发来的消息 108 ''' 109 send_name = data.get('data')['send_name'] 110 other_msg = data.get('data')['message'] 111 print('别人发来了消息:',other_msg) 112 time_stamp = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime() ) + '\n' 113 self.text_output.insert(tkinter.END,time_stamp,'green') 114 self.text_output.insert(tkinter.END,'%s:%s' % (send_name,other_msg),'red') 115 116 def flush_onlien_user(self,data): 117 self.listbox_user.delete(0,tkinter.END) #清空在线用户列表 118 for user in data.get('data'): 119 #user : {id:name} 120 id_ = list(user.keys())[0] 121 name = list(user.values())[0] 122 self.listbox_user.insert(tkinter.END, '%s:%s' % (name,id_)) 123 124 def button_send_msg(self,events=None): 125 self_msg = self.text_input.get('0.0',tkinter.END) 126 self.text_input.delete('0.0',tkinter.END) 127 if not self_msg.isspace(): 128 time_stamp = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime() ) + '\n' 129 self.text_output.insert(tkinter.END,time_stamp,'time_stamp') 130 self.text_output.insert(tkinter.END,' ' + self_msg,'self_msg') 131 self.thread_pool.apply_async(func=self.clear_input_text) 132 #id:name 133 if self.talk_user_name: 134 print('捕捉到在线用户,准备发送消息') 135 recv_id = self.talk_user_name.split(':')[0] 136 print(recv_id) 137 send_data = { 138 'flag': 'send', 139 'data': { 140 'send_id': self.user_id, 141 'recv_id': recv_id, 142 'message': self_msg, 143 } 144 } 145 self.client.send(pickle.dumps(send_data)) 146 else: 147 ''' 148 群发功能 149 ''' 150 send_data = { 151 'flag': 'part', 152 'data': { 153 'send_id': self.user_id, 154 'message': self_msg, 155 } 156 } 157 158 def clear_input_text(self): 159 time.sleep(0.1) 160 self.text_input.delete('0.0',tkinter.END) 161 162 def get_talk_user(self,events): 163 ''' 164 获取当前聊天用户 165 ''' 166 if self.listbox_user.size() != 0: 167 index = self.listbox_user.curselection()[0] 168 self.talk_user_name = self.listbox_user.get(index) 169 print(self.talk_user_name) 170 171 def fc_button_cancle(self): 172 ''' 173 聊天界面的销毁 174 销毁窗口 175 客户端套接字释放 176 ''' 177 exit() 178 179 def __del__(self): 180 self.client.close() #套接字释放 181 self.root.destroy() #销毁窗口 182 183class LoginRoot(): 184 def __init__(self): 185 self.root = tkinter.Tk() 186 self.root.title('登陆') 187 self.root.resizable(width=False,height=False) #禁止窗口缩放调整 188 189 self.root_width = 197 190 self.root_height = 75 191 192 #自适应,首先要获取到用户的屏幕分辨率 193 self.user_screen_width = self.root.winfo_screenwidth() #用户的屏幕也宽度 194 self.user_screen_height = self.root.winfo_screenheight() #用户的屏幕高度 195 196 self.root.geometry("%dx%d%+d%+d" % #设置窗口所处的用户界面位置及窗口大小 197 (self.root_width, 198 self.root_height, 199 (self.user_screen_width - self.root_width) / 2, 200 (self.user_screen_height - self.root_height) / 2,) 201 ) 202 203 #创建提示label 204 self.label_id = tkinter.Label(self.root,text='I D:',font=("黑体",10, "bold")) # font设置字体样式 205 self.label_name = tkinter.Label(self.root,text='昵称:',font=("黑体",10, "bold")) 206 #摆放提示label 207 self.label_id.grid(row=0,column=0,sticky=tkinter.W) 208 self.label_name.grid(row=1,column=0,) 209 #创建输入单行文本框 210 self.entry_id = tkinter.Entry(self.root) 211 self.entry_name = tkinter.Entry(self.root) 212 #摆放文本框 213 self.entry_id.grid(row=0,column=1) 214 self.entry_name.grid(row=1,column=1) 215 #创建功能按钮 216 self.button_login = tkinter.Button(self.root,text='登陆',command=self.user_login) 217 self.button_cancle = tkinter.Button(self.root,text='取消',command=self.user_cancle) 218 #摆放功能按钮 219 self.button_login.grid(row=2,column=1,sticky=tkinter.E) 220 self.button_cancle.grid(row=2,column=0,sticky=tkinter.W) 221 self.root.mainloop() 222 223 def user_login(self): 224 ''' 225 要确定用户提供的ID是唯一的 226 把昵称传递给TalkRoot 227 ''' 228 user_id = self.entry_id.get() 229 user_name = self.entry_name.get() 230 231 send_login_msg = { 232 'flag': 'login', 233 'data':{ 234 'id': user_id, 235 'name': user_name 236 } 237 } 238 ip = '192.168.1.101' 239 port = 8000 240 try: 241 self.client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 242 self.client.connect( (ip,port) ) 243 except Exception as e: 244 print('登陆连接时的错误:',e) 245 messagebox.showerror(title='登陆失败',message='登陆失败') 246 else: 247 self.client.send(pickle.dumps(send_login_msg)) 248 data = pickle.loads(self.client.recv(1024)) 249 if data.get('flag') == 'login': 250 if data.get('data')['state']: 251 #登陆成功 252 self.root.destroy() 253 tkr = TalkRoot(user_name,self.client,user_id) 254 else: 255 self.client.close() 256 messagebox.showwarning(title='登陆失败',message='%s' % (data.get('data')['message'])) 257 258 def user_cancle(self): 259 self.root.destroy() 260 261def main(): 262 lgr = LoginRoot() 263 264 265if __name__ == '__main__': 266 main()

二,聊天类软件后台架构及请求数据设计

一,服务端功能

  • 1:接收用户登陆

    • 主线程,消息收集
    • 服务端套接字,唯一ID的校验
  • 2:告知在线用户

    • 另开线程,遍历访问服务端保存的客户端序列数据
  • 3:处理在线用户的消息发送

    • 主线程,消息收集 一旦捕获到了一个消息是要发送给别人的
    • 另开线程,处理消息转发,发给另外一个在线的套接字

二,客户端功能

  • 1:登陆

    • 套接字,发送ID和昵称即可
  • 2:接收处理服务端发来的在线用户列表

  • 3:发送消息,展示消息

三,请求数据结构体 / 客户端

  • 1:pickle.dumps() #打包二进制数据体

    • 1 { #客户端登陆发送的数据体 2 'flag': 'login', #数据标志位 3 'data': { 4 'id': '123456', #用户ID 5 'name: 'xxxxx', #用户昵称 6 } 7 } 8 9 { #客户端发送数据体 10 'flag': 'send' #数据标志位 11 'data': { 12 'send_id': '123455', #发送者的ID 13 'recv_id': '123456', #接收人的ID14 'message: 'xxxxx', #发给别人的数据 15 } 16 } 17 18 { #客户端注册数据体 19 'flag': 'register', #数据标志位 20 'data': { 21 'id': '123456', #用户ID 22 'name: 'xxxxx', #用户昵称 23 'password': 'xxxxx', # 24 } 25 }

四,服务端保存在线用户数据体

  • 1:直接连进来的,不进入这个数据体,不算有效用户

  • 2:某个线程,捕捉这个套接字发来的第一个login的数据体

  • 3:判断ID:

    • ID不重复:登陆保存
    • ID重复:当用户发送重复id的时,返回的数据
      •   

        1{ 2 'flag':'login', 3 'data': { 4 'state':True,/False 5 'message':'登陆成功' 6 } 7}  
  • 4:成功登陆的用户保存在字典中的数据结构体

    • 1 #字典: 2 dict_onlien_user = { 3 xxxx:{ 4 'name':'666', 5 'socket':client, 6 }, 7 xxxx:{, 8 name:'666', 9 socket:client, 10 }, 11 }
    • onlien_user.get(recv_id)['socket'].send(message)  #如果再转发消息的时候,准确快速的找到接收者 

  • 5:成功的用户发来的数据,要给别人发消息,服务端怎么保存这个数据?

    •   

      1{ #客户端发送数据体 2 'flag': 'send' #数据标志位 3 'data': { 4 'send_id': '123455', #发送者的ID 5 'recv_id': '123456', #接收人的ID6 'message: 'xxxxx', #发给别人的数据 7 } 8}
  • 6:客户端接收服务端发来的在线用户数据结构体

    • 1 list_onlien_user = [ 2 {'id1':'name1'}, 3 {'id2':'name2'}, 4 }
  • 7: 刷新的用户列表数据是一个列表,现在要更改

    • 1 { #服务端发给客户端的数据体 2 'flag': 'flush' #数据标志位 3 'data': [在线用户列表] 4 }
  • 8: 发给其他用户的数据,怎么发过去?

    • 1 { #服务端发给客户端的数据体 2 'flag': 'forward' #数据标志位 3 'data': { 4 'send_name': '123455', #发送者的ID 5 'message': '123456', #接收人的ID6 } 7 }

五,代码编写如下:

1#服务端 2import socket 3from multiprocessing.pool import ThreadPool 4import pickle 5import copy 6import time 7 8class TalkServer: 9 def __init__(self,ip,port): 10 self.ip = ip 11 self.port = port 12 self.socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 13 self.socket_server.setblocking(0) #服务端套接字设置为非阻塞 14 self.socket_server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #设置端口复用 15 self.socket_server.bind( (self.ip, self.port) ) 16 17 self.dict_online_user = {} #保存未来的在线用户字典 18 self.list_online_user = [] #保存即将发送给别人在现在用户列表 19 self.thread_pool = ThreadPool(10) 20 21 self.is_flush = False #用来判断是否需要刷新在线用户的 22 23 def run(self, num_=5): 24 self.socket_server.listen(num_) 25 #2:用户发送给别人的消息处理 26 self.thread_pool.apply_async(func=self.inform_online_user_list) 27 self.thread_pool.apply_async(func=self.check_send_data) 28 while True: 29 ''' 30 接收用户来访 31 ''' 32 try: 33 client,client_addr = self.socket_server.accept() 34 except BlockingIOError: 35 pass 36 else: 37 print('有人来了:[%s|%s]' % client_addr) 38 #没报错,那么就是用户真正的连接到了,accept捕捉到了返回值 39 #1:用户登陆发来的消息处理,开一个线程去等待他发来对应的数据,或者说判断这个ID是否是重复的 40 self.thread_pool.apply_async(func=self.check_login_data,args=(client,)) 41 #login数据 42 43 def inform_online_user_list(self): 44 ''' 45 告知客户端现在的在线用户,就是直接发送一个在线用户的列表 46 ''' 47 while True: 48 if self.is_flush: 49 time.sleep(1) 50 print('刷新在线用户') 51 send_online_user_msg = { 52 'flag': 'flush', 53 'data': self.list_online_user, 54 } 55 56 for id in self.dict_online_user: 57 client = self.dict_online_user[id]['socket'] 58 client.send(pickle.dumps(send_online_user_msg)) 59 self.is_flush = False 60 61 def check_send_data(self): 62 ''' 63 处理用户的发送数据,要发给别人拉 64 还会碰到用户发来的断开连接的数据 65 ''' 66 while True: 67 list_onlien_user_bak = copy.copy(self.list_online_user) 68 for data in list_onlien_user_bak: #[{'id1':'name1'},{'id1':'name1'}...] 69 id = list(data.keys())[0] 70 client = self.dict_online_user[id]['socket'] #套接字拿到 71 name = self.dict_online_user[id]['name'] 72 #print('当前遍历到的在线用户,%s:%s' % (id,name)) 73 try: 74 recv_msg = client.recv(1024) #非阻塞形式获取客户端发来的数据 75 except BlockingIOError as e: 76 pass #当前该在线用户并没有发送任何消息 77 except ConnectionResetError as e: 78 ''' 79 客户端断开连接 80 ''' 81 pass 82 else: 83 #1:判断是否是断开的数据 84 if not recv_msg: 85 print('离开了:%s,%s' % (id,name)) 86 client.close() 87 del self.dict_online_user[id] 88 self.list_online_user.remove(data) 89 self.is_flush = True 90 else: 91 ''' 92 { #发送数据体 93 'flag': 'send' #数据标志位 94 'data': { 95 'send_id': '123455', #发送者的ID 96 'recv_id': '123456', #接收人的ID97 'message: 'xxxxx', #发给别人的数据 98 } 99 } 100 ''' 101 clear_recv_msg = pickle.loads(recv_msg) 102 if clear_recv_msg.get('flag') == 'send': #确实是要给别人发送消息 103 clear_recv_data = clear_recv_msg.get('data') 104 if clear_recv_data: #发来的数据中确实有data 105 send_id = clear_recv_data.get('send_id') 106 recv_id = clear_recv_data.get('recv_id') 107 message = clear_recv_data.get('message') 108 109 if self.dict_online_user.get(recv_id): 110 recv_socket = self.dict_online_user.get(recv_id)['socket'] #接收者的套接字 111 else: 112 continue 113 send_name = self.dict_online_user[send_id]['name']#发送者的名字 114 ''' 115 { #服务端发给客户端的数据体 116 'flag': 'forward' #数据标志位 117 'data': { 118 'send_name': '123455', #发送者的ID 119 'message': '123456', #接收人的ID120 } 121 } 122 ''' 123 forward_data = { 124 'flag': 'forward', 125 'data': { 126 'send_name': send_name, 127 'message': message, 128 } 129 } 130 recv_socket.send(pickle.dumps(forward_data)) 131 print('消息转发完毕:\n',forward_data) 132 133 def check_login_data(self,client): 134 ''' 135 { #登陆数据体 136 'flag': 'login', #数据标志位 137 'data': { 138 'id': '123456', #用户ID 139 'name: 'xxxxx', #用户昵称 140 } 141 } 142 ''' 143 recv_msg = client.recv(1024) #接收用户发来的login数据体 144 if recv_msg: #发来的数据是有效的 145 clear_recv_msg = pickle.loads(recv_msg) 146 if clear_recv_msg.get('flag') == 'login': #发来的确实是login的数据 147 clear_recv_data = clear_recv_msg.get('data') 148 if clear_recv_data: #发来的数据中确实有data 149 id = clear_recv_data.get('id') 150 name = clear_recv_data.get('name') 151 #判断ID是否重复 152 if id in self.dict_online_user: 153 print('[%s:%s]该用户出现重复ID' % (id, name)) 154 send_login_msg = { 155 'flag': 'login', 156 'data': { 157 'state': False, 158 'message': 'ID使用重复', 159 } 160 } 161 client.send(pickle.dumps(send_login_msg)) #给客户端返回错误信息 162 elif not id or not name: 163 print('[%s:%s]该用户所需数据为空' % (id, name)) 164 send_login_msg = { 165 'flag': 'login', 166 'data': { 167 'state': False, 168 'message': 'ID或名字为空', 169 } 170 } 171 client.send(pickle.dumps(send_login_msg)) #给客户端返回错误信息 172 else: 173 ''' 174 dict_onlien_user = { 175 xxxx:{ 176 'name':'666', 177 'socket':client, 178 ... 179 }, 180 ''' 181 client.setblocking(0) #真正存储在在线字典里的用户套接字是个非阻塞的 182 self.dict_online_user[id] = { 183 'name': name, 184 'socket': client, 185 } 186 self.list_online_user.append( {id:name} ) 187 #刷新在线用户 188 print('在线用户已添加') 189 self.is_flush = True 190 send_login_msg = { 191 'flag': 'login', 192 'data': { 193 'state': True, 194 'message': '登陆成功', 195 } 196 } 197 client.send(pickle.dumps(send_login_msg)) 198 return 199 client.close() #用户数据无效,关闭连接 200 201def main(): 202 ip = '' 203 port = 8000 204 tks = TalkServer(ip, port) 205 tks.run() 206 207if __name__ == '__main__': 208 main() 

  运行结果:

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

43.QQ聊天软件GUI窗口编写 - HelloWorld