Python GUI Chat Application | Python
Published: 2024-02-02 12:03:35

A Python GUI chat application is a program that allows users to exchange messages in a graphical user interface (GUI) rather than through a command-line interface. It typically involves creating a user-friendly interface where users can send and receive messages in a visually appealing manner. GUI chat applications are widely used for communication, whether for personal use or as part of a larger project.

The objective of this project tutorial is to build chat application with GUI using python. This contains two files, one will act as a server and the other will act as a client. It will create a desktop GUI for chat interface. Currently, the chat application works in the local machine. To work between devices, change the IP address for host and port. It also uses threading for simultaneously sending and receiving messages.


First let us develop a GUI for client and server chat application using tkinter module.

**GUI Chat Application**

A Python GUI chat application client is a program that provides users with a graphical user interface to connect to a chat server and engage in real-time text-based communication with other users. In essence, the client facilitates the interaction between the user and the chat server, allowing messages to be sent and received in a user-friendly manner.

Import Modules

from tkinter import *

    tkinter - It allows you to create windows, dialogs, buttons, text boxes, and various other graphical elements to build interactive desktop applications with graphical user interfaces. 

GUI Function

First create a GUI function for server chat application.

# GUI function
def GUI():
    global chatlog
    global textbox

    # initialize tkinter object
    gui = Tk()
    # set title for the window
    gui.title("Server Chat")
    # set size for the window
    gui.geometry("380x430")

    # text space to display messages
    chatlog = Text(gui, bg='white')
    chatlog.config(state=DISABLED)

    # button to send messages
    sendbutton = Button(gui, bg='orange', fg='red', text='SEND', command=send)

    # textbox to type messages
    textbox = Text(gui, bg='white')

    # place the components in the window
    chatlog.place(x=6, y=6, height=386, width=370)
    textbox.place(x=6, y=401, height=20, width=265)
    sendbutton.place(x=300, y=401, height=20, width=50)
    
    # create thread to capture messages continuously
    _thread.start_new_thread(receive, ())

    # to keep the window in loop
    gui.mainloop()

    def GUI(): This line defines a function named GUI that sets up the graphical user interface.

    global chatlog and global textbox: These lines indicate that the chatlog and textbox variables are being accessed from outside the function's scope.

    gui = Tk(): This line creates a Tk object, which is the main window of the GUI application.

    gui.title("Server Chat"): This line sets the title of the GUI window to "Server Chat".

    gui.geometry("380x430"): This line sets the initial dimensions of the GUI window to be 380 pixels wide and 430 pixels tall.

    chatlog = Text(gui, bg='white'): This line creates a Text widget to display the chat log. The background color is set to white.

    chatlog.config(state=DISABLED): This line initializes the chat log in a disabled state so that the user cannot edit it directly.

    sendbutton = Button(gui, bg='orange', fg='red', text='SEND', command=send): This line creates a Button widget labeled "SEND" with an orange background and red foreground color. The command parameter is set to the send function, so clicking the button will trigger the send function.

    textbox = Text(gui, bg='white'): This line creates a Text widget for the user to input messages. The background color is set to white.

    Placement of GUI components: The place method is used to position the chat log, text box, and send button in the window.

    gui.mainloop(): This line starts the main event loop, which keeps the GUI application running and responsive to user interactions.


Next you can replicate the above code snippet to create GUI for client chat application with just changing the title to Client Chat.

Next let us

 create an  entry point for your Python GUI chat application. Both client and server application will have this entry point .

if __name__ == '__main__':
    GUI()

GUI for server chat application

GUI for server chat application

GUI for client chat application
GUI for client chat application

    GUI() starts the GUI application by calling the GUI() function. This function sets up the graphical interface, chat log, text box, and other components. It also starts a thread to continuously receive messages from the server.

    if __name__ == '__main__': block ensures that the code within it is executed only when the script is run directly, not when it's imported as a module.

    We can see that both server and client GUI are created similarly.


Till now you have seen how you can create a GUI for both client and server application. Next you will see how to create a network interface between the two GUI windows.

**Socket Programming for Server Client Interface**

Socket programming is a fundamental concept in networking and computer programming that enables communication between computers over a network. It provides a way for programs on different devices to exchange data, such as messages or files, through a network connection. Socket programming is widely used to create server-client interfaces, where one program acts as a server that listens for incoming connections, and other programs (clients) connect to the server to exchange information.

**Socket Programming - Server Client**
Import Modules

Earlier you had imported tkinter module to create the GUI application. Now you have to  import the other required modules for socket programming.

