Move to chapter based reader

This commit is contained in:
Christopher T. Johnson
2023-11-15 17:25:13 -05:00
parent 0b02ed2201
commit 2b2f461d2f
5 changed files with 219 additions and 102 deletions

View File

@@ -11,7 +11,6 @@ from main import query_error
class Book: class Book:
sections: List[str] = [] sections: List[str] = []
metadata: Dict[str, str] = {} metadata: Dict[str, str] = {}
words = {}
def __init__(self, src: str) -> None: def __init__(self, src: str) -> None:
super(Book, self).__init__() super(Book, self).__init__()
@@ -131,61 +130,66 @@ class Book:
def parse_section(self, src: str, href: str) -> None: def parse_section(self, src: str, href: str) -> None:
newdom = xml.dom.getDOMImplementation().createDocument("", "html", None) newdom = xml.dom.getDOMImplementation().createDocument("", "html", None)
def strip_node(elm: xml.dom.minidom.Element) -> xml.dom.minidom.Node: def strip_node(elm: xml.dom.minidom.Element) -> xml.dom.minidom.Element:
if elm.nodeType == xml.dom.Node.TEXT_NODE: if elm.nodeType == xml.dom.Node.TEXT_NODE:
return cast( return cast(
xml.dom.minidom.Node, xml.dom.minidom.Element,
newdom.createTextNode(cast(xml.dom.minidom.Text, elm).data), newdom.createTextNode(cast(xml.dom.minidom.Text, elm).data),
) )
newelm = newdom.createElement(elm.localName) newelm: xml.dom.minidom.Element = newdom.createElement(elm.localName)
node = elm.firstChild node = elm.firstChild
while node: while node:
if node.nodeType == xml.dom.Node.TEXT_NODE: elm = cast(xml.dom.minidom.Element, node)
text = node.data if elm.nodeType == xml.dom.Node.TEXT_NODE:
text = cast(xml.dom.minidom.Text, elm).data
if text: if text:
text = text.strip() text = text.strip()
if text and len(text) > 0: if text and len(text) > 0:
newelm.appendChild(newdom.createTextNode(text)) newelm.appendChild(newdom.createTextNode(text))
elif node.localName == "img": elif elm.localName == "img":
pass pass
elif node.localName == "a": elif elm.localName == "a":
a_node = node.firstChild a_node = cast(xml.dom.minidom.Element, elm.firstChild)
while a_node: while a_node:
if a_node.nodeType == xml.dom.Node.TEXT_NODE: if a_node.nodeType == xml.dom.Node.TEXT_NODE:
newelm.appendChild(newdom.createTextNode(a_node.data)) text = cast(xml.dom.minidom.Text, a_node)
newelm.appendChild(newdom.createTextNode(text.data))
else: else:
newelm.appendChild(strip_node(a_node)) newelm.appendChild(strip_node(a_node))
a_node = a_node.nextSibling a_node = a_node.nextSibling
else: else:
newelm.appendChild(strip_node(node)) newelm.appendChild(strip_node(elm))
node = node.nextSibling node = node.nextSibling
return newelm return newelm
def parse_node(parent: xml.dom.Node, elm: xml.dom.Node) -> None: def parse_node(
parent: xml.dom.minidom.Element, elm: xml.dom.minidom.Element
) -> None:
if elm.nodeType == xml.dom.Node.ELEMENT_NODE: if elm.nodeType == xml.dom.Node.ELEMENT_NODE:
if elm.localName.startswith("h"): tag: str = cast(str, elm.localName)
if tag.startswith("h"):
clone = strip_node(elm) clone = strip_node(elm)
parent.appendChild(clone) parent.appendChild(clone)
elif elm.localName == "p": elif tag == "p":
clone = strip_node(elm) clone = strip_node(elm)
clone.normalize() clone.normalize()
parent.appendChild(clone) parent.appendChild(clone)
else: else:
node = elm.firstChild node = elm.firstChild
while node: while node:
parse_node(parent, node) parse_node(parent, cast(xml.dom.minidom.Element, node))
node = node.nextSibling node = node.nextSibling
return return
with open(f"{src}/{href}") as f: with open(f"{src}/{href}") as f:
dom = xml.dom.minidom.parse(f) dom = xml.dom.minidom.parse(f)
title = dom.getElementsByTagName("title")[0].firstChild.data # title = dom.getElementsByTagName("title")[0].firstChild.data
body = dom.getElementsByTagName("body")[0] body = dom.getElementsByTagName("body")[0]
section = newdom.createElement("body") section = newdom.createElement("body")
node = body.firstChild node = body.firstChild
while node: while node:
parse_node(section, node) parse_node(section, cast(xml.dom.minidom.Element, node))
node = node.nextSibling node = node.nextSibling
self.sections.append(section.toxml()) self.sections.append(section.toxml())
return return

