Skip to content

Commit

Permalink
add Words Recorder code & README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
Tich committed Jul 16, 2018
1 parent 2294113 commit 8ba56f2
Show file tree
Hide file tree
Showing 8 changed files with 337 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A set of special tools to cope with my daily tasks. It's based on [Python 3.6.5]

### Words Recorder

Words Recorder is an app to record the word that you are unfamiliar with when you do some reading, based on Python, PyQt5 and MySQL.
[Words Recorder](words-recorder) is an app to record the word that you are unfamiliar with when you do some reading, based on Python, PyQt5 and MySQL.

<div align="center">
<img src="images/Words-Recorder.png" alt="Words Recorder" height="350" />
Expand Down
Binary file added images/Words-Recorder-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 66 additions & 0 deletions words-recorder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<img src="../images/Words-Recorder-icon.png" alt="logo" align="right" />

## Words Recorder

Words Recorder is an app to record the word that you are unfamiliar with when you do some reading, based on Python, PyQt5 and MySQL.

### screenshot

<div align="center">
<img src="../images/Words-Recorder.png" alt="Words Recorder" height="350" />
</div>

### Installation
First, clone the repo and install the required packages.
```
>> git clone https://github.com/LewisTian/PyQt5-tools.git
>> cd PyQt5-tools/words-recorder
>> pip install -r requirements.txt
```
Next, create a MySQL table like 'mysql.sql', and config the 'setting.ini'. The 'path' below must be matched with the 'secure_file_priv' in the 'my.ini'(Windows) / 'mysqld.cnf'(Linux).
```
# setting.ini
[MySQL]
host = localhost
user = root
password =
db =
port = 3306
charset = utf8
path =
```
Finally, you can run the app.
```
>> python main.py
```

### Usage
Note that you should connect to the database first.

#### import
You can import data via a file, and the rules of the file format are as follows
- original word and translation are splitted by blanks or tabs.
- phrase and expression should be joined by '-' or '\_' instead of blanks.
- a blank line in the last.

#### export
Export data as a '.csv' file.

#### insert
Put original word and translation in the corresponding input field, then click the 'insert' button or press 'Ctrl+Return'.

#### query
Put original word in the 'origin' input field, then click the 'query' button or press 'Ctrl+Q'.

#### update
You can modify the data in the table('id' column is not permitted), then click the 'update' button or press 'Ctrl+U'.
**You can modify multiple lines of data at once.**

#### delete
Click the 'delete' button or press 'Ctrl+D'. You can delete multiple lines at once.

### style sheet
You can write your own style sheet named 'style.qss' in the 'PyQt5-tools/words-recorder' directory.

### License
GNU General Public License v3.0
Binary file added words-recorder/icon.ico
Binary file not shown.
252 changes: 252 additions & 0 deletions words-recorder/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2018-07-13 15:24:23
# @Author : Lewis Tian ([email protected] | [email protected])
# @Link : https://lewistian.github.io/
# @Version : Python3.6

from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow, QMessageBox, QFileDialog, QTableWidgetItem
from PyQt5.QtCore import QCoreApplication, QTimer, QDateTime, Qt
from mwin import Ui_MWin
import sys
import re
import pymysql
from configparser import ConfigParser

# global val
status = "logged in: %s, lasted: %s."
db = None
cursor = None
outSql = """
SELECT * FROM words INTO OUTFILE '%s' FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\r\n';
"""
inSql = """
INSERT INTO words(origin, trans) VALUES (%s, %s);
"""

class MainWindow(QMainWindow):
def closeEvent(self, event):
if db:
db.close()

def messageBox(self, showInfo):
""":author : Tich
show information."""
box = QMessageBox.about(self, 'Words Recoder 1.0', showInfo)

def importData(self, w):
""":author : Tich
import data via file.
the file consists of two columns,
one for words and one for translation
there is a '\n' in the last line
"""
if db:
filename, filetype = QFileDialog.getOpenFileName(None, 'Open File', '.')
data = []
if filename:
print(filename)
with open(filename, encoding = 'utf-8') as f:
for x in f:
words = re.split(r'\s+', x[:-1])
if len(words) == 2:
data.append(words)
print(data)
try:
flag = cursor.executemany(inSql, data)
if flag:
db.commit()
self.messageBox("data has been imported!")
self.updateTable(w)
except Exception as e:
db.rollback()
self.messageBox("import data failed!\nerror msg: %s"%(e.args[1]))
else:
self.messageBox("connect to the database first!\nclick the button 'File-connect'")

def exportDataAsCSV(self):
# filename, filetype = QtWidgets.QFileDialog.getSaveFileName(None, 'Save File', '.', "All Files (*);;Text Files (*.txt)")
if db:
filename, filetype = QFileDialog.getSaveFileName(None, 'Save File', self.outPath, "CSV Files (*.csv)")
if filename:
print(filename)
try:
num = cursor.execute(outSql % filename)
if num:
# self.messageBox("data has been exported as %s", % (filename) )
self.messageBox("data has been exported as %s!" % filename)
except Exception as e:
self.messageBox("export data failed!\nerror msg: %s"%(e.args[1]))
else:
self.messageBox("connect to the database first!\nclick the button 'File-connect'")

