Fix #1: PyQt6 and Tkinter GUIs

This commit is contained in:
Anthony Wang 2024-01-02 20:06:09 -06:00
parent fdd8f1fe2d
commit 33b76d4106
Signed by: a
SSH key fingerprint: SHA256:B5ADfMCqd2M7d/jtXDoihAV/yfXOAbWWri9+GdCN4hQ
3 changed files with 105 additions and 1 deletions

View file

@ -10,7 +10,11 @@ To create a card deck, use `sqlite3 cards "CREATE TABLE cards (idx INTEGER PRIMA
Now build this project with `gcc sd.c segmenttree.c -o sd -lsqlite3 -O2 -march=native` and run `./sd` to enjoy a fast flash cards experience! The program will display the `key` of a randomly selected card. Press any key to show the `val` of the card. Now press either `y` or `n` depending on whether you got the card correct, and the program adjusts that card's weight.
If you're wondering where the name came from, this is the C port of [SD](https://git.exozy.me/a/SD), which was named after a common type of flash card. 😀
There is also a Python GUI which requires PyQt6. Run it with `python main.py PATH_TO_SDC_BINARY`. You can optionally pass additional flags to SDC. Alternatively, there is a Tkinter GUI, `python tkinter.py PATH_TO_SD_BINARY`, that only requires the Python standard library but does not support Wayland. The GUIs are not compatible with the original unmaintained SD which lacks noninteractive mode, but it would be easy to add that to SD.
It should also be fairly easy to write your own SD clone or GUI, so if you write one, I'd be glad to link to it here.
If you're wondering where the name came from, this is the C port of SD, which was named after a common type of flash card. 😀
## Performance

50
main.py Normal file
View file

@ -0,0 +1,50 @@
import subprocess
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel
from PyQt6.QtGui import QFont
from PyQt6.QtCore import Qt
class SDGUI(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(100, 100, 1280, 720)
self.setWindowTitle('SD GUI')
# Start SD
self.proc = subprocess.Popen(
sys.argv[1:] + ['-n'], stdin=subprocess.PIPE, stdout=subprocess.PIPE
)
# Display key
key = self.proc.stdout.readline().decode('utf-8')
self.label = QLabel(key, self)
self.label.setFont(QFont('Arial', 48))
self.label.setWordWrap(True)
self.label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.setCentralWidget(self.label)
def keyPressEvent(self, event):
if self.label.text().count('\n') == 2 and event.text() not in 'yn':
# Manually quit here because stdout.readline blocks and doesn't error when SD exits
self.close()
# Write to SD
self.proc.stdin.write((event.text() + '\n').encode('utf-8'))
self.proc.stdin.flush()
# Get response
text = self.proc.stdout.readline().decode('utf-8')
if text.startswith('>'):
# Key
self.label.setText(text)
else:
# Value
self.label.setText(self.label.text() + text)
app = QApplication(sys.argv)
window = SDGUI()
window.show()
app.exec()

50
tkinter.py Normal file
View file

@ -0,0 +1,50 @@
import subprocess
import sys
import tkinter
from tkinter import ttk
from tkinter import font
# Initialize Tk root
root = tkinter.Tk()
root.geometry('1280x720')
root.title('SD GUI')
# Start SD
proc = subprocess.Popen(
sys.argv[1:] + ['-n'], stdin=subprocess.PIPE, stdout=subprocess.PIPE
)
# Display key
key = proc.stdout.readline().decode('utf-8')
label = ttk.Label(root, text=key, font=font.Font(size=48), wraplength=900)
label.place(relx=0.5, rely=0.5, anchor='center')
def key_handler(event):
if label['text'].count('\n') == 2 and event.char not in 'yn':
# Manually quit here because stdout.readline blocks and doesn't error when SD exits
root.quit()
# Write to SD
proc.stdin.write((event.char + '\n').encode('utf-8'))
proc.stdin.flush()
# Get response
text = proc.stdout.readline().decode('utf-8')
if text.startswith('>'):
# Key
label['text'] = text
else:
# Value
label['text'] += text
def on_closing():
root.quit()
# Run the main loop
root.bind('<Key>', key_handler)
root.protocol('WM_DELETE_WINDOW', on_closing)
root.mainloop()