用 pyqt4 编写的一个翻译小工具
有时候我们在开发时遇到一些陌生的英文单词或者不容易看出某些长句的中文意思时该怎么办呢?打开桌面上的翻译软件?打开浏览器里收藏着的翻译网址或者直接贴上百度的搜索框去查?这些方法固然可以,还很常见,但如果是 linux 系统的话,很难找到像 windows 上那些公司级别来开发的成熟的翻译软件,所以只能打开浏览器来查了。浏览器一般都会装上一些翻译插件,比如我常用的 chrome 的 划词翻译,直接用这些插件来进行翻译比起打开一个翻译网站或者百度google搜索要更快,毕竟因为加载的内容更少,但这终究只是浏览器的插件,在浏览网页时用还方便,对于在其它软件上看到的陌生单词如果也放到这儿来查的话多少就感到有些转折了,所以少数的软件也会有相应的翻译插件,像优秀的编辑器 sublime text 等,就有人专门写了一个翻译的插件,可是像这类有翻译插件的软件毕竟还是极少数,如果用其它编辑器或 IDE 来开发的话也自己写一个翻译插件的话就太折腾了(我之前用 codeblocks 来看代码时遇到不懂的单词也想着能不能自行开发一个翻译插件,上网搜了一下发现开发 codeblocks 的插件需要的技术挺偏的,而且也不容易;有时经常在终端上 man 一个不熟悉的命令时也会遇到很多不懂的英文单词,此时为终端加一个翻译插件感觉就不太现实了吧)。
所以,我前几天时就在想,能不能开发一个全局的翻译插件呢?也就是在使用电脑上所有软件时都能很方便调用这个插件去获取翻译的结果,因为我大多数时间是在使用 ubuntu,ubuntu 的任务栏默认是位于电脑的上方的,感觉看着很显眼,鼠标触及也方便,所以想就把这个插件放到任务栏上吧,这样子不管是在用 codeblocks / eclipse等 IDE 来进行开发,或者在使用终端进行各种命令的操作时,或者直接是在看网页(用不同的浏览器)等等,都能通过点击任务栏的小图标就能立即进行翻译了。
我一开始的设计思想就是为了用最少的操作(也就是最少的鼠标点击次数或者键盘打字数目)来达到目的,所以我的这个全局插件的翻译原理是这样的:用 pyqt 构建好的 GUI 程序在后台运行,任务栏上显示,每当点击它在任务栏上的图标菜单里的翻译按钮时,程序会获取剪切版里的内容,然后把这些内容通过有道翻译的API得到翻译的 json 格式的结果,然后把 json 格式的结果处理一下,最后通过弹窗显示或者系统气泡消息的方式展现出来。因为我用的终端是 terminator,能设置成鼠标划过的文本直接进入剪切板,所以当我想要翻译一句英文时,只需要用鼠标选择好这些文本,然后再点击任务栏图标的翻译按钮就能直接能到结果,整个过程不过两次点击鼠标的时间,无须用到键盘,比起用浏览器来查,可以说是大大节省了时间,能显著地提高日常学习/开发的效率。好了,废话不多说了,先放上一张效果图:
(我能说这个图非常难截么?因为用不了截图软件来截图(鼠标一点击截图软件时任务栏图标的菜单列表就会立刻消失),所以只能用键盘的截图键来截整个屏幕的图,然后再裁剪图片,可是在 ubuntu 下截取瞬间会有闪现的效果,导致这个菜单栏变得很模糊,所以我只能先换一张几乎是纯黑色的桌面背景,然后裁剪好后再作亮度调整等处理,先将就着看一下哦~)
完整代码如下:
#!/usr/bin/env python
# coding: utf-8 from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
import requests
# import redis
import json class SystemTray(QMainWindow):
"""My SystemTray, includes translator and functions of getting commands quickly.""" YDERRORCODE = {
0: u'正常',
20: u'要翻译的文本过长',
30: u'无法进行有效的翻译',
40: u'不支持的语言类型',
50: u'无效的key',
60: u'无词典结果,仅在获取词典结果生效'
} def __init__(self, title="SystemTray", size=[600, 500]):
super(SystemTray, self).__init__()
self.initSelf(title, size)
self.initUI() def initSelf(self, title, size):
self.setWindowTitle(title)
self.setWindowIcon(QIcon('./images/window_icon.jpg'))
self.resize(size[0], size[1])
self.showOnCenter() self.clipboard = QApplication.clipboard()
self.translateUrl = "http://fanyi.youdao.com/openapi.do?keyfrom=myname&key=xxx&type=data&doctype=json&version=1.1&q=" def initUI(self):
self.initBoard()
self.statusbar = self.statusBar()
self.initAction()
self.initTrayIcon() def initBoard(self):
board = QWidget()
mainLayout = QVBoxLayout() gbox = QGroupBox(u'翻译设置')
grid = QGridLayout()
self.cbImmediatelyTranslate = QCheckBox(u'翻译剪切板中的内容')
self.cbImmediatelyTranslate.setChecked(True)
self.cbImmediatelyTranslate.stateChanged.connect(self.translateOption)
grid.addWidget(self.cbImmediatelyTranslate, 0, 0, 1, 2)
label = QLabel(u'字数限制:')
label.setAlignment(Qt.AlignRight)
grid.addWidget(label, 0, 3)
self.sbWordLimit = QSpinBox()
self.sbWordLimit.setRange(1, 800)
self.sbWordLimit.setValue(200)
self.sbWordLimit.valueChanged.connect(lambda x: self.slotWordLimitChange(self.sbWordLimit.value()))
grid.addWidget(self.sbWordLimit, 0, 4) self.label_1 = QLabel(u'输入要翻译的文本:')
grid.addWidget(self.label_1, 1, 0)
self.textTranslate = QTextEdit()
grid.addWidget(self.textTranslate, 2, 0, 3, 6)
self.btnTranslate = QPushButton(u'翻译')
self.btnTranslate.clicked.connect(self.btnClicked)
grid.addWidget(self.btnTranslate, 6, 5)
self.label_1.hide()
self.textTranslate.hide()
self.btnTranslate.hide() label = QLabel(u'显示方式:')
label.setAlignment(Qt.AlignRight)
grid.addWidget(label, 6, 0)
self.cbbTranslateShowType = QComboBox()
self.cbbTranslateShowType.addItem(QIcon(u'./images/messagebox.png'), u'弹窗显示')
self.cbbTranslateShowType.addItem(self.style().standardIcon(QStyle.SP_MessageBoxInformation), u'系统通知')
self.cbbTranslateShowType.currentIndexChanged.connect(lambda x: self.slotShowTypeChange(self.cbbTranslateShowType.currentIndex()))
grid.addWidget(self.cbbTranslateShowType, 6, 1) self.cbShowTranslateDeatil = QCheckBox(u'显示详细的翻译结果')
self.cbShowTranslateDeatil.clicked.connect(lambda x: self.slotShowDetailChange(self.cbShowTranslateDeatil.isChecked()))
self.cbShowTranslateDeatil.setChecked(True)
grid.addWidget(self.cbShowTranslateDeatil, 6, 3) grid.setColumnStretch(1, 1)
grid.setColumnStretch(2, 1)
grid.setColumnStretch(4, 1)
grid.setColumnStretch(5, 1)
gbox.setLayout(grid)
mainLayout.addWidget(gbox) gbox = QGroupBox(u'快速复制命令到剪切板')
grid = QGridLayout()
label = QLabel(u'历史命令(history):')
grid.addWidget(label, 0, 0)
self.cbbHistoryCommands = QComboBox()
grid.addWidget(self.cbbHistoryCommands, 1, 0)
gbox.setLayout(grid)
mainLayout.addWidget(gbox) mainLayout.addStretch(1)
board.setLayout(mainLayout)
self.setCentralWidget(board) def slotShowTypeChange(self, index):
self.cbbTranslateShowType.setCurrentIndex(index)
if index == 0:
self.actMessagebox.setChecked(True)
else:
self.actSystemMessage.setChecked(True) def slotShowDetailChange(self, bShowDeatil):
if bShowDeatil == True:
self.actShowDetail.setChecked(True)
self.cbShowTranslateDeatil.setChecked(True)
else:
self.actShowDetail.setChecked(False)
self.cbShowTranslateDeatil.setChecked(False) def slotWordLimitChange(self, wordLen):
if wordLen in [100, 200, 400]:
self.sbWordLimit.setValue(wordLen)
if wordLen == 100:
self.actWordLimit_1.setChecked(True)
elif wordLen == 200:
self.actWordLimit_2.setChecked(True)
elif wordLen == 400:
self.actWordLimit_3.setChecked(True)
else:
self.actWordLimit_4.setChecked(True)
self.actWordLimit_4.setText(('其它(' + str(wordLen) + ')').decode('utf8'))
self.show() def initAction(self):
self.actTranslate = QAction(QIcon('./images/youdao.jpg'), u'立即翻译', self)
self.actTranslate.setShortcut('ctrl+alt+f')
self.actTranslate.triggered.connect(self.translate_clipboard) menuShowType = QMenu(u'显示方式', self)
ag = QActionGroup(self, exclusive=True)
self.actMessagebox = QAction(QIcon(u'./images/messagebox.png'), u'弹窗显示', menuShowType, checkable=True)
self.actMessagebox.triggered.connect(lambda x: self.slotShowTypeChange(0))
self.actMessagebox.setChecked(True)
self.actSystemMessage = QAction(self.style().standardIcon(QStyle.SP_MessageBoxInformation), u'系统通知', menuShowType, checkable=True)
self.actSystemMessage.triggered.connect(lambda x: self.slotShowTypeChange(1))
menuShowType.addActions([ag.addAction(self.actMessagebox), ag.addAction(self.actSystemMessage)]) menuTranslateOption = QMenu(u'翻译设置', self)
menuTranslateOption.setIcon(QIcon(u'./images/config.png'))
self.actShowDetail = QAction(u'显示详细结果', menuTranslateOption, checkable=True)
self.actShowDetail.triggered.connect(lambda x: self.slotShowDetailChange(self.actShowDetail.isChecked()))
self.actShowDetail.setChecked(True) menuWordLimit = QMenu(u'字数限制', self)
ag = QActionGroup(self, exclusive=True)
self.actWordLimit_1 = QAction(u'', menuWordLimit, checkable=True)
self.actWordLimit_1.triggered.connect(lambda x: self.slotWordLimitChange(100))
self.actWordLimit_2 = QAction(u'', menuWordLimit, checkable=True)
self.actWordLimit_2.triggered.connect(lambda x: self.slotWordLimitChange(200))
self.actWordLimit_2.setChecked(True)
self.actWordLimit_3 = QAction(u'', menuWordLimit, checkable=True)
self.actWordLimit_3.triggered.connect(lambda x: self.slotWordLimitChange(400))
self.actWordLimit_4 = QAction(u'其它', menuWordLimit, checkable=True)
self.actWordLimit_4.triggered.connect(lambda x: self.slotWordLimitChange(1))
menuWordLimit.addActions([ag.addAction(self.actWordLimit_1), ag.addAction(self.actWordLimit_2), ag.addAction(self.actWordLimit_3), ag.addAction(self.actWordLimit_4)]) menubar = self.menuBar()
menuTranslate = menubar.addMenu(u'翻译')
menuTranslate.addAction(self.actTranslate)
menuTranslateOption.addMenu(menuShowType)
menuTranslateOption.addAction(self.actShowDetail)
menuTranslateOption.addMenu(menuWordLimit)
menuTranslate.addMenu(menuTranslateOption) commandsMenu = menubar.addMenu(u'commands设置') def initTrayIcon(self):
menuTrayIcon = QMenu(self)
menuTrayIcon.addAction(self.actTranslate) menuTranslateOption = QMenu(u'翻译设置', self)
menuTranslateOption.setIcon(QIcon(u'./images/config.png'))
menuShowType = QMenu(u'显示方式', self)
menuShowType.addActions([self.actMessagebox, self.actSystemMessage])
menuTranslateOption.addMenu(menuShowType)
menuTranslateOption.addAction(self.actShowDetail)
menuWordLimit = QMenu(u'字数限制', self)
menuWordLimit.addActions([self.actWordLimit_1, self.actWordLimit_2, self.actWordLimit_3, self.actWordLimit_4])
menuTranslateOption.addMenu(menuWordLimit) menuTrayIcon.addMenu(menuTranslateOption)
# menuTrayIcon.addAction(QAction("Minimize", self, triggered=self.showMinimized))
menuTrayIcon.addSeparator()
menuTrayIcon.addAction(QAction(QIcon('./images/qt.png'), u"打开主面板", self, triggered=self.showNormal))
menuTrayIcon.addAction(QAction(QIcon('./images/quit.png'), u"退出", self, triggered=qApp.quit)) self.trayIcon = QSystemTrayIcon(QIcon('./images/tray_icon.jpg'), self)
self.trayIcon.setContextMenu(menuTrayIcon)
self.trayIcon.show() def btnClicked(self):
self.translateText(self.textTranslate.toPlainText()) def translateOption(self):
if self.cbImmediatelyTranslate.isChecked():
self.label_1.hide()
self.textTranslate.hide()
self.btnTranslate.hide()
else:
self.label_1.show()
self.textTranslate.show()
self.btnTranslate.show() def translate(self, text):
if len(text) > self.sbWordLimit.value():
return (1, u'翻译的文本长度超过字数限制!')
text = (str(text.toUtf8())).strip()
if text == '':
return (2, u'翻译的字符串中没有实际的字符(只包含空格/tab/换行等)')
req = self.translateUrl + text
r = requests.get(req)
if r.ok != True:
return (r.status_code, QString(u'网络错误,url请求失败'))
else:
u_dict = json.loads(r.text)
errorCode = u_dict['errorCode']
if errorCode != 0:
return (errorCode, QString(self.YDERRORCODE[errorCode]))
else:
res = QString(u'')
if u_dict.has_key('translation'):
res += u"<翻译>: "
for x in u_dict['translation']:
res = res + x + ", "
res = (
res[:-2] + "\n") if res[-2:] == ", " else (res + "\n")
if u_dict.has_key('basic'):
if u_dict['basic'].has_key('us-phonetic'):
res = res + u"<美式发音>: " + u_dict['basic']['us-phonetic'] + "\t"
if u_dict['basic'].has_key('uk-phonetic'):
res = res + u"<英式发音>: " + u_dict['basic']['uk-phonetic'] + "\n"
if u_dict['basic'].has_key('explains'):
res += u"<解释>: "
for x in u_dict['basic']['explains']:
res = res + x + ", "
res = (
res[:-2] + "\n") if res[-2:] == ", " else (res + "\n")
if self.cbShowTranslateDeatil.isChecked():
if u_dict.has_key('web'):
res += u"<网络用语>: \n"
for d in u_dict['web']:
if d.has_key('key'):
res = res + u" <关键词>: " + d['key'] + "\n"
if d.has_key('value'):
res = res + u" <意思>: "
for v in d['value']:
res = res + v + ", "
res = (
res[:-2] + "\n") if res[-2:] == ", " else (res + "\n")
return (errorCode, res) def translateText(self, text):
if type(text) == type(QString()):
text = text.simplified()
elif type(text) == str:
text = text.strip()
result = self.translate(text)
showType = self.cbbTranslateShowType.currentIndex()
if result[0] != 0:
title = QString(u'翻译出错')
self.showTranslateResult(title, result[1], QMessageBox.Warning)
else:
title = (text[0:20] + u'....' if len(text)
>= 20 else text) + u" 的翻译结果 "
self.showTranslateResult(title, result[1], QMessageBox.Information) def translate_clipboard(self):
clip_data = self.clipboard.mimeData()
if clip_data.hasText():
src = clip_data.text()
self.translateText(src)
else:
QMessageBox.information(self, u'提示', u'剪切板中的内容为空,无法翻译!') def showTranslateResult(self, title, content, icon):
showType = self.cbbTranslateShowType.currentIndex()
if showType == 0:
# 至关重要的一句,否则当关闭messagebox的窗口时,整个程序自动退出!
QApplication.setQuitOnLastWindowClosed(False)
QMessageBox(QMessageBox.Icon(icon), title, content).exec_()
elif showType == 1:
self.trayIcon.showMessage(title, content, QSystemTrayIcon.MessageIcon(icon))
else:
pass def showOnCenter(self):
screen = QDesktopWidget().screenGeometry()
self.move((screen.width() - self.width()) / 2,
(screen.height() - self.height()) / 2) def closeEvent(self, event):
if self.trayIcon.isVisible():
self.trayIcon.showMessage(u'隐藏', u'在任务栏按钮可打开主窗口', QSystemTrayIcon.MessageIcon(QMessageBox.Information), 1000)
self.hide()
event.ignore() if __name__ == '__main__':
app = QApplication(sys.argv)
tray = SystemTray()
# tray.show()
sys.exit(app.exec_())
只需要安装好 pyqt4 即可。代码写得有些乱,因为一开始就是为了快速达到目的,当复制好要翻译的英文时,再点击任务栏菜单立即翻译的按钮,就能看到翻译的结果了:
或者系统的气泡消息:
因为用到的外部库只有 pyqt4 一个,其它都是 python2.7 的标准库,而 pyqt4 在 windows 下能用 py2exe 打包成可执行程序,所以在windows下还是能用的,而且因为 qt 对 windows 平台的支持更好,所以我觉得在windows下的体验应该比 ubuntu 要更好一些。
附上代码中用到的图片下载地址:beautiful_icons
用 pyqt4 编写的一个翻译小工具的更多相关文章
- 基于百度通用翻译API的一个翻译小工具
前几天写了一个简单的翻译小工具,是基于有道翻译的,不过那个翻译接口有访问限制,超过一定次数后会提示访问过于频繁,偶然发现百度翻译API如果月翻译字符少于200万是不收取费用的,所以就注册了一个百度开发 ...
- (win环境)使用Electron打造一个桌面应用翻译小工具
初始化项目 npm init 修改package.json {"name": "trans","version": "1.0.0& ...
- C#借助谷歌翻译实现翻译小工具(一)基本功能实现
软件效果: 实现原理很简单,就是封装谷歌翻译网站:http://translate.google.cn/,一个WebBrowser"肢解"谷歌翻译网站的HtmlElement元素, ...
- 搭建Spring开发环境并编写第一个Spring小程序
搭建Spring开发环境并编写第一个Spring小程序 2015-05-27 0个评论 来源:茕夜 收藏 我要投稿 一.前面,我写了一篇Spring框架的基础知识文章,里面没 ...
- JDK9版本以上Java独有的一个轻量级小工具,你知道吗?jshell
jshell,是JavaJDK9这个大版本更新以来,带来的一个轻量级小工具.我们再也不用进入Java目录,编写一个Java文件,然后再去编译,最后才能执行它. 这里,你可以直接写一个小功能,就能去实现 ...
- 练习-99乘法表 token生成器 翻译小工具
一.99乘法表 1.1 技术点 记住: for 循环的使用,以及for的嵌套使用 range()的使用,掌握sep为负数的使用的使用. print() 函数的使用,默认的结尾的换行符 替换 end= ...
- 访问github太慢?我写了一个开源小工具一键变快
前言 GitHub应该是广大开发者最常去的站点,这里面有大量的优秀项目,是广大开发者寻找资源,交友学习的好地方.尤其是前段时间GitHub公布了一项代码存档计划--Arctic Code Vault, ...
- 调用百度API写了一个js翻译小工具
目前还未完成的功能有:textarea高度自适应,移动端与pc端都写了.效果如图: html: <!DOCTYPE html> <html lang="en"&g ...
- C#借助谷歌翻译实现翻译小工具(二)添加托盘图标
接上一节完善小翻译工具 设置Form的ShowInTaskbar属性为False,取消任务栏显示 设置Form的MaximizeBox属性为False,取消最大化显示 窗口添加两个控件 分别是:Con ...
随机推荐
- iis 更改asp.net 版本设置
参考来源: https://github.com/neo2018/ZYFC/blob/2e20009097c1e837a6e667a3dffd4224e28f4411/MderFc/Classes/I ...
- C语言的第二次实验报告
一.思路及方法 11-8 螺旋方阵 设计二维数组,通过对方阵的行和列进行特征分析找出其中规律,利用循环即可将方阵输出. 12-6 字符串转换成十进制整数 设计字符数组,用getchar函数逐个截取,并 ...
- Train-Alypay-Cloud:蚂蚁大数据平台培训开课通知(第三次)
ylbtech-Train-Alypay-Cloud:蚂蚁大数据平台培训开课通知(第三次) 1.返回顶部 1. 您好! 很高兴通知您,您已经成功报名将于蚂蚁金服计划在2018年2月28日- 2018年 ...
- 使用TensorFlow识别照片中的物体
1.环境ubuntu14.04.5 安装TensorFlow 官方文档:https://www.tensorflow.org/install/install_linux sudo pip instal ...
- Python实践练习:疯狂填词
题目 创建一个疯狂填词(Mad Libs)程序,它将读入文本文件,并让用户在该文本文件中出现 ADJECTIVE.NOUN.ADVERB 或 VERB 等单词的地方,加上他们自己的文本. 例如,一个文 ...
- [原创]Spring Boot + Mybatis 简易使用指南(一)基础环境搭建
前言 作者: Ant QQ:517377100 相对于使用JdbcTemplate,Mybatis可自动建立pojo类型与数据库列的映射关系,数据库访问层的开发简单了许多 所有数据库访问操作,均封装在 ...
- VLC播放RTSP视频延迟问题 (转)
原帖地址:http://blog.chinaunix.net/uid-26611383-id-3755283.html ======================================== ...
- MaskBlt 拷贝非矩形区域图象
MaskBlt 该函数使用特定的掩码和光栅操作来对源和目标位图的颜色数据进行组合. 原型: BOOL MaskBlt( HDC hdcDest, int nXDest, int nYDest ...
- java对象转json对象
org.java类 public class orgs { private String id; private String name; public String getId() { return ...
- Go Packages、Variables、functions
[Go Packages.Variables.functions] 1.定义包名. 2.引入Package. 3.定义导出的变量.首字母必须大写. 4.函数.Notice that the type ...