def connectDatabase(self, w):
""":author : Tich
connect to database
:param w: used for data update in `w.table`
"""
global db, cursor
if db:
return
config = ConfigParser()
conf = {}
try:
config.readfp(open('setting.ini'))
head = ['host', 'user', 'password', 'db', 'port', 'charset', 'path']
for x in head:
conf[x] = config.get("MySQL", x)
self.outPath = conf['path']
except:
self.messageBox("config the 'setting.ini' file first!")
return
try:
# print(conf)
# db = pymysql.connect(conf)
db = pymysql.connect(host=conf['host'],user=conf['user'],password=conf['password'],
db=conf['db'],port=int(conf['port']), charset=conf['charset'])
cursor = db.cursor()
self.messageBox("connected to the database!\nthe table will be updated.")
except Exception as e:
self.messageBox("database connect error!\nerror msg: %s.\
\n===\nplease check your databse setting \nand restart the app."%(e.args[1]))
return
# update data once connecting to the database
self.updateTable(w)

def updateTable(self, w):
""":author : Tich
update data in the table
:param w: update data in `w.table`
"""
try:
num = cursor.execute("SELECT * FROM words ORDER BY origin;")
if num:
w.table.setRowCount(num)
for r in cursor:
# print(r)
i = cursor.rownumber - 1
for x in range(3):
item = QTableWidgetItem(str(r[x]))
item.setTextAlignment(Qt.AlignCenter);
w.table.setItem(i, x, item)
except Exception as e:
# print(e)
self.messageBox("update table error!\nerror msg: %s"%e.args[1])

def insert(self, w):
origin = w.input_origin.text().replace(' ', '')
trans = w.input_trans.text().replace(' ', '')
if origin and trans:
if db:
try:
sql = "INSERT INTO words(origin, trans) VALUES ('%s', '%s');" %(origin, trans)
print(sql)
num = cursor.execute(sql)
if num:
db.commit()
# self.messageBox("data has been inserted!")
self.updateTable(w)
except Exception as e:
db.rollback()
self.messageBox("insert data failed!\nerror msg: %s"%(e.args[1]))
else:
self.messageBox("connect to the database first!\nclick the button 'File-connect'")

def query(self, w):
origin = w.input_origin.text().replace(' ', '')
if origin:
if db:
try:
sql = "SELECT origin, trans FROM words WHERE origin = '%s'" % origin
print(sql)
num = cursor.execute(sql)
if num:
for r in cursor:
w.input_trans.setText(r[1])
# self.messageBox("%s: %s"%(r))
except Exception as e:
self.messageBox("insert data failed!\nerror msg: %s"%(e.args[1]))
else:
self.messageBox("connect to the database first!\nclick the button 'File-connect'")

def update(self, w):
flag = False
if db:
for x in w.table.selectedIndexes():
sql = "update words set origin='%s', trans='%s' where id=%s;"
print(w.table.item(x.row(), 1).text())
num = cursor.execute(sql%(w.table.item(x.row(), 1).text(), w.table.item(x.row(), 2).text(), w.table.item(x.row(), 0).text()))
if num:
flag = True
db.commit()
else:
pass
# print(x.row())
# w.table.item(i,j)
if flag:
self.updateTable(w)
else:
self.messageBox("connect to the database first!\nclick the button 'File-connect'")

def delete(self, w):
flag = False
if db:
for x in w.table.selectedIndexes():
sql = "delete from words where Id = '%s';"
num = cursor.execute(sql % w.table.item(x.row(), 0).text())
if num:
flag = True
db.commit()
else:
pass
if flag:
self.updateTable(w)
else:
self.messageBox("connect to the database first!\nclick the button 'File-connect'")

def connectSlots(base, w):
""":author : Tich
connect w with base slots
"""
# close event
w.actionexit.triggered.connect(base.close)
# about
w.actionabout.triggered.connect(lambda: base.messageBox("Words Recoder 1.0: Recod unknown words into the MySQL database."))
# heko
w.actionhelp.triggered.connect(lambda: base.messageBox("1.click 'File - connect' to connect MySQL.\
\n2. click button 'insert' to insert new word. \
\n3. click button 'query' to query word."))
# import data via file
w.actionimport.triggered.connect(lambda: base.importData(w))
# export data as .csv file
w.actionexport.triggered.connect(base.exportDataAsCSV)
# connect to MySQL
w.actionconnect.triggered.connect(lambda: base.connectDatabase(w))

w.insert.clicked.connect(lambda: base.insert(w))
w.insert.setShortcut('Ctrl+Return')

w.query.clicked.connect(lambda: base.query(w))
w.query.setShortcut('Ctrl+Q')

w.update.clicked.connect(lambda: base.update(w))
w.update.setShortcut('Ctrl+U')

w.delet.clicked.connect(lambda: base.delete(w))
w.delet.setShortcut('Ctrl+D')

if __name__ == '__main__':
app = QApplication(sys.argv)
base = MainWindow() # create base window
try:
with open('style.qss') as f:
style = f.read() # 读取样式表
base.setStyleSheet(style)
except:
print("open stylesheet error")
w = Ui_MWin() # create user ubterface instance
w.setupUi(base) # load w into base window
w.table.setColumnWidth(0, 40)
connectSlots(base, w)
base.show() # show base window
sys.exit(app.exec_())
7 changes: 7 additions & 0 deletions words-recorder/mysql.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
DROP TABLE IF EXISTS `words`;
CREATE TABLE `words` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`origin` varchar(50) DEFAULT NULL,
`trans` varchar(300) DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3 changes: 3 additions & 0 deletions words-recorder/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
PyQt5
pymysql
configparser
8 changes: 8 additions & 0 deletions words-recorder/setting.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[MySQL]
host = localhost
user = root
password =
db =
port = 3306
charset = utf8
path =

0 comments on commit 8ba56f2

Please sign in to comment.