无法使用定义的变量python

问题描述 投票:0回答:1

我正在使用一个聊天应用程序,但是我收到一个错误消息,即使我设计了变量也没有定义,我知道我可能必须重组一些东西,但是我不确定从哪里开始,这里的代码引起问题

import socket
import select
import errno
import sys
import threading
from tkinter import *


HEADER_LENGTH = 10

IP = socket.gethostbyname("0.0.0.0")
PORT = 1234

class inputNameWin():
    def __init__(self):
        self.window = Tk()
        self.window.title("login")

        self.inputLabel = Label(self.window, text="Type in your username, then click connect")
        self.inputLabel.grid(row=0, column=1)

        self.inputName = Entry(self.window, width="10")
        self.inputName.grid(row=1, column=0, columnspan=2)

        self.connectButton = Button(self.window, text="CONNECT", command= lambda : self.checkName(self.inputName.get()))
        self.connectButton.grid(row=2, column=0, columnspan=2)
        self.window.mainloop()

    def checkName(self, name):
        name = name.strip()
        if len(name) <= 3 :
            self.inputLabel['text'] = f"Username {name} is too short! Try another"
        elif len(name) >= 15:
            self.inputLabel['text'] = f"Username {name} is too long! Try another"
        else:
            self.window.destroy()
            start(name)


class mainWin():
    def __init__(self, username):
        self.username = username
        self.mainWindow = Tk()
        self.mainWindow.title(f"Chatty.py client [NO CONNECTION] NAME = {self.username}")
        self.mainWindow.configure(bg="white")

        self.padSizeX = 5
        self.padSizeY = 60

        self.status = Label(self.mainWindow, text=f"Username : {self.username} [NO CONNECTION]", fg="black", bg="white")
        self.status.grid(row=0, column=0, columnspan=2)

        self.messagEntry = Entry(self.mainWindow, fg="black", bg="white")
        self.messageSend = Button(self.mainWindow, text="Send", command= lambda : connection.sendMessage(self.messagEntry.get()), fg="green", bg="white", activebackground="white", activeforeground="black")
        self.messagEntry.grid(row=2, column=0, columnspan=2)
        self.messageSend.grid(row=3, column=0, columnspan=2)

        self.incoming = Listbox(self.mainWindow, fg="green", bg="white", width=50, height=25, selectbackground="blue", highlightcolor="green2")
        self.incoming.grid(row=1, column=0)

        self.outgoing = Listbox(self.mainWindow, fg="blue", bg="white", width=50, height=25, selectbackground="green", highlightcolor="green2")
        self.outgoing.grid(row=1, column=1)

class connectionHandler():
    def __init__(self, username):
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.connect((IP, PORT))
        self.client_socket.setblocking(False)

        self.username = username.encode("utf-8");
        self.username_header = f'{len(username):<{HEADER_LENGTH}}'
        self.username_header = self.username_header.encode('utf-8')

        self.client_socket.send(self.username_header + self.username)

        main = threading.Thread(target=self.main)
        main.start()

    def sendMessage(self,message):
        if(message):
            try:    
                message = str(message)
                try:
                    type_, data = message.split("$")
                    if(type_ == "message"):
                        messageOutput = f"message${data}"
                        GUI.incoming.insert(END, "")
                        GUI.outgoing.insert(END, f"{data} << {self.username}")
                    else:
                        print(f"invalid type {type_}")
                except:
                    messageList = []
                    type_ = messageList[1]
                    messageList.remove(type_)
                    for part in messageList:
                        messageOutput = f"{message}{part}"
                messageOutput = messageOutput.encode("utf-8")
                message_header = f"{len(messageOutput):<{HEADER_LENGTH}}".encode('utf-8')
                GUI.client_socket.send(message_header + messageOutput)
                GUI.incoming.insert(END, "")
                self.outgoing.insert(END, f"{messageOutput} << {self.username}")
            except:
                message = str(message)
                messageOutput = f"message${message}".encode("utf-8")
                message_header = f"{len(messageOutput):<{HEADER_LENGTH}}".encode("utf-8")
                self.client_socket.send(message_header + messageOutput)
                GUI.incoming.insert(END, "")
                GUI.outgoing.insert(END, f"{messageOutput} << {self.username}")

    def main(self):
        while True:
            try:
                while True:

                    username_header = self.client_socket.recv(HEADER_LENGTH)
                    if(not len(username_header)):
                        print("connection closed by server")
                        sys.exit()
                    username_lenght = int(username_header.decode("utf-8").strip())

                    username = client_socket.recv(username_lenght).decode("utf-8")

                    message_header = client_socket.recv(HEADER_LENGTH)
                    message_length = int(message_header.decode("utf-8").strip())
                    messageRaw = client_socket.recv(message_length).decode("utf-8")

                    type_, message = messageRaw.split("$")

                    if(type_ == "message"):
                        print(f"{username} >> {message}")
                    elif(type_ == "cmd"):
                        print("got cmd")
                        if(username == "sever"):
                            print("recieved server command")

            except IOError as e:
                if(e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK):
                    print("READ ERR",str(e))
                    sys.exit()
                continue

            except Exception as e:
                print("Error".str(e))
                sys.exit()      

def start(username):
    connection = connectionHandler(username)
    GUI = mainWin(username)
    GUI.mainWindow.mainloop()

loginWin = inputNameWin()

很抱歉,您无法阅读一百多行代码。我收到的错误是

Exception in Tkinter callback
Traceback (most recent call last):
  File "/home/kali/anaconda3/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
    return self.func(*args)
  File "client.py", line 54, in <lambda>
    self.messageSend = Button(self.mainWindow, text="Send", command= lambda : connection.sendMessage(self.messagEntry.get()), fg="green", bg="white", activebackground="white", activeforeground="black")
NameError: name 'connection' is not defined

我需要使连接成为局部变量,还是只需要取消此结构并重做我要处理的方式?

python multithreading sockets tkinter chat
1个回答
0
投票

Python在词法上(也称为静态)范围内,而不是动态范围内。这意味着connection中使用的mainwin.__init__必须是global变量,因为它不是__init__的局部变量,并且全局范围是最接近的封闭范围。不过,您正在start函数中将其定义为local变量。

最快的解决方法是在connection中全局分配给start

def start(username):
    global connection
    connection = connectionHandler(username)
    GUI = mainWin(username)
    GUI.mainWindow.mainloop()

一种更好的解决方案是将所需的对象作为mainWin.__init__的参数传递,尽管这需要对定义进行其他小的更改,因为您希望回调函数使用传递给__init__的值,而不是[ C0]作为自由变量。

首先,

connection

然后,

def start(username):
    connection = connectionHandler(username)
    GUI = mainWin(username, connection)
    GUI.mainWindow.mainloop()
© www.soinside.com 2019 - 2024. All rights reserved.