Tjena-hopp, Tobbe här.
Nu är det äntligen dags för Dev Blog #1! Det har i och för sig bara gått några dagar sen #0 … men ändå! Dagens agenda är ett Python-program gjort med TkInter.
Boken om Cirus och Lucas
För de som inte vet (det vill säga cirka 20 % av de som läser detta, då praktiskt taget de enda som slänger en blick på denna artikel är mina nära vänner, som redan vet) så skriver jag för närvarande en bok. Den heter Boken om Cirus och Lucas. Det är en sci-fi-bok som handlar om – du gissade (troligtvis) rätt – Cirus och Lucas. Mer än så avslöjar jag inte … förrän nästa Dev Blog kommer ut! Haha, you stepped right into my trap! Nu är du tvungen att läsa nästa, med förutsättningen av att du är någorlunda intresserad… Vilket jag hoppas att du är!
WRITe i Python
Tillbaka till ämnet: WRITe. Eftersom jag skriver en bok, vill jag hålla koll på antalet ord jag har skrivit, vilket detta program är tänkt att göra. Jag skissade upp hur det på ett ungefär skulle se ut. Resultatet:

Det är inte riktigt en skiss, men varför skulle jag rita upp en skiss, när jag kan få det perfekt? Idén är helt enkelt ett Excel-inspirerat kalkylblad. De olika kolumnerna ska innehålla dagens datum, totala antalet ord, och den sista, Ökning, ska vara autogenererad, baserad på ordantalet. Detta räknas lätt ut genom att ta dagens ordantal och subtrahera gårdagens ordantal.
Så, nu har vi ett koncept. Nu är det bara kvar att göra programmet…! Men det är lättare sagt än gjort. Först måste vi välja språk; Python. Varför Python? Kul att du frågar! Python, känt för att vara ganska slött (i jämförelse med exempelvis C, C++, Rust, Java eller alla andra main-stream språk), är dock väldigt simpelt och light-weight.
Jag gjorde bedömningen, och kom fram till att detta program inte blir något (betydligt) slöare i fall jag använder Python, då det är ohyggligt simpelt. Jag hade lika gärna kunna göra det med penna eller papper; det är en helt annan grej om man ska göra ett robust, snabbt operativsystem. Då använder man oftast C, C++, C# och Assembly, som är bokstavligen byggda för det. Men vi är ännu inte klara med planeringen… TkInter är ett bibliotek inbyggt i Python, gjort för att skapa fönster. ”Vad menar du med detta, Tobbe?” Jo, detta…:

… i stället för detta:

Som ni kan se, så är TkInter-program inte bara snyggare, utan även svårare att göra fel i. Så, TkInter it is! Nu kan vi började skriva kod. Hädanefter antar jag att du är någorlunda bekant med programmering i allmänhet. Koden är kommenterad, dock på engelska.
Jag satte i hop (som jag inte tycker skrivs ”ihop”) ett program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | import tkinter import threading ENTRIES = {} # Entry box dictionary, containing all the entry boxes ROWS = 5 COLUMNS = 3 class SimpleTableInput(threading.Thread, tkinter.Frame): def __init__(self, parent): tkinter.Frame.__init__(self, parent) # Validation command; command to validate entry box input (only # numbers are allowed) global validationCommand validationCommand = (self.register(self.validate), "%P") # Create integer-only entry boxes for row in range(ROWS): for column in range(COLUMNS): self.addEntry(row, column, validationCommand) # Create column headers headers = ["Date", "Word Count", "Word Increase"] for column in range(COLUMNS): index = (0, column) entry = ENTRIES[index] header = tkinter.StringVar(parent, value=headers[column]) entry.config(textvariable=header) entry.config(state="readonly") def addEntry( self, row: int, column: int, # Default validation command: True if int. validationCommand=(lambda x: True if x is int else False), ): entryBox = tkinter.Entry( self, validate="key", validatecommand=validationCommand ) entryBox.grid(row=row, column=column, stick="nsew") index = (row, column) ENTRIES[index] = entryBox def validate(self, P): """ Perform input validation. Allow only an empty value, or a value that can be converted to an int. """ try: int(P) except ValueError: return False return True class App(tkinter.Frame): def __init__(self, parent): super().__init__() tkinter.Frame.__init__(self, parent) self.table = SimpleTableInput(self) self.table.grid(row=1, column=1, sticky="nsew") root = tkinter.Tk() root.title("WRITe") root.resizable(width=False, height=False) App(root).pack(side="top", fill="both", expand=True) root.mainloop() |
(Ett stort tack till Bryan Oakley, vars kalkylbladskod jag baserade mitt program på.) Denna kod genererar detta program:
Inget komplicerat, inget speciellt; bara en prototyp. Programspråket är engelska, då (nästan) all kod jag skriver är på engelska. Jag kommer troligtvis lägga till en språkknapp, som kan byta mellan båda. Svenska namnet får väl vara SKRIv! Haha! Fattar du? Det hoppas jag… Nu har vi i alla fall ett kalkylblad, med tre kolumnrubriker. Den översta raden går inte att redigera, och har förinställd text, vilket åstadkoms med följande kod:
1 2 3 4 5 6 7 | headers = ["Date", "Word Count", "Word Increase"] for column in range(COLUMNS): index = (0, column) entry = ENTRIES[index] header = tkinter.StringVar(parent, value=headers[column]) entry.config(textvariable=header) entry.config(state="readonly") |
Resterande rutor accepterar bara siffror, med hjälp av validatecommand-attributen:
1 2 3 4 | validationCommand = lambda x: True if x is int else False entryBox = tkinter.Entry( self, validate="key", validatecommand=validationCommand ) |
Programmets källkod finns på GitHub. Nu har vi programmets grund – men vi är ännu inte klara! I nästa WRITe-inlägg kommer vi att lägga till en knapp som lägger till nya rader, en knapp som tar bort rader, och en knapp som sparar datan. Del två finns nedan … när jag har skrivit den, vilket troligtvis är om några dagar. Alla Dev-Blog-inlägg finns här, och alla WRITe-inlägg här.
Men det var allt för mig, vi ses nästa gång!
Tobbe out.