Stonelee's Blog

如无必要,勿增实体

使用热键控制python程序

分享到: 更多

需求

按一个热键,程序开始循环执行某项操作,按另一个热键,操作终止;可以如此反复。此需求广泛应用于自动脚本执行等工作。

技术点

  • 全局热键的绑定
  • 热键的阻塞问题

绑定多个全局热键时,如果一个热键执行的操作未停止,程序不会响应其他热键,因此我采用另外开启线程的方法解决。

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
#coding=utf-8
'''
Created on 2010-10-12
@author: lxd
'''
import wx
import win32con
import time
import threading

class WorkThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.timeToQuit = threading.Event()
        self.timeToQuit.clear()

    def stop(self):
        self.timeToQuit.set()

    def run(self):
        while True:
            if not self.timeToQuit.isSet():
                print 'work'
                time.sleep(1)
            else:
                break

class FrameWithHotKey(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)
        self.regHotKey()
        self.Bind(wx.EVT_HOTKEY, self.OnHotKeyStart, id=self.hotKeyId_start)
        self.Bind(wx.EVT_HOTKEY, self.OnHotKeyEnd, id=self.hotKeyId_end)
        self.Bind(wx.EVT_HOTKEY, self.OnHotKeyQuit, id=self.hotKeyId_quit)
        self.work = None

    def regHotKey(self):
        self.hotKeyId_start = 100
        self.RegisterHotKey(self.hotKeyId_start, win32con.MOD_ALT, win32con.VK_F1)
        self.hotKeyId_end = 101
        self.RegisterHotKey(self.hotKeyId_end, win32con.MOD_ALT, win32con.VK_F2)
        self.hotKeyId_quit = 102
        self.RegisterHotKey(self.hotKeyId_quit, win32con.MOD_ALT, win32con.VK_F3)

    def OnHotKeyStart(self, evt):
        if not self.work:
            self.work = WorkThread()
            self.work.setDaemon(True)
            self.work.start()

    def OnHotKeyEnd(self, evt):
        if self.work:
            self.work.stop()
            self.work = None

    def OnHotKeyQuit(self, evt):
        exit()

app = wx.App()
FrameWithHotKey(None)
app.MainLoop()

程序运行后,按Alt+F1会重复打印‘work’,按Alt+F2停止打印,按Alt+F3结束程序。

Matpoltlib绘制爱的方程式

分享到: 更多

灵感来自 http://www.matrix67.com/blog/archives/85

使用matplotlib绘制二维图形,使用contour来绘制方程,省去了手工计算的麻烦,解决思路参见 http://stackoverflow.com/questions/2484527/is-it-possible-to-plot-implicit-equations-using-matplotlib

效果:

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np
import matplotlib.pyplot as plt

X = np.arange(-5.0, 5.0, 0.1)
Y = np.arange(-5.0, 5.0, 0.1)
x, y = np.meshgrid(X, Y)
f = 17 * x ** 2 - 16 * np.abs(x) * y + 17 * y ** 2 - 225

plt.figure()
CS = plt.contour(x, y, f, 0, colors='r')
plt.title(r'$17x^2-16|x|y+17y^2=255$')
plt.show()

但是对于3D版 http://www.matrix67.com/blog/archives/223 ,小弟还没有找到优雅的求解方法,期待牛人的解答。

RLock来实现多线程同步

分享到: 更多

问题场景

有多个线程,分别负责建造房子,种树,养花之类的工作,这些工作都需要一定的等待时间,在等待过程中需要与服务端通信来保持连接。连接的提交不能太过频繁,最好2-3秒一次。

对于这种多线程之间的同步问题可以利用RLock来实现锁机制。

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
#coding=utf-8
'''
Created on 2010-9-14
@author: stonelee
'''
import time
import random
import threading
p_lock = threading.RLock()
s_lock = threading.RLock()

def my_post(str):
    p_lock.acquire()
    print str
    time.sleep(random.random() * 2)
    p_lock.release()

def my_sleep(seconds):
    s_lock.acquire()
    time.sleep(seconds)
    s_lock.release()

def my_wait(name, seconds):
    last_time = time.time()
    last_seconds = 0
    while last_seconds < seconds:
        my_post('%s:%s' % (time.time(), name))
        my_sleep(3)
        last_seconds = time.time() - last_time

