analitics

Pages

Monday, August 3, 2026

tkinter : simple rss feeds reader on pydroid 3.

Today, this is a simple rss feeds reader with tkinter on pydroid I.D.E. android. The source code is very simple and get feeds from web. See the result:
import tkinter as tk
from tkinter import messagebox, ttk
import webbrowser
import feedparser

RSS_URL = "https://blog.python.org/feeds/posts/default"

article_links = []


def clean_text(text):
    """Converts text to basic ASCII to strip non-supported Android Tkinter characters."""
    if not text:
        return ""
    # Encodes to ASCII ignoring emojis, special quotes, and unsupported byte sequences
    clean = text.encode("ascii", "ignore").decode("ascii")
    # Removes extra whitespace and linebreaks
    return " ".join(clean.split())


def load_feed():
    global article_links

    listbox.delete(0, tk.END)
    article_links.clear()

    status_label.config(text="Fetching articles...", foreground="blue")
    root.update()

    try:
        feed = feedparser.parse(RSS_URL)

        if not feed.entries:
            status_label.config(text="No articles found.", foreground="red")
            return

        for entry in feed.entries:
            title_raw = entry.get("title", "Untitled")
            title = clean_text(title_raw)
            link = entry.get("link", "")

            listbox.insert(tk.END, title)
            article_links.append(link)

        status_label.config(
            text=f"Loaded {len(feed.entries)} articles!", foreground="green"
        )

    except Exception as e:
        status_label.config(text="Connection error!", foreground="red")
        messagebox.showerror("Error", f"Failed to load feed:\n{e}")


def open_link(event):
    try:
        index = listbox.curselection()[0]
        url = article_links[index]
        if url:
            webbrowser.open(url)
    except IndexError:
        pass


# --- GUI Setup ---
root = tk.Tk()
root.title("Python Foundation RSS Reader")
root.geometry("600x800")

title_label = ttk.Label(
    root, text="Python Software Foundation Blog", font=("Helvetica", 14, "bold")
)
title_label.pack(pady=10)

refresh_btn = ttk.Button(root, text="Refresh", command=load_feed)
refresh_btn.pack(pady=5)

status_label = ttk.Label(
    root, text="Connecting...", font=("Helvetica", 10)
)
status_label.pack(pady=5)

frame = ttk.Frame(root)
frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL)

listbox = tk.Listbox(
    frame,
    font=("Helvetica", 11),
    selectbackground="#007ACC",
    selectforeground="white",
    activestyle="none",
    yscrollcommand=scrollbar.set,
    bd=1,
    relief="solid",
)

scrollbar.config(command=listbox.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

listbox.bind("<>", open_link)

root.after(500, load_feed)
root.mainloop()