{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b75c14e5",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# GUI User Input and Arranging Widgets\n",
    "#### CS 65: Introduction to Computer Science I"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "046f9c71",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## `tkinter`'s Entry widget\n",
    "\n",
    "The __Entry__ widget provides a text box that allows the user to type in a short bit of text.\n",
    "\n",
    "This is one way to get input from your user\n",
    "* An _Entry_ is for input\n",
    "* A _Label_ is for output - it can't be changed by the user\n",
    "\n",
    "When creating an Entry widget, you initialize it with its parent window and how wide the input box should be."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aa0f301a",
   "metadata": {},
   "outputs": [],
   "source": [
    "self.my_entry = tkinter.Entry(self.main_window, width=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f927dcc2",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Whenever you want to use the input that the user typed into an Entry, use the Entry's `get()` method, which returns the text as a string."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3067f8f8",
   "metadata": {},
   "outputs": [],
   "source": [
    "#You probably want to do this inside a callback function\n",
    "user_input = self.my_entry.get() #this will be a string"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1d066a95",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## A conversion calculator example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1efa7539",
   "metadata": {},
   "outputs": [],
   "source": [
    "import tkinter\n",
    "\n",
    "class KilometersToMilesGUI:\n",
    "    def __init__(self):\n",
    "\n",
    "        # Create the main window.\n",
    "        self.main_window = tkinter.Tk()\n",
    "\n",
    "        # Create the widgets\n",
    "        self.prompt_label = tkinter.Label(self.main_window, text=\"Enter a distance in kilometers:\")\n",
    "        self.kilo_entry = tkinter.Entry(self.main_window, width=10)\n",
    "        self.answer_label = tkinter.Label(self.main_window, text=\"Converted to miles:\")\n",
    "        self.calc_button = tkinter.Button(self.main_window, text=\"Convert\", command=self.convert)\n",
    "\n",
    "        # Pack the widgets.\n",
    "        self.prompt_label.pack()\n",
    "        self.kilo_entry.pack()\n",
    "        self.answer_label.pack()\n",
    "        self.calc_button.pack()\n",
    "\n",
    "        # Enter the tkinter main loop.\n",
    "        tkinter.mainloop()\n",
    "\n",
    "    # The convert method is a callback function for\n",
    "    # the Calculate button.\n",
    "    def convert(self):\n",
    "        # Get the value entered by the user into the\n",
    "        # kilo_entry widget.\n",
    "        kilo = float(self.kilo_entry.get())\n",
    "\n",
    "        # Convert kilometers to miles.\n",
    "        miles = kilo * 0.6214\n",
    "\n",
    "        # Convert miles to a string and create\n",
    "        # the string for the new text to appear\n",
    "        # on the answer label\n",
    "        new_text = \"Converted to miles: {mi:.2f}\".format(mi=miles)\n",
    "        self.answer_label.config(text=new_text)\n",
    "\n",
    "\n",
    "# Create an instance of the KilometersToMilesGUI class.\n",
    "kilo_conv = KilometersToMilesGUI()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f74d408a",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Using the `side` argument when packing\n",
    "\n",
    "When calling `pack()` for any widget, you can give it the optional `side` argument to tell it which part of the window you want it anchored towards (default is `top`)\n",
    "* `side=\"top\"`\n",
    "* `side=\"bottom\"`\n",
    "* `side=\"left\"`\n",
    "* `side=\"right\"`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b7109e98",
   "metadata": {},
   "outputs": [],
   "source": [
    "import tkinter\n",
    "\n",
    "class KilometersToMilesGUI:\n",
    "    def __init__(self):\n",
    "\n",
    "        # Create the main window.\n",
    "        self.main_window = tkinter.Tk()\n",
    "        self.main_window.title(\"km to mi calculator\")\n",
    "        self.main_window.geometry(\"600x300\")\n",
    "\n",
    "        # Create the widgets\n",
    "        self.prompt_label = tkinter.Label(self.main_window, text=\"Enter a distance in kilometers:\")\n",
    "        self.kilo_entry = tkinter.Entry(self.main_window, width=10)\n",
    "        self.answer_label = tkinter.Label(self.main_window, text=\"Converted to miles:\")\n",
    "        self.calc_button = tkinter.Button(self.main_window, text=\"Convert\", command=self.convert)\n",
    "\n",
    "        # Pack the widgets.\n",
    "        self.prompt_label.pack(side=\"top\")\n",
    "        self.kilo_entry.pack(side=\"left\")\n",
    "        self.answer_label.pack(side=\"right\")\n",
    "        self.calc_button.pack(side=\"bottom\")\n",
    "\n",
    "        # Enter the tkinter main loop.\n",
    "        tkinter.mainloop()\n",
    "\n",
    "    # The convert method is a callback function for\n",
    "    # the Calculate button.\n",
    "    def convert(self):\n",
    "        # Get the value entered by the user into the\n",
    "        # kilo_entry widget.\n",
    "        kilo = float(self.kilo_entry.get())\n",
    "\n",
    "        # Convert kilometers to miles.\n",
    "        miles = kilo * 0.6214\n",
    "\n",
    "        # Convert miles to a string and create\n",
    "        # the string for the new text to appear\n",
    "        # on the answer label\n",
    "        new_text = \"Converted to miles: {mi:.2f}\".format(mi=miles)\n",
    "        self.answer_label.config(text=new_text)\n",
    "\n",
    "\n",
    "# Create an instance of the KilometersToMilesGUI class.\n",
    "kilo_conv = KilometersToMilesGUI()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36dcec7a",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Using the `padx` and `pady` arguments when packing\n",
    "\n",
    "You can also send optional `padx` and `pady` arguments to `pack()` which control how much horizontal or vertical space to pad around the widget."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11eaa1db",
   "metadata": {},
   "outputs": [],
   "source": [
    "import tkinter\n",
    "\n",
    "class KilometersToMilesGUI:\n",
    "    def __init__(self):\n",
    "\n",
    "        # Create the main window.\n",
    "        self.main_window = tkinter.Tk()\n",
    "        self.main_window.title(\"km to mi calculator\")\n",
    "        self.main_window.geometry(\"600x300\")\n",
    "\n",
    "        # Create the widgets\n",
    "        self.prompt_label = tkinter.Label(self.main_window, text=\"Enter a distance in kilometers:\")\n",
    "        self.kilo_entry = tkinter.Entry(self.main_window, width=10)\n",
    "        self.answer_label = tkinter.Label(self.main_window, text=\"Converted to miles:\")\n",
    "        self.calc_button = tkinter.Button(self.main_window, text=\"Convert\", command=self.convert)\n",
    "\n",
    "        # Pack the widgets.\n",
    "        self.prompt_label.pack(side=\"left\", padx=20)\n",
    "        self.kilo_entry.pack(side=\"left\", padx=20)\n",
    "        self.answer_label.pack(side=\"bottom\", pady=20)\n",
    "        self.calc_button.pack(side=\"bottom\")\n",
    "\n",
    "        # Enter the tkinter main loop.\n",
    "        tkinter.mainloop()\n",
    "\n",
    "    # The convert method is a callback function for\n",
    "    # the Calculate button.\n",
    "    def convert(self):\n",
    "        # Get the value entered by the user into the\n",
    "        # kilo_entry widget.\n",
    "        kilo = float(self.kilo_entry.get())\n",
    "\n",
    "        # Convert kilometers to miles.\n",
    "        miles = kilo * 0.6214\n",
    "\n",
    "        # Convert miles to a string and create\n",
    "        # the string for the new text to appear\n",
    "        # on the answer label\n",
    "        new_text = \"Converted to miles: {mi:.2f}\".format(mi=miles)\n",
    "        self.answer_label.config(text=new_text)\n",
    "\n",
    "\n",
    "# Create an instance of the KilometersToMilesGUI class.\n",
    "kilo_conv = KilometersToMilesGUI()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7fd14244",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Using Frames\n",
    "\n",
    "A __Frame__ is like a sub-window that you can use to organize your widgets. \n",
    "\n",
    "In the example below, the `main_window` only directly contains three widgets: `top_frame`, `middle_frame`, and `bottom_frame`.\n",
    "\n",
    "All other widgets are placed in one of the frames instead of the main window."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bb25a319",
   "metadata": {},
   "outputs": [],
   "source": [
    "import tkinter\n",
    "\n",
    "class KilometersToMilesGUI:\n",
    "    def __init__(self):\n",
    "\n",
    "        # Create the main window.\n",
    "        self.main_window = tkinter.Tk()\n",
    "        self.main_window.title(\"km to mi calculator\")\n",
    "        self.main_window.geometry(\"600x300\")\n",
    "        \n",
    "        # Create the frames\n",
    "        self.top_frame = tkinter.Frame(self.main_window)\n",
    "        self.middle_frame = tkinter.Frame(self.main_window)\n",
    "        self.bottom_frame = tkinter.Frame(self.main_window)\n",
    "\n",
    "\n",
    "        # Create the widgets\n",
    "        self.prompt_label = tkinter.Label(self.top_frame, text=\"Enter a distance in kilometers:\")\n",
    "        self.kilo_entry = tkinter.Entry(self.top_frame, width=10)\n",
    "        self.answer_label = tkinter.Label(self.middle_frame, text=\"Converted to miles:\")\n",
    "        self.calc_button = tkinter.Button(self.bottom_frame, text=\"Convert\", command=self.convert)\n",
    "\n",
    "        # Pack the frames\n",
    "        self.top_frame.pack(expand=True,fill=\"both\")\n",
    "        self.middle_frame.pack(expand=True,fill=\"both\")\n",
    "        self.bottom_frame.pack(expand=True,fill=\"both\")\n",
    "        \n",
    "        # Pack the widgets.\n",
    "        self.prompt_label.pack(side=\"left\",padx=20)\n",
    "        self.kilo_entry.pack(side=\"left\")\n",
    "        self.answer_label.pack(side=\"left\",padx=20)\n",
    "        self.calc_button.pack(side=\"right\",padx=20)\n",
    "\n",
    "        # Enter the tkinter main loop.\n",
    "        tkinter.mainloop()\n",
    "\n",
    "    # The convert method is a callback function for\n",
    "    # the Calculate button.\n",
    "    def convert(self):\n",
    "        # Get the value entered by the user into the\n",
    "        # kilo_entry widget.\n",
    "        kilo = float(self.kilo_entry.get())\n",
    "\n",
    "        # Convert kilometers to miles.\n",
    "        miles = kilo * 0.6214\n",
    "\n",
    "        # Convert miles to a string and create\n",
    "        # the string for the new text to appear\n",
    "        # on the answer label\n",
    "        new_text = \"Converted to miles: {mi:.2f}\".format(mi=miles)\n",
    "        self.answer_label.config(text=new_text)\n",
    "\n",
    "\n",
    "# Create an instance of the KilometersToMilesGUI class.\n",
    "kilo_conv = KilometersToMilesGUI()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e4a8ca6",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Group Exercise\n",
    "\n",
    "Create a GUI application that allows the user to type in a city and state, and then click a button which displays the population of that city. Use the <a href=\"http://analytics.drake.edu/~manley/CS65/data/zipcodes.json\">zipcodes.json</a> file from __Lab 17__."
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Slideshow",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