class ThreadA(threading.Thread):
    def run(self):
        for i in range(10000):
            my_post('%s:==================build house' % time.time())
            my_wait('a wait', 20)

class ThreadB(threading.Thread):
    def run(self):
        for i in range(10000):
            my_post('%s:=================plant tree' % time.time())
            my_wait('b wait', 5)

threadA = ThreadA()
threadA.setDaemon(True)
threadB = ThreadB()
threadB.setDaemon(True)

threadA.start()
threadB.start()
threadA.join()
threadB.join()

使用进程间通信开发Inkscape插件

分享到: 更多

Inkscape是一款功能强大的svg图形绘制软件,开源免费,而且可以用python写扩展。

正好项目需要借助Inkscape来绘制图形,需要开发相应的插件,翻遍Inkscape的插件系统,觉得它的实现比较弱,尤其是界面控件,仅仅提供了基本的文本、下拉框几种,不给力啊~

在与同事谈论许久之后,给出以下方案:

1.Extensions调用子进程,传递参数。

1
2
3
4
5
6
import subprocess
f = open('lxd/error.txt', 'w')
subproc = subprocess.Popen(['python', 'lxd/lxd.py'], stdin=subprocess.PIPE, stdout=subprocess.PIPE,
f.close()
r = subproc.communicate('inkscape')[0]#传递参数,返回子进程的stdout
draw_sth(tri, r)#Inkscape画图

2.子进程中进行实际功能开发。此段略过~可以借助强大丰富的python库实现理想的效果。

3.子进程与Extensions进程间通信,返回参数。

1
2
3
import sys
s = sys.stdin.readline()#获取主进程Extensions传递的参数
sys.stdout.write(s + '123')#向主进程Extensions传递参数

纸质材料数字化方法总结

分享到: 更多

如何将纸质材料转为word文档?

通过扫描仪将纸质材料扫描成图片格式。

首先安装扫描仪驱动,连接好扫描仪。 我用的是汉王OCR 6.0,打开软件后,先选择好相应的扫描仪,点击“扫描”。 模式我选的是“黑白图片”,经试验对于本来就比较清晰的文本这种格式的识别率最高,而且扫描速度也快。 对于不太清楚的文本可以使用自定义设置,多试验几个选项来加强识别率。 然后就要一页一页的将材料扫描为图片了,图片会自动保存到image目录下。

文字识别

点击“选择所有文字”,再点击“开始识别”,将保存的所有图片扫描为文本格式,这时会发现原来的图片文字会自动被识别保存到相应的文本文件里。 识别过程中发现对于某些情况汉王识别率可以迅速降为0,比如扫描文字右侧文字偏小时,有黑道时。这时可以借助另一款识别软件 清华紫光OCR 来进行识别。

文字修改

借助汉王强大的识别对照功能,可以轻松实现文字的修改。

在上面的编辑区中,如果发现识别错误的地方,只需要将光标移过去,上方就会出现原来文字对照和文字提示,修改起来很方便。美中不足之处就是不能用鼠标滚轮移动页面,需要借助键盘上的上下箭头。另外“施”这个字无法修改,不知道什么原因….修改好一页后,只需要在左侧导航栏里点击下一幅图片就可以了,系统会自动保存。也幸亏有这个功能,汉王一高兴了就死掉,不知道为何原因。。。

文件整理到word中

编程实现各文本文件汇总到一个单一文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os
def join(pathname):
    fdoc = open('doc.txt', 'a')
    for dirpath, dirnames, filenames in os.walk(pathname):
        for file in filenames:
            if file.split('.')[-1].lower() == 'txt':
                wholeFile = os.path.join(pathname, file)
                f = open(wholeFile, 'r')
                fdoc.write(f.read())
                f.close()
                print '%s is over' % file
        fdoc.close()
        print 'all over'

if __name__ == '__main__':
    pathname = ur'D:\Program Files\HWOCR60\IMAGE'
    join(pathname)

在word中将全部空格,回车符替换为空,然后分段,然后整体修改,搜索“设旋”、“设旌”改为“设施”… 完善格式…

ps

Microsoft Office 工具里的Microsoft Office Document Imaging也可以实现识别功能,看它的版权页发现使用的是清华紫光的TH-OCR技术,不过是2002版本的,比起网上下载的99版TH-OCR好多了。可以考虑应用VBA做一些批处理操作。

另外下载了据称是世界上最先进的识别软件ABBYY FineReader,试用版可以使用15天,识别50页,试用了下效果还可以。注册的话需要$200。

Python中类方法、类实例方法、静态方法的使用与区别

分享到: 更多

参考自 http://stackoverflow.com/questions/1669445/what-is-the-difference-between-a-static-method-and-class-method-in-python

使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A(object):
    def foo(self,x):
        #类实例方法
        print "executing foo(%s,%s)"%(self,x)

    @classmethod
    def class_foo(cls,x):
        #类方法
        print "executing class_foo(%s,%s)"%(cls,x)

    @staticmethod
    def static_foo(x):
        #静态方法
        print "executing static_foo(%s)"%x

调用方法:

1
2
3
4
5
6
7
8
a = A()
a.foo(1)

a.class_foo(1)
A.class_foo(1)

a.static_foo(1)
A.static_foo(1)

运行结果:

1
2
3
4
5
executing foo(<__main__.A object at 0xb77d67ec>,1)
executing class_foo(<class '__main__.A'>,1)
executing class_foo(<class '__main__.A'>,1)
executing static_foo(1)
executing static_foo(1)

区别:

  • 类方法和静态方法都可以被类和类实例调用,类实例方法仅可以被类实例调用
  • 类方法的隐含调用参数是类,而类实例方法的隐含调用参数是类的实例,静态方法没有隐含调用参数

Python动态改变对象属性(热插拔)

分享到: 更多

运用非面向对象的技术,结合动态语言的特性,确实能实现许多很灵活的功能,

本文根据“Mixin 扫盲班 – 赖勇浩”文后 沈崴哥的代码

假设现有水果,需要描述它的属性:颜色,熟了没?直接上代码:

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
#coding=utf-8
class Instance:
    def __init__(self, *args):
        for m in args:
            m(self)

    def config(self, *args):
        for m in args:
            m(self)

#无参数的
def has_harvest(self):
    self.harvest = True

def has_not_harvest(self):
    self.harvest = False

#有参数的
def setColor(color):
    def method(self):
        self.color = color
    return method

apple = Instance(has_not_harvest, setColor('green'))
print 'harvest:%s;color:%s' % (apple.harvest, apple.color)

apple.config(has_harvest, setColor('red'))
print 'harvest:%s;color:%s' % (apple.harvest, apple.color)

结果如下:

1
2
harvest:False;color:green
harvest:True;color:red

如果想再添加一属性:能不能吃?,很简单,代码如下:

1
2
3
4
5
#再加一属性
def can_eat(self):
    self.eat = True
apple.config(has_harvest, setColor('red'), can_eat)
print 'harvest:%s;color:%s;eat:%s' % (apple.harvest, apple.color, apple.eat)

结果如下:

1
harvest:True;color:red;eat:True

用这种技巧动态增加对象方法非常方便,值得推荐

Dwg转化为svg

分享到: 更多

最近一个项目想将AutoCAD做的矿图转化为svg格式来在网页上作为底图展示。初步考虑使用Acme CAD Converter进行格式转化。

命令行使用:

1
$ AcmeCADConverter /r /p 1 /f 101 /a -2 /w 2000 /h 1500 "d:\Drawing1.dwg"
  • /r 命令行模式
  • /p 1 黑色
  • /f 101 svg格式
  • /a -2 转化所有图层
  • /w 2000 宽2000mm(实际上是将svg图形放大到这个范围)
  • /h 1500 高1500mm
  • 可添加多个文件路径。
  • /e 自动伸展图形到合适位置,因为本项目还想在底图基础上绘制新的图形,对位置要求比较严格,因此不使用本项。需要在AutoCAD中将图形拖到一个合适的位置,然后再转化。

未注册版本的Acme CAD Converter生成的svg会有一个水印,但从源码来看实际上就是12个path而已,非常 容易去掉,不知道该软件作者是基于什么考虑…

Google SketchUp可以很容易的创建三维图形,Inkscape来编辑svg图形。