from socket import *
import _thread

    socket -  used for network programming, allowing you to establish network connections, send and receive data over the network, and create various types of network-related applications.

    _thread - provides a basic way to create and manage threads within a single process.





Create Server Socket

Next create a function to initialize the server connection.

# initialize server connection
def initialize_server():
    # initialize socket
    s = socket(AF_INET, SOCK_STREAM)
    # config details of server
    host = 'localhost'  ## to use between devices in the same network eg.192.168.1.5
    port = 1234
    # initialize server
    s.bind((host, port))
    # set no. of clients
    s.listen(1)
    # accept the connection from client
    conn, addr = s.accept()

    return conn

    def initialize_server(): This line defines a function named initialize_server().

    s = socket(AF_INET, SOCK_STREAM): This line creates a socket object using the socket() function from the socket library. AF_INET indicates the address family (IPv4), and SOCK_STREAM specifies that this is a TCP socket.

    host = 'localhost': This line defines the hostname or IP address that the server will bind to. In this case, 'localhost' is used, which means the server will listen for connections on the local machine.

    port = 1234: This line specifies the port number on which the server will listen for incoming connections.

    s.bind((host, port)): This line binds the socket to the specified host and port. The server will listen for incoming connections on this address.

    s.listen(1): This line sets the maximum number of clients that can wait in a queue to be served. In this case, only one client can be queued.

    conn, addr = s.accept(): This line accepts an incoming connection from a client. The accept() method blocks until a client connects. It returns a new socket (conn) that can be used for communication with the client and the client's address (addr).

    return conn: Finally, the function returns the socket object conn, which represents the communication channel with the connected client.


Next call the above defined function from main function.

if __name__ == '__main__':
    chatlog = textbox = None
    conn = initialize_server()
    GUI()

    conn = initialize_server() initializes the server socket connection using the initialize_server() function you provided earlier. The conn variable holds the socket object for communication with the connected client.



Create Client Socket

Next create a function to initialize the client connection.

# initialize client connection
def initialize_client():
    # initialize socket
    s = socket(AF_INET, SOCK_STREAM)
    # config details of server
    host = 'localhost'  ## to use between devices in the same network eg.192.168.1.5
    port = 1234
    # connect to server
    s.connect((host, port))

    return s

    def initialize_client(): This line defines a function named initialize_client().

    s = socket(AF_INET, SOCK_STREAM): This creates a socket object using the socket() function from the socket library. AF_INET indicates the address family (IPv4), and SOCK_STREAM specifies that this is a TCP socket.

    host = 'localhost': This line defines the hostname or IP address of the server that the client wants to connect to. In this case, 'localhost' is used, which refers to the local machine itself. If you want to connect to a server on a different device, you should replace 'localhost' with the appropriate IP address.

    port = 1234: This line specifies the port number on the server that the client wants to connect to. In this example, port number 1234 is used. Make sure this matches the port number your server is listening on.

    s.connect((host, port)): This line establishes a connection to the server using the connect() method of the socket object s. It takes a tuple (host, port) as an argument to indicate the server's address.

    return s: Finally, the function returns the socket object s, which can be used for sending and receiving data between the client and the server.


Next call the above defined function from main function.

if __name__ == '__main__':
    chatlog = textbox = None
    s = initialize_client()
    GUI()

    s = initialize_client() initializes the client socket connection to the server using the initialize_client() function you provided earlier. The s variable holds the socket object for communication.


Function to send message

Next create a function to send the message from server application.

# function to send message
def send():
    global textbox
    # get the message
    msg = textbox.get("0.0", END)
    # update the chatlog
    update_chat(msg, 0)
    # send the message
    conn.send(msg.encode('ascii'))
    textbox.delete("0.0", END)

    def send(): This line defines a function named send that doesn't take any parameters. This function is intended to be called when the user wants to send a message.

    global textbox: This line indicates that the textbox variable is being accessed from outside the function's scope. This variable likely refers to a text box widget where the user can input messages.

    msg = textbox.get("0.0", END): This line retrieves the text content from the textbox widget. "0.0" represents the start of the text (row 0, column 0), and END represents the end of the text.

    update_chat(msg, 0): This line invokes the update_chat function to update the chat log with the message. The second parameter 0 indicates that the message is from the user.

    conn.send(msg.encode('ascii')): This line sends the message to the server using the socket object conn. The message is encoded into bytes using the ASCII encoding before sending.

    textbox.delete("0.0", END): After sending the message, this line clears the content of the textbox widget to prepare for the next message.


Function to receive message

Next create a function to receive message in server application.

