这是我第一次尝试使用GUI和客户端 - 服务器应用程序,所以我很挣扎。我(希望)有一个服务器端和客户端以及一个gui来提示用户输入用户名和密码(存储在服务器端的文本文档中)。 gui(有点)在客户端工作,但在成功输入匹配的用户名和密码组合后,我不知道如何调用单独的菜单' gui打开。如何从client.py导入menu.py,这样当用户成功登录时,会遇到一个单独的gui?代码如下。如果我遗漏任何东西,请告诉我。谢谢!
客户端:
import socket
from tkinter import *
import tkinter.messagebox as tm
from tkinter import ttk
serverName = 'localhost'
serverPort = 12000
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
class LoginFrame(Frame):
def __init__(self, master):
super().__init__(master)
self.label_1 = Label(self, text="Username")
self.label_2 = Label(self, text="Password")
self.entry_1 = Entry(self)
self.entry_2 = Entry(self, show="*")
self.label_1.grid(row=0, sticky=E)
self.label_2.grid(row=1, sticky=E)
self.entry_1.grid(row=0, column=1)
self.entry_2.grid(row=1, column=1)
self.logbtn = Button(self, text="Login", command = self._login_btn_clicked)
self.logbtn.grid(columnspan=2)
self.pack()
def _login_btn_clicked(self):
username = self.entry_1.get()
clientSocket.sendto(username.encode('UTF-8'),(serverName, serverPort))
password = self.entry_2.get()
clientSocket.sendto(password.encode('UTF-8'),(serverName, serverPort))
message, address = clientSocket.recvfrom(1024)
message = message.decode('UTF-8')
if message == "200 OK":
tm.showinfo("Logged in", message)
else:
tm.showinfo("Login error", message)
root = Tk()
root.title("GUI")
root.geometry('{}x{}'.format(270, 80))
lf = LoginFrame(root)
root.mainloop()
服务器:
import socket
# Create a UDP socket
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Assign IP address and port number to socket
serverSocket.bind(('', 12000))
while True:
# Receive the client packet along with the address it is coming from
username, address = serverSocket.recvfrom(1024)
username = username.decode('UTF-8')
password, address = serverSocket.recvfrom(1024)
password = password.decode('UTF-8')
infile = open("sales.txt", 'r')
for rows in infile: #equivalent to: Recs=infile.readline()
#this gets 1 line at a time as a string including \n
rows = rows.strip()
rowsList = rows.split('\t')
#message += row + "\n" # + str(rowsList)
username2 = rowsList[0].strip(' ')
if username == username2:
password2 = rowsList[1]
if password == password2:
# the server responds
message = "200 OK"
message = message.encode('UTF-8')
serverSocket.sendto(message, address)
else:
# the server responds
message = "401 Unauthorized"
message = message.encode('UTF-8')
serverSocket.sendto(message, address)
# the server responds
message = "401 Unauthorized"
message = message.encode('UTF-8')
serverSocket.sendto(message, address)
infile.close()
菜单:
from tkinter import *
from tkinter import ttk
class MenuFrame(Frame):
def __init__(self, master):
super().__init__(master)
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column = 0, row = 0, sticky = (N, W, E, S))
mainframe.columnconfigure(0, weight = 1)
mainframe.rowconfigure(0, weight = 1)
name = "John"
sales = StringVar()
moreSales = StringVar()
sales.set("1")
welcome = "Welcome, " + name + "!"
sales_entry = ttk.Entry(mainframe, width = 7, textvariable = moreSales)
ttk.Label(mainframe, text = welcome).grid(column = 2, row = 1, sticky = W)
ttk.Label(mainframe, text = "Current Sales:").grid(column = 1, row = 2, sticky = W)
ttk.Label(mainframe, textvariable = sales).grid(column = 2, row = 2, sticky = (E))
ttk.Label(mainframe, text = "sales").grid(column = 3, row = 2, sticky = W)
ttk.Label(mainframe, text = "Add Sales").grid(column = 1, row = 3, sticky = W)
sales_entry.grid(column = 2, row = 3, sticky = (W, E))
ttk.Button(mainframe, text = "Add", command = MenuFrame.add(sales, moreSales)).grid(column = 3, row = 3, sticky = W)
ttk.Button(mainframe, text = "Log Out", command = MenuFrame.logout).grid(column = 2, row = 4, sticky = W)
def add(sales, moreSales):
try:
value1 = int(sales.get())
value2 = int(moreSales.get())
sales.set(value1 + value2)
except ValueError:
pass
def logout():
root.destroy()
root = Tk()
root.title("GUI")
mf = MenuFrame(root)
root.mainloop()
编辑:我试过了
import Menu
并添加了
root = Tk()
root.title("GUI")
mf = MenuFrame(root)
root.mainloop()
之后
if message == "200 OK" in client.py
但是我收到了错误:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Pat\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1549, in __call__
return self.func(*args)
File "C:\Users\Pat\Desktop\DunderMifflinSales-master\DunderMifflinClient.py", line 49, in _login_btn_clicked
mf = MenuFrame(root)
NameError: name 'MenuFrame' is not defined
答案 0 :(得分:1)
第一步是确保第二个GUI可以正确导入。必须没有实际在模块的全局范围内创建窗口的代码。您需要从Menu.py
完全删除此代码块:
root = Tk()
root.title("GUI")
mf = MenuFrame(root)
root.mainloop()
完成后,您的代码应该可以正常工作。假设您希望“Menu.py”中的代码出现在单独的窗口中,您可以执行以下操作:
from tkinter import *
import Menu
...
if should_display_new_gui:
toplevel = Toplevel(root)
mf = Menu.MenuFrame(toplevel)
mf.pack(fill="both", expand=True)
如果您希望菜单框显示在同一根窗口而不是新窗口中,则可以跳过创建Toplevel
的实例,而是将root
作为参数传递给{{1 }}
您的MenuFrame
代码中还有其他与此特定问题无关的错误。例如,请考虑以下代码:
MenuFrame
第一个问题是ttk.Button(..., command = MenuFrame.add(...)).grid(...)
是一个类,而MenuFrame
是该类的实例的方法。因此,需要修复的第一件事是使用add
而不是self.add(...)
。
第二个问题是,当您执行MenuFrame.add(...)
时,此_立即调用..., command=add(...)
并将结果分配给add
。这与你做到这一点没有什么不同:
command
您需要将cmd = MenuFrame.add(...)
ttk.Button(..., command = cmd).grid(...)
引用传递给函数,而不是函数本身。如果您要传递变量,通常会使用command
或lambda
。但是,您不需要传递任何内容,因为您的functools.partial
方法正在获取所需的数据。因此,您可以将命令更改为:
add
然后,像这样定义ttk.Button(..., command=self.add).grid(...)
:
add
但,由于def add(self):
value1 = int(sales.get())
value2 = int(moreSales.get())
和sales
是局部变量,因此不起作用。您需要将它们保存为类的属性:
moreSales
然后您可以像这样访问它们:
def __init__(self, master):
super().__init__(master)
...
self.sales = StringVar()
self.moreSales = StringVar()
...