We’ll start off by working through a quick app that just does the very basics we need to study. It’ll load up some cards out of a JSON file, shuffle them, and go through them one at a time as you press the D button on the MagTag. In the next section, we’ll add some fancier features, like sorting your cards into categories, and letting you pick which ones you’d like to study per session.

In this code, we’ll be using a PCF font for international character sets. PCF fonts offer a little extra efficiency compared to raw BDF (bitmap) fonts, so they’re easier to fit on CircuitPython drives. We’ll be using one today for the Japanese Hiragana and Katakana characters used in this deck.

Download the Software

Download the code by clicking the "Download: Project Zip" and copy the files to the CIRCUITPY flash drive that appears on your computer when you plug your MagTag in to your computer via a known good USB cable.

Here's the program we'll be running on the code.py file in the CIRCUITPY drive.

import time
import json
import terminalio
import digitalio
import random
from adafruit_magtag.magtag import MagTag

# Set up the magtag
print("Magtag Basic Flashcards")
magtag = MagTag()

# Import cards
cards = {}
with open("deck.json") as fp:
    cards = json.load(fp)

# Create a text area
magtag.add_text(
    text_font="yasashi20.pcf",
    text_position=(
        magtag.graphics.display.width // 2,
        magtag.graphics.display.height // 2,
    ),
    line_spacing=0.85,
    text_anchor_point=(0.5, 0.5),
)

# Set up buttons
cur_btn = False
prev_btn = False

while True:
    # Shuffle the deck
    cards = sorted(cards, key=lambda _: random.random())
    for card in cards:

        # Show the first side and wait for the D button
        text = ''.join(magtag.wrap_nicely(card[0], 20))
        magtag.set_text(text)
        while True:
            cur_btn = magtag.peripherals.button_d_pressed
            if cur_btn and not prev_btn:
                print("Show Result")
                time.sleep(0.1)
                break
            prev_btn = cur_btn

        # Show the second side and wait for the D button
        text = '\n'.join(magtag.wrap_nicely(card[1], 11))
        text += '\n'
        text += '\n'.join(magtag.wrap_nicely(card[2], 20))
        print(text)
        magtag.set_text(text)
        while True:
            cur_btn = magtag.peripherals.button_d_pressed
            if cur_btn and not prev_btn:
                print("Next Card")
                time.sleep(0.1)
                break
            prev_btn = cur_btn

Example Deck

In addition, here's an example "deck" of cards, written in JSON. In case you've never used JSON before, it stands for JavaScript Object Notation: it's a format of writing data (like arrays and key-value pairs) that was originally derived from Javascript but is now commonly used across many different programming languages. In this example deck file, we create a list of lists, using square brackets [] to enclose the lists and commas , to separate list elements.

[
    ["Monday","げつ ようび","Getsu yōbi"],
    ["Tuesday","か ようび","Ka yōbi"],
    ["Wednesday","すい ようび","Sui yōbi"],
    ["Thursday","もく ようび","Moku yōbi"],
    ["Friday","きん ようび","Kin yōbi"],
    ["Saturday","ど ようび","Do yōbi"],
    ["Sunday","にち ようび","Nichi yōbi"]
]

This particular example is written for studying Japanese, but it should work fine for any topic you want - Spanish, geography, code reference, obscure Star Trek trivia, whatever. Just make sure to tweak the text-displaying parts of the code if you add or remove “sections” of the card structure.

How does it work?

Let's walk through this code step by step. First, we import all the required libraries, and create an object for the magtag that contains all the library features, like detecting button presses. We'll also tell the Serial Port we've started up the program.

import time
import json
import terminalio
import digitalio
import random
from adafruit_magtag.magtag import MagTag

# Set up the magtag
print("Magtag Basic Flashcards")
magtag = MagTag()

Then, we use the json library to open our deck file, and interpret the JSON syntax into a list-of-lists that we can use in Python. 

# Import cards
cards = {}
with open("deck.json") as fp:
    cards = json.load(fp)

As the last part of our setup, we create a text object to hold the sides of our flashcard. This uses the Yasashi 20 point PCF font, which contains both english and Japanese Hira and Katakana characters (no Kanji, though, sadly - that's a bit too much for the size of the Magtag's memory).

We'll put it right in the center of the screen.

# Create a text area
magtag.add_text(
    text_font="yasashi20.pcf",
    text_position=(
        magtag.graphics.display.width // 2,
        magtag.graphics.display.height // 2,
    ),
    line_spacing=0.85,
    text_anchor_point=(0.5, 0.5),
)

To actually change the sides of the card, and to move to the next card, we'll need to detect when a magtag button is pressed.

The magtag library contains the attribute magtag.peripherals.button_d_pressed, which will tell us whether the D button is currently up or down. But this value by itself isn't able to detect when the button is pressed. To do that, we'll create a couple of memory variables:

cur_btn = False
prev_btn = False

Whenever we want to wait for a button press, we'll enter a short while loop, and do nothing until we see the button change from an "up" state to a "down" state.

while True:
    cur_btn = magtag.peripherals.button_d_pressed
    if cur_btn and not prev_btn:
        print("Show Result")
        time.sleep(0.1)
        break
    prev_btn = cur_btn

Before we actually start using the deck, we want to make sure it isn't in the same order every time. Circuitpython doesn't have access to the random.shuffle() function, but we can fake it by using the built in function sorted() and indexes from random.random() to achieve the same effect. 

cards = sorted(cards, key=lambda _: random.random())

When we want to display text, we use the built in magtag set_text function. By using wrap_nicely, we can make sure that the card text won't ever go off the side of the magtag - note that characters from other languages (like Hiragana) can be larger than roman ones, so expect to change the length parameter based on the kind of text you want to display.

# Example Hira wrapping (fewer characters)
text = '\n'.join(magtag.wrap_nicely(card[1], 11))
# Example Roman wrapping (more characters)
text += '\n'.join(magtag.wrap_nicely(card[2], 20))
# Set the contents of the text field
magtag.set_text(text)

We combine all these elements into the program's final main loop, which will run through the cards in a random order forever, waiting on user button presses to move forward.

while True:
    # Shuffle the deck
    cards = sorted(cards, key=lambda _: random.random())
    for card in cards:

        # Show the first side and wait for the D button
        text = ''.join(magtag.wrap_nicely(card[0], 20))
        magtag.set_text(text)
        while True:
            cur_btn = magtag.peripherals.button_d_pressed
            if cur_btn and not prev_btn:
                print("Show Result")
                time.sleep(0.1)
                break
            prev_btn = cur_btn

        # Show the second side and wait for the D button
        text = '\n'.join(magtag.wrap_nicely(card[1], 11))
        text += '\n'
        text += '\n'.join(magtag.wrap_nicely(card[2], 20))
        print(text)
        magtag.set_text(text)
        while True:
            cur_btn = magtag.peripherals.button_d_pressed
            if cur_btn and not prev_btn:
                print("Next Card")
                time.sleep(0.1)
                break
            prev_btn = cur_btn

This guide was first published on Jan 06, 2021. It was last updated on Jan 06, 2021.

This page (Simple Flashcards) was last updated on Oct 22, 2021.

Text editor powered by tinymce.