Creating a modern GUI for your python application 
Tags: python, eel, html, javascript
Published: 2020-12-22 03:21:04

In this post, we are going to use a library which will allow us to create outstanding graphical user interfaces (GUI's) for our day to day python scripts.

We have a bunch of options to create GUI's on python, tkinter, wxPython, PySimpleGui, among others. Tkinter is really robust and allow us to have cross-platform applications, however, Tkinter based GUI's aren't as beautiful as what we can typically find with web based applications, and other cool applications based on electron. 

Eel is a library which allow us to take advantage of web technologies, such as HTML, CSS, JS and of course, all bunch of web frameworks out there, as bootstrap, jquery, cool plotting libraries as plotly, etc.

# Eel
[Eel library](https://github.com/samuelhwilliams/Eel) allow us to easily make use of HTML, CSS and JS for building our User Interface, without losing all our powerful Python capabilities. Eel relies on a bunch of python libraries, it simply creates a local webserver and opens a browser (chrome by default), the browser renders HTML, CSS and JS, while python controls most of the logic. 

Cool thing with Eel, is that allow us to run python functions from javascript and viceversa, thus, we can exchange information and have the best of both worlds (python and JS).

# Installing eel
In order to install eel library, you can do it from Pypi as:
```
pip install eel
```
Highly recommended to create a virtual environment first.

# How to use it?
We must create our folder structure first, our root folder will be "application". Inside, we will create our python script, which I decided to call app.py. 

In order to better structure our code, we created a subfolder named "web", which contains index.html file, and two subfolders for our css and js files.

```
application
│   app.py
│
└───web
    │   index.html
    │
    ├───css
    │       main.css
    │
    └───js
            main.js
```
For this post, we will build a top menu resembling a file menu for desktop applications using pre-built code from [W3schools](https://www.w3schools.com/css/css_navbar_horizontal.asp). First, we must edit our html file:
```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Eel example</title>

    <link rel="stylesheet" href="css/main.css">
    <script type="text/javascript" src="/eel.js"></script> 
</head>
<body>
    <div class="topnav">
        <a class="active" id="button-name">Display name</a>
        <a id="button-number">Display a random number</a>
        <a id="button-date">Display time and date</a>
        <a id="button-ip">Display my ip</a>
      </div> 
</body>
<script src="js/main.js"></script>
</html>
```

As you can see, you would be able to create your whole GUI using HTML, we just must add `<script type="text/javascript" src="/eel.js"></script> `, this script will allow us to call our exposed python functions.

For CSS file:
```
/* Add a black background color to the top navigation */
.topnav {
    background-color: #333;
    overflow: hidden;
  }
  
  /* Style the links inside the navigation bar */
  .topnav a {
    float: left;
    color: #f2f2f2;
    text-align: center;
    padding: 14px 16px;
    text-decoration: none;
    font-size: 17px;
  }
  
  /* Change the color of links on hover */
  .topnav a:hover {
    background-color: #ddd;
    color: black;
  }
  
  /* Add a color to the active/current link */
  /* .topnav a.active {
    background-color: #4CAF50;
    color: white;
  } */
```
And finally, for JS file, we're just adding event listeners to out four buttons in navbar. As you can see, all of them are calling some functions but started with eel, e.g. ell.get_random_name(), this is a python function, thus, when we click the button, it will call a python function. Also, we have a JS function called prompt_alerts and it has a decorator eel.expose, this allow us to run this JS function from python:
```
document.getElementById("button-name").addEventListener("click", ()=>{eel.get_random_name()}, false);
document.getElementById("button-number").addEventListener("click", ()=>{eel.get_random_number()}, false);
document.getElementById("button-date").addEventListener("click", ()=>{eel.get_date()}, false);
document.getElementById("button-ip").addEventListener("click", ()=>{eel.get_ip()}, false);

eel.expose(prompt_alerts);
function prompt_alerts(description) {
  alert(description);
}
```
We have completed our graphical user interface, now, we must create our python file. We must import eel library, and all other libraries you need for your project, in this case, random and datetime.

```
import eel
import random
from datetime import datetime

eel.init('web')

@eel.expose
def get_random_name():
    eel.prompt_alerts('Random name')

@eel.expose
def get_random_number():
    eel.prompt_alerts(random.randint(1, 100))

@eel.expose
def get_date():
    eel.prompt_alerts(datetime.now().strftime("%d/%m/%Y %H:%M:%S"))

@eel.expose
def get_ip():
    eel.prompt_alerts('127.0.0.1')

eel.start('index.html')
```
Then, we must add our eel.init line, this initialize eel library, to an specific folder. Then, we create our four functions, which we want to call from JS, that's why we added decorator `@eel.expose`. As you can see, each one is calling our JS function `prompt_alerts` and passing a string argument.

`eel.start` will run the application, there are a lot of arguments that can be passed, in this example, we're using minimal arguments, we're just setting the html file to be rendered (relative to web folder).

Now that we have completed our code, we can start our application:
```python app.py```
A new window should appeared, as shown in next figure:
![Python GUI using eel library](https://dev-to-uploads.s3.amazonaws.com/i/m1rpp2yan906gasoldvr.png)

If you click on any of your four buttons, an alert should be shown, e.g.:
![Alert example](https://dev-to-uploads.s3.amazonaws.com/i/byh3hsqfhyfulmfjlf3l.png)

Now, you're able to create outstanding GUI's for you python applications, in our next series, we will create a complex example and explore other arguments that can be passed to eel.start.