View File

@@ -1,13 +1,16 @@
import json import json
from typing import cast
from PyDictionary import PyDictionary # type: ignore[import-untyped] import requests
from PyQt6.QtCore import QRect, Qt, pyqtSlot from PyQt6.QtCore import QPoint, QRect, Qt, QTimer, pyqtSlot
from PyQt6.QtGui import ( from PyQt6.QtGui import (
QBrush, QBrush,
QColor, QColor,
QFont, QFont,
QMouseEvent,
QPainter, QPainter,
QPainterPath, QPainterPath,
QPaintEvent,
QTextCharFormat, QTextCharFormat,
QTextCursor, QTextCursor,
QTextDocument, QTextDocument,
@@ -21,10 +24,26 @@ from ui.EditDialog import Ui_Dialog
class EditDialog(QDialog, Ui_Dialog): class EditDialog(QDialog, Ui_Dialog):
block: int
def __init__(self, person_id: int) -> None: def __init__(self, person_id: int) -> None:
super(EditDialog, self).__init__() super(EditDialog, self).__init__()
self.person_id = person_id self.person_id = person_id
self.setupUi(self) self.setupUi(self)
#
# Override UI
#
font = QFont()
font.setFamily("OpenDyslexic")
font.setPointSize(14)
self.paraEdit.setFont(font)
self.nextParaBtn = QPushButton(parent=self.widget)
self.nextParaBtn.setObjectName("nextParaBtn")
self.verticalLayout.addWidget(self.nextParaBtn)
self.nextParaBtn.setText("Next Paragraph")
#
# End overrides
#
self.load_book(self.person_id) self.load_book(self.person_id)
blockNumber = self.block blockNumber = self.block
self.paraEdit.setReadOnly(True) self.paraEdit.setReadOnly(True)
@@ -33,20 +52,60 @@ class EditDialog(QDialog, Ui_Dialog):
self.block = blockNumber self.block = blockNumber
self.savePosition() self.savePosition()
self.stackedWidget.setCurrentIndex(0) self.stackedWidget.setCurrentIndex(0)
self.nextParaBtn = QPushButton(parent=self.widget)
self.nextParaBtn.setObjectName("nextParaBtn")
self.verticalLayout.addWidget(self.nextParaBtn)
self.nextParaBtn.setText("Next Paragraph")
self.defineBtn.clicked.connect(self.defineAction) self.defineBtn.clicked.connect(self.defineAction)
self.showBtn.clicked.connect(self.showAction) self.showBtn.clicked.connect(self.showAction)
self.nextBtn.clicked.connect(self.nextAction) self.nextBtn.clicked.connect(self.nextAction)
self.prevBtn.clicked.connect(self.prevAction) self.prevBtn.clicked.connect(self.prevAction)
self.nextParaBtn.clicked.connect(self.nextParaAction) self.nextParaBtn.clicked.connect(self.nextParaAction)
self.wordsBtn.clicked.connect(self.wordAction)
self.paraEdit.verticalScrollBar().valueChanged.connect(self.scrollSlot) self.paraEdit.verticalScrollBar().valueChanged.connect(self.scrollSlot)
return return
@pyqtSlot()
def wordAction(self) -> None:
pos = self.paraEdit.mapTo(self, self.paraEdit.cursorRect().topLeft())
top = self.paraEdit.mapTo(self, QPoint(0, 0))
value = self.paraEdit.verticalScrollBar().value()
#
# XXX - Where does "4" come from?
#
delta = pos.y() - top.y() - 4
self.pxPerTick = int(1000 / delta)
if self.pxPerTick < 1:
if delta < 0:
self.pxPerTick = -1
else:
self.pxPerTick = 1
steps = abs(delta / self.pxPerTick)
msPerTick = int(1000 / steps)
if msPerTick < 3:
msPerTick = 3
self.target = value + delta
print(f"delta: {delta}, pixels: {self.pxPerTick}, ms: {msPerTick}")
timer = QTimer(self)
timer.timeout.connect(self.softTick)
timer.start(msPerTick)
return
@pyqtSlot()
def softTick(self) -> None:
value = self.paraEdit.verticalScrollBar().value()
sender: QTimer = cast(QTimer, self.sender())
if self.pxPerTick < 0: # moving content up
if value < self.target:
sender.stop()
return
else:
if value > self.target:
sender.stop()
return
value += self.pxPerTick
self.paraEdit.verticalScrollBar().setValue(value)
self.update()
return
@pyqtSlot(int) @pyqtSlot(int)
def scrollSlot(self, value): def scrollSlot(self, value: int) -> None:
self.update() self.update()
return return
@@ -82,7 +141,7 @@ class EditDialog(QDialog, Ui_Dialog):
self.sequence_map[query.value("sequence")] = query.value("section_id") self.sequence_map[query.value("sequence")] = query.value("section_id")
return return
def show_section(self, section_id, start=True): def show_section(self, section_id: int, start: bool = True) -> None:
sequence = self.section_map[section_id] sequence = self.section_map[section_id]
self.setWindowTitle(f"Section {sequence}") self.setWindowTitle(f"Section {sequence}")
self.paraEdit.clear() self.paraEdit.clear()
@@ -96,29 +155,57 @@ class EditDialog(QDialog, Ui_Dialog):
cursor.setPosition(textBlock.position()) cursor.setPosition(textBlock.position())
self.paraEdit.setTextCursor(cursor) self.paraEdit.setTextCursor(cursor)
self.paraEdit.ensureCursorVisible() self.paraEdit.ensureCursorVisible()
#
# Mark all the defined words with underlines
#
def_format = QTextCharFormat()
def_format.setFontUnderline(True)
cursor = QTextCursor(self.paraEdit.document())
query = QSqlQuery()
query.prepare("SELECT * FROM word_block " "WHERE section_id = :section_id")
query.bindValue(":section_id", section_id)
if not query.exec():
query_error(query)
while query.next():
#
# Define these variables so that the code matches
# the defining action
#
blockNum = query.value("block")
start = query.value("start")
end = query.value("end")
textBlock = self.paraEdit.document().findBlockByNumber(blockNum)
cursor.setPosition(
start + textBlock.position(), QTextCursor.MoveMode.MoveAnchor
)
cursor.setPosition(
end + textBlock.position(), QTextCursor.MoveMode.KeepAnchor
)
cursor.setCharFormat(def_format)
return return
def mousePressEvent(self, event): def mousePressEvent(self, event: QMouseEvent | None) -> None:
return return
def paintEvent(self, e): def paintEvent(self, e: QPaintEvent | None) -> None:
position = self.paraEdit.document().findBlockByNumber(self.block).position() position = self.paraEdit.document().findBlockByNumber(self.block).position()
cursor = self.paraEdit.textCursor() cursor = self.paraEdit.textCursor()
cursor.setPosition(position) cursor.setPosition(position)
#
# rect is position in viewport coordenates.
rect = self.paraEdit.cursorRect(cursor) rect = self.paraEdit.cursorRect(cursor)
# print(rect) c_pt = self.paraEdit.mapTo(self, rect.bottomLeft())
pos = self.paraEdit.mapToParent(self.paraEdit.pos())
painter = QPainter(self) painter = QPainter(self)
brush = QBrush() brush = QBrush()
brush.setColor(QColor("green")) brush.setColor(QColor("green"))
brush.setStyle(Qt.BrushStyle.SolidPattern) brush.setStyle(Qt.BrushStyle.SolidPattern)
path = QPainterPath() path = QPainterPath()
path.moveTo(0, 0) path.moveTo(0, 0)
path.lineTo(pos.x() - 1.0, pos.y() / 2.0) path.lineTo(18, -rect.height() / 2.0)
path.lineTo(0, pos.y()) path.lineTo(0, -rect.height())
path.lineTo(0, 0) path.lineTo(0, 0)
# XXX - Replace the guess with a calculated value painter.translate(1.0, c_pt.y())
painter.translate(1.0, pos.y() + rect.y() + 12)
painter.fillPath(path, brush) painter.fillPath(path, brush)
@pyqtSlot() @pyqtSlot()
@@ -132,6 +219,9 @@ class EditDialog(QDialog, Ui_Dialog):
@pyqtSlot() @pyqtSlot()
def defineAction(self) -> None: def defineAction(self) -> None:
#
# Find the word
#
cursor = self.paraEdit.textCursor() cursor = self.paraEdit.textCursor()
word = cursor.selectedText() word = cursor.selectedText()
start = cursor.selectionStart() start = cursor.selectionStart()
@@ -144,41 +234,54 @@ class EditDialog(QDialog, Ui_Dialog):
tmp = start tmp = start
start = end start = end
end = tmp end = tmp
#
# Find the block
#
textBlock = self.paraEdit.document().findBlock(cursor.position())
blockNum = textBlock.blockNumber()
query = QSqlQuery() query = QSqlQuery()
query.prepare("SELECT * FROM words WHERE word = :word") query.prepare("SELECT * FROM words WHERE word = :word")
query.bindValue(":word", word) query.bindValue(":word", word)
if not query.exec(): if not query.exec():
query_error(query) query_error(query)
if query.next(): # we have something if query.next(): # we have something
self.defined(query.value("word_id"), start, end) self.defined(query.value("word_id"), blockNum, start, end)
return return
dictionary = PyDictionary() #
meaning = json.dumps(dictionary.meaning(word)) # Get the defintion
por = dictionary.translate(word, "pt") #
response = requests.get(
f"https://api.dictionaryapi.dev/api/v2/entries/en/{word}"
)
if response.status_code != 200:
print(response.content)
return
definitions = json.loads(response.content.decode("utf-8"))
definition = definitions[0]
query.prepare( query.prepare(
"INSERT INTO words (word, definition, translation) " "INSERT INTO words (word, definition) " "VALUES (:word, :definition)"
"VALUES (:word, :definition, :translation)"
) )
query.bindValue(":word", word) query.bindValue(":word", word)
query.bindValue(":definition", meaning) query.bindValue(":definition", json.dumps(definition))
query.bindValue(":translation", por)
if not query.exec(): if not query.exec():
query_error(query) query_error(query)
self.defined(query.lastInsertId(), start, end) start = start - textBlock.position()
end = end - textBlock.position()
self.defined(query.lastInsertId(), blockNum, start, end)
return return
def defined(self, word_id: int, start: int, end: int) -> None: def defined(self, word_id: int, blockNum: int, start: int, end: int) -> None:
query = QSqlQuery() query = QSqlQuery()
query.prepare( query.prepare(
"SELECT * FROM word_paragraph " "SELECT * FROM word_block "
"WHERE word_id = :word_id " "WHERE section_id = :section_id "
"AND paragraph_id = :paragraph_id " "AND block = :block "
"AND start = :start " "AND start = :start "
"AND end = :end" "AND end = :end"
) )
query.bindValue(":word_id", word_id) query.bindValue(":word_id", word_id)
query.bindValue(":paragraph_id", self.paragraph_id) query.bindValue(":section_id", self.section_id)
query.bindValue(":block", blockNum)
query.bindValue(":start", start) query.bindValue(":start", start)
query.bindValue(":end", end) query.bindValue(":end", end)
if not query.exec(): if not query.exec():
@@ -186,11 +289,12 @@ class EditDialog(QDialog, Ui_Dialog):
if query.next(): if query.next():
return return
query.prepare( query.prepare(
"INSERT INTO word_paragraph VALUES " "INSERT INTO word_block VALUES "
"( :word_id, :paragraph_id, :start, :end)" "( :word_id, :section_id, :block, :start, :end)"
) )
query.bindValue(":word_id", word_id) query.bindValue(":word_id", word_id)
query.bindValue(":paragraph_id", self.paragraph_id) query.bindValue(":section_id", self.section_id)
query.bindValue(":block", blockNum)
query.bindValue(":start", start) query.bindValue(":start", start)
query.bindValue(":end", end) query.bindValue(":end", end)
if not query.exec(): if not query.exec():
@@ -198,24 +302,29 @@ class EditDialog(QDialog, Ui_Dialog):
def_format = QTextCharFormat() def_format = QTextCharFormat()
def_format.setFontUnderline(True) def_format.setFontUnderline(True)
cursor = QTextCursor(self.paraEdit.document()) cursor = QTextCursor(self.paraEdit.document())
cursor.setPosition(start, QTextCursor.MoveMode.MoveAnchor) textBlock = self.paraEdit.document().findBlockByNumber(blockNum)
cursor.setPosition(end, QTextCursor.MoveMode.KeepAnchor) cursor.setPosition(
start + textBlock.position(), QTextCursor.MoveMode.MoveAnchor
)
cursor.setPosition(end + textBlock.position(), QTextCursor.MoveMode.KeepAnchor)
cursor.setCharFormat(def_format) cursor.setCharFormat(def_format)
return return
def display_definition(self) -> None: def display_definition(self) -> None:
cursor = self.paraEdit.textCursor() cursor = self.paraEdit.textCursor()
textBlock = self.paraEdit.document().findBlock(cursor.position())
blockNum = textBlock.blockNumber()
query = QSqlQuery() query = QSqlQuery()
query.prepare( query.prepare(
"SELECT w.* FROM word_paragraph wp " "SELECT w.* FROM word_block wb "
"LEFT JOIN words w " "LEFT JOIN words w "
"ON (w.word_id = wp.word_id) " "ON (w.word_id = wb.word_id) "
"WHERE :position BETWEEN wp.start AND wp.end " "WHERE :position BETWEEN wb.start AND wb.end "
"AND wp.paragraph_id = :paragraph_id" "AND wb.block = :block AND wb.section_id = :section_id"
) )
query.bindValue(":position", cursor.position()) query.bindValue(":position", cursor.position() - textBlock.position())
query.bindValue(":paragraph_id", self.paragraph_id) query.bindValue(":block", blockNum)
print("display_definition()", cursor.position()) query.bindValue(":section_id", self.section_id)
if not query.exec(): if not query.exec():
query_error(query) query_error(query)
if not query.next(): if not query.next():
@@ -237,15 +346,22 @@ class EditDialog(QDialog, Ui_Dialog):
word_format.setFontWeight(QFont.Weight.Normal) word_format.setFontWeight(QFont.Weight.Normal)
word_format.setFontPointSize(16) word_format.setFontPointSize(16)
cursor.setCharFormat(word_format) cursor.setCharFormat(word_format)
for key in definition.keys(): try:
cursor.insertBlock()
cursor.insertText(definition["phonetic"])
except Exception:
pass
for meaning in definition["meanings"]:
cursor.insertList(typeFormat) cursor.insertList(typeFormat)
cursor.insertText(key) cursor.insertText(meaning["partOfSpeech"])
cursor.insertList(defFormat) cursor.insertList(defFormat)
first = True first = True
for a_def in definition[key]: for a_def in meaning["definitions"]:
if not first: if not first:
cursor.insertBlock() cursor.insertBlock()
cursor.insertText(a_def) cursor.insertText(a_def["definition"])
# TODO: synonyms
# TODO: antonyms
first = False first = False
return return
@@ -257,12 +373,13 @@ class EditDialog(QDialog, Ui_Dialog):
self.stackedWidget.setCurrentIndex(1 - idx) self.stackedWidget.setCurrentIndex(1 - idx)
return return
def nextDefinition(self): def nextDefinition(self) -> None:
cursor = self.paraEdit.textCursor() cursor = self.paraEdit.textCursor()
position = cursor.position() position = cursor.position()
print(position) block = cursor.block()
formats = cursor.block().textFormats()
found = None found = None
while block and not found:
formats = block.textFormats()
for f in formats: for f in formats:
wc = QTextCursor(cursor) wc = QTextCursor(cursor)
wc.setPosition(f.start) wc.setPosition(f.start)
@@ -284,14 +401,14 @@ class EditDialog(QDialog, Ui_Dialog):
if found: if found:
cursor.setPosition(found.start) cursor.setPosition(found.start)
self.paraEdit.setTextCursor(cursor) self.paraEdit.setTextCursor(cursor)
block = block.next()
self.display_definition() self.display_definition()
return return
def scrollTo(self, position): def scrollTo(self, position: int) -> None:
cursor = self.paraEdit.textCursor() cursor = self.paraEdit.textCursor()
cursor.setPosition(position) cursor.setPosition(position)
rect = self.paraEdit.cursorRect(cursor) rect = self.paraEdit.cursorRect(cursor)
print(rect)
return return
def savePosition(self) -> None: def savePosition(self) -> None:

16
main.py
View File

@@ -2,6 +2,7 @@
import os import os
import re import re
import sys import sys
from typing import cast
from PyQt6.QtCore import Qt, pyqtSlot from PyQt6.QtCore import Qt, pyqtSlot
from PyQt6.QtGui import ( from PyQt6.QtGui import (
@@ -42,15 +43,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
model.setQuery(query) model.setQuery(query)
self.peopleView.setModel(model) self.peopleView.setModel(model)
self.peopleView.setModelColumn(1) self.peopleView.setModelColumn(1)
# self.load_definition(word, PyDictionary.meaning(word))
# self.wordButton.clicked.connect(self.wordAction)
self.ReadButton.clicked.connect(self.readAction) self.ReadButton.clicked.connect(self.readAction)
self.bookBtn.clicked.connect(self.bookAction) self.bookBtn.clicked.connect(self.bookAction)
self.createActions() self.createActions()
self.show() self.show()
return return
def createActions(self): def createActions(self) -> None:
query = QSqlQuery() query = QSqlQuery()
query.prepare("SELECT * FROM books ORDER BY title") query.prepare("SELECT * FROM books ORDER BY title")
if not query.exec(): if not query.exec():
@@ -63,11 +62,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
return return
@pyqtSlot() @pyqtSlot()
def setBookAction(self): def setBookAction(self) -> None:
action = self.sender() action = cast(QAction, self.sender())
print(action)
book_id = action.data() book_id = action.data()
print(book_id)
indexes = self.peopleView.selectedIndexes() indexes = self.peopleView.selectedIndexes()
if len(indexes) < 1: if len(indexes) < 1:
return return
@@ -164,8 +161,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
SQL_CMDS = [ SQL_CMDS = [
"PRAGMA foreign_keys=ON", "PRAGMA foreign_keys=ON",
"CREATE TABLE IF NOT EXISTS words " "CREATE TABLE IF NOT EXISTS words "
"(word_id INTEGER PRIMARY KEY AUTOINCREMENT, word TEXT, definition TEXT, " "(word_id INTEGER PRIMARY KEY AUTOINCREMENT, word TEXT, definition TEXT)",
"translation TEXT)",
"CREATE TABLE IF NOT EXISTS books " "CREATE TABLE IF NOT EXISTS books "
"(book_id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, author TEXT, " "(book_id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, author TEXT, "
"uuid TEXT, level INTEGER)", "uuid TEXT, level INTEGER)",
@@ -236,7 +232,7 @@ def schema_update(db: QSqlDatabase) -> None:
if not query.exec(matches.group(1) + new_table_name + matches.group(3)): if not query.exec(matches.group(1) + new_table_name + matches.group(3)):
query_error(query) query_error(query)
# step 5 transfer content # step 5 transfer content
coldefs = re.search(r"\((.+)\)", old).group(1).split(", ") coldefs = re.search(r"\((.+)\)", old).group(1).split(", ") # type: ignore[union-attr]
cols = [x.split(" ")[0] for x in coldefs] cols = [x.split(" ")[0] for x in coldefs]
if not query.exec( if not query.exec(
"INSERT INTO " "INSERT INTO "

View File

@@ -24,7 +24,7 @@ class Ui_Dialog(object):
self.paraEdit = QtWidgets.QTextEdit(parent=self.page) self.paraEdit = QtWidgets.QTextEdit(parent=self.page)
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("OpenDyslexic") font.setFamily("OpenDyslexic")
font.setPointSize(16) font.setPointSize(11)
self.paraEdit.setFont(font) self.paraEdit.setFont(font)
self.paraEdit.setObjectName("paraEdit") self.paraEdit.setObjectName("paraEdit")
self.verticalLayout_2.addWidget(self.paraEdit) self.verticalLayout_2.addWidget(self.paraEdit)

View File

@@ -26,7 +26,7 @@
<property name="font"> <property name="font">
<font> <font>
<family>OpenDyslexic</family> <family>OpenDyslexic</family>
<pointsize>16</pointsize> <pointsize>11</pointsize>
</font> </font>
</property> </property>
</widget> </widget>