# function to receive message
def receive():
    while 1:
        try:
            data = conn.recv(1024)
            msg = data.decode('ascii')
            if msg != "":
                update_chat(msg, 1)
        except:
            pass

    def receive(): This line defines a function named receive that doesn't take any parameters. This function is meant to run continuously to receive and display messages from the server.

    while 1: This line starts an infinite loop, which means the code within the loop will be executed repeatedly.

    try: The code within this block is enclosed in a try-except block. This is used to catch any exceptions that might occur during the execution of the code within the block.

    data = conn.recv(1024): This line receives data from the server using the socket's recv method. It attempts to receive up to 1024 bytes of data at a time.

    msg = data.decode('ascii'): The received data is assumed to be in ASCII encoding, so this line decodes the received bytes into a string message.

    if msg != "": This line checks if the received message is not an empty string.

    update_chat(msg, 1): If the received message is not empty, this line invokes the update_chat function to update the chat log with the received message. The second parameter 1 indicates that the message is from the other party.

    except: If any exceptions occur in the try block, they are caught here. The pass statement is used to do nothing in case of an exception. In a real application, you might want to handle exceptions more appropriately.


Function to update the chat log

Next create a function to update the chat log.

# update the chat log
def update_chat(msg, state):
    global chatlog
    chatlog.config(state=NORMAL)
    # update the message in the window
    if state==0:
        chatlog.insert(END, 'YOU: ' + msg)
    else:
        chatlog.insert(END, 'OTHER: ' + msg)
    chatlog.config(state=DISABLED)
    # show the latest messages
    chatlog.yview(END)

    def update_chat(msg, state): This line defines a function named update_chat that takes two parameters: msg (the message to be added to the chat log) and state (a flag indicating whether the message is from the user or the other party).

    global chatlog: This line indicates that the chatlog variable is being accessed from outside the function's scope. This variable likely refers to a widget that displays the chat log in the GUI.

    chatlog.config(state=NORMAL): This line sets the state of the chatlog widget to "NORMAL," which allows modifications to be made to its content. This is necessary to insert new messages.

    if state == 0: section checks whether the message is from the user or the other party. If state is 0, it means the message is from the user. If it's not 0, the message is from the other party.

    chatlog.insert(END, 'YOU: ' + msg): This line inserts a message into the chatlog widget. If the message is from the user (state == 0), it formats the message as "YOU: [message]". If the message is from the other party, it formats the message as "OTHER: [message]".

    chatlog.config(state=DISABLED): After updating the chat log, the state of the chatlog widget is set to "DISABLED," preventing further modifications until explicitly set back to "NORMAL."

    chatlog.yview(END): This line ensures that the chat log's view is scrolled to the end, showing the latest messages.


Creating threads for multiprocessing 

Next let us create threads to continuously capture messages. 

 # create thread to capture messages continuously
_thread.start_new_thread(receive, ())

    Add this line to both client and server GUI code snippet that we had created in the beginning of this tutorial.

    This line starts a new thread that executes the receive function, which continuously receives messages from the server.


Next create bind key to function.

 # bind textbox to use ENTER Key
 textbox.bind("<KeyRelease-Return>", press)

    Add this line to both client and server GUI code snippet that we had created in the beginning of this tutorial.

    textbox.bind("<KeyRelease-Return>", press): This line binds the "KeyRelease-Return" event (Enter key release) to the press function. This is likely used to enable sending messages by pressing the Enter key.


Next let us see the working of chat application.
Interaction between client and server application
Interaction between client and server application

    You can see that the messages that has been sent to server has been updated in client.

    You can use the server application in one device and the client application on other device. By this you can use this as a basic desktop chat application. 


Final Thoughts

    Before you start coding, plan out the features and design of your application. Consider the user interface, messaging flow, user authentication, error handling, and any additional features you want to include.

    Design an intuitive and user-friendly interface. Use GUI libraries like tkinter, PyQt, or wxPython to create windows, buttons, text boxes, and other UI elements.

    Understand the client-server architecture and how messages will be exchanged between clients and the server. Implement both the client and server components of your chat application.

    Learn socket programming to establish communication between the client and server. Use sockets to send and receive messages over a network connection.

    Implement multithreading to handle multiple clients concurrently. This ensures that the application remains responsive and can manage multiple chat sessions simultaneously.

    Implement proper error handling to handle scenarios like connection failures, lost connections, and exceptions that can occur during network operations.


Building a chat application involves multiple technical aspects, including networking, user interface design, and software architecture. Take your time to understand and implement each piece effectively, and don't hesitate to seek help or consult resources when needed. With careful planning and dedicated effort, you can create a functional and user-friendly Python GUI chat application. Here you have learnt how you can create a basic desktop chat application using python . This can be enhanced further in future.