A handy graphical user interface library for daily use
Project description
Pancake Kit
Pancake Kit aims to provide a handy user interface to your Python script. It provides GUI as a lightweight web app powered by Flask.
Installation
pip3 install pancakekit
Quick Tasting
A good lesson of pancake cooking is that being simple is awesome. PancakeKit tries to make GUI preparation as easy as a pancake.
from pancakekit import Pancake
def fibonacci(n=10):
return (fibonacci(n-1) + fibonacci(n-2)) if n >= 2 else n
cake = Pancake() # Step 1: Make a Pancake instance.
cake.add(fibonacci) # Step 2: Add your function to the pancake.
cake.serve() # Step 3: Serve the cake.
When you open http://127.0.0.1:8000/
in a web browser, you will find an input box for entering n
and a button that invokes fibonacci()
.
Adding a Python object as a topping
In Pancake Kit, a Pancake instance corresponds to a single web page. Each UI component is added to the pancake as a Topping instance.
Dictionary: multiple inputs
d = cake.add({"a": 0, "b": 1})
d.value_changed = lambda: print(d.value)
String: input
a = cake.add("a") # str
a.value = 4
a.value_changed = lambda x: print(x)
Number: text box
b = cake.add(0) # number
b.value = 1
Function: multiple inputs & execution button
def f(a, b, c):
return a * b + c
cake.add(f)
Equivalently, you can decorate the function with a decorator @cake.topping
:
@cake.topping
def f(a, b, c):
return a * b + c
Adding a topping
You can add your favorite toppings to your pancake, as in the following example:
from pancakekit import Pancake, Button, Label
cake = Pancake()
button = cake.add(Button(0))
label = cake.add(Label(1))
def button_click(x):
button.value = label.value
label.value += x
button.clicked = button_click
cake.serve()
Here, when a clicked
event is sent to button_click
, the value of the button is passed as an argument. The value of the topping can be changed by assigning a value to the value
property.
Responding to user actions
When a user changes the value of the toppings from the browser, the callback function specified by topping.value_changed
is invoked.
from pancakekit import *
cake = Pancake()
dict_input = cake.add(DictInput({"a": 1, "b": 2, "c": 3}))
dict_input.value_changed = lambda: cake.show_message(dict_input.value)
cake.serve()
Note that cake.show_message()
will pop up a message in the browser.
Accessing a topping by its name
You can access the toppings in the cake by their names.
from pancakekit import *
cake = Pancake()
cake.add(Slider("a", range_min=0, range_max=20), name="slider0")
cake.add(Slider("b", range_min=0, range_max=20), name="slider1")
cake["slider0"].value_changed = lambda x: setattr(cake["slider1"], "value", x+5)
cake["slider1"].value_changed = lambda x: setattr(cake["slider0"], "value", x*2)
cake.serve()
Use Pancake Kit in the interactive mode
In the interactive mode, you can perform on-site decoration on your pancake.
# On the Terminal or Command Prompt
from pancakekit import *
cake = Pancake()
cake.serve()
# -> You will find a blank page on http://127.0.0.1:8000/.
d = cake.add({"a": 1, "b":2, "c":3})
# -> A DictInput appears on the page immediately.
d.value_changed = cake.show_message
# -> As you change the values of the input, you will see a pop-up message.
As a shortcut to the instantiation & cake.serve(), you can use MagicPancake. The additional feature of the MagicPancake is that you can access the value of a topping by its name.
from pancakekit import *
cake = MagicPancake()
cake.add("myinput", name="a")
cake.a = 10
cake["a"].value_changed = lambda: cake.show_message(cake.a)
More conveniently, execute
python3 -m pancakekit
where the cake
object and all the toppings in pancakekit
have already been loaded as local variables.
Alternatively, you can use MagicCard to add the toppings.
MagicCard
By holding down the shift key and pressing the return key, MagicCard appears with a text box. You can execute the code in the textbox by the command/control key + return. The pancake can be referred to as cake
. Try the following to see if it actually works.
cake.add(Button("Hi"))
cake(cake.toppings) # In the magic card, the direct call of cake() pops up a message.
Toppings
Toppings for user interaction
Button(title: str)
btn = cake.add(Button("Button"))
btn.clicked = lambda x: print(x)
btn.value = "My button"
Input(label: str, default=None, placeholder=None)
myinput = cake.add(Input("input", default=1))
myinput.value_changed = lambda x: print(x)
myinput.value += 1
DictInput(input_dict: dict)
dict_input = cake.add(DictInput({"a": 0, "b": 2}))
print(dict_input.value) # -> {"a": 0, "b": 2}
dict_input["a"] = 1
print(dict_input["a"]) # -> 1
dict_input.value_changed = cake.show_message
Slider(key: str, range_min: float, range_max: float, value: float=None)
slider = cake.add(Slider("myslider", range_min=0, range_max=10, value=5))
slider.value_changed = cake.show_message
Toppings for display
Label(text: str)
Text(text: str)
Paragraph(text: str)
ImageBox(image: PIL.Image|str)
- image argument should be PIL.Image or a path to a image file.
ImageCard(image: PIL.Image|str)
Table(df: pandas.DataFrame)
Toppings for arrangement
Row()
cake = Pancake()
row = cake.add(Row())
my_input = row.add(Input("Input"))
button = row.add(Button("Go!"))
button.clicked = lambda: cake.show_message(my_input.value)
Column()
cake = Pancake()
column = cake.add(Column())
my_input = column.add(Input("Input"))
button = column.add(Button("Go!"))
button.clicked = lambda: cake.show_message(my_input.value)
Card()
Make its content draggable such as ImageCard.
cake = Pancake()
card = cake.add(Card())
row = card.add(Row())
for key in ["a", "b", "c"]:
row.add(Slider(key, 0, 10))
FloatingCard()
A Card topping floating above other toppings with a classic-style draggable handle.
Automated toppings
FromFunction(function)
Serving multiple pancakes
As you know, a pacanke should be served on a plate. That is,
from pancakekit import *
plate = Plate()
class Crape(Pancake):
def decorate(self):
b = self.add(Button("I want to have a waffle!"))
b.clicked = lambda: plate.go_to("Waffle")
def show_up(self):
plate.cake["greediness"].value += 1
class Waffle(Pancake):
def decorate(self):
b = self.add(Button("I want to have a taiyaki!"))
b.clicked = lambda: plate.go_to("Taiyaki")
def show_up(self):
plate.cake["greediness"].value += 2
class Taiyaki(Pancake):
def decorate(self):
b = self.add(Button("I want to have a crape!"))
b.clicked = lambda: plate.go_to("Crape")
def show_up(self):
plate.cake["greediness"].value += 3
Crape(plate)
Waffle(plate)
Taiyaki(plate)
plate.cake.add(Label("Greediness:"))
plate.cake.add(0, name="greediness")
plate.serve()
When subclassing Pancake, describe the procedure to be performed once when instantiating in the decorate()
and the procedure to be performed each time the page is displayed in show_up()
.
Making a custom topping
One of the simplest custom topping is as follows:
class MyLabel(Topping):
def prepare(self, text):
self.value = text
style = {"text-shadow": f"1px 1px 1px #bbb"}
self.label = Tag("label", style = style, value_ref=self)
def html(self):
return self.label.render()
prepare(self, *args, **kwargs)
is called once when the topping is added to a pancake. html(self)
returns a HTML string to be rendered.
Other than prepare
and html
, you can override the following methods:
-
value_getter(self) -> Any
This method returns a value of the topping. The default behavior is to return
self._value
. -
value_preprocessor(self, value: Any) ->Any
This method processes
value
and returns a value to be stored inself._value
. The default behavior is to returnvalue
. -
web_value_preprocessor(self, tag: Tag, value: Any) ->Any
This method processes
value
from the browser input and returns a value to be stored inself._value
. The default behavior is to returnvalue
. -
event_preprocessor(self, event: Event)->Any
This value processes event and returns a value to be passed to an user-defined function. The default behavior is to return
event.value
.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.