二月 09

StyledTextCtrl中自定义语法高亮,主要是设置Lexer为STC_LEX_CONTAINER,然后在EVT_STC_STYLENEEDED事件中对文档进行着色处理;当EVT_STC_STYLENEEDED事件发生时候,获取起始和结束位置进行SetStyling的操作。当打开一个较大文件的时候,修改了文档中的某个位置,EVT_STC_STYLENEEDED会多次发出第一次通知后,在滚动条拖动时候会接着上次的结束位置多次发出通知…具体原因还得再研究;这种情况下,大文件的编辑就会非常吃力,所以得想办法停止事件的发生。

查阅文档并且google后,再查到一国外强人回帖:

An earlier message indicated that you use SCLEX_NULL. SCLEX_NULL
tries to maintain the style information as all 0s. To do this without
performing lots of unnecessary writing it just updates the last style
byte so that the style cursor is moved to the end of the document.

If you want to perform your own styling then use SCLEX_CONTAINER.
If you don’t want to perform any styling within the SCN_STYLENEEDED
notification, you should still move the styling cursor by calling
SCI_STARTSTYLING with the notification position (or the end of the
document) so that Scintilla will believe that styling has been
performed up to that point and not continue asking for more styling.

修改程序,在EVT_STC_STYLENEEDED事件中的着色处理完成后,使用StartStyling方法把style cursor指向文档结束位置:“style cursor is moved to the end of the document”, 问题解决。

最后,着色的起始位置应该根据语法,做一些分析,不应该仅仅是行的开头。

二月 09

目前使用wxPython 2.8.10版本,关于StyledTextCtrl控件的一些情况:

wxPython 2.8.10中的StyledTextCtrl应该是基于scintilla 1.7x版本。

这个版本不支持一些scintilla高级功能,比如SCI_INDICATORFILLRANGE,所以”高亮所有匹配单词”似乎没办法实现。

wxWidget 2.9版本应该已经使用scintilla 2.01,官方看到一个补丁(http://trac.wxwidgets.org/ticket/11346),我想wxPython2.9应该也会StyledTextCtrl到scintilla 2.01。

wxPython的开发者Robin Dunn:“I’ve been busy with day-job work and some life issues so progress has been slow lately, but it is moving forward.”。

二月 05

代码折叠功能是一个完善的编辑器不可缺少的功能,在StyledTextCtrl中可以自定义语法高亮,当然也可以自定义代码折叠(关于自定义语法高亮,大家爱可以读读limodou大侠的《StyledTextCtrl语法高亮使用的探讨》一文)。
StyledTextCtrl中的代码折叠的基础是每行的FoldLevel值,FoldLevel值的大小不同,就形成了不同的代码块,例如:

这样的折叠效果,每行的FoldLevel为:

第一列是行(从0开始是第一行),第二列是FoldLevel,第三列是FoldLevel原始值;第二列的FoldLevel由第三列FoldLevel原始值解码出来。
代码被设计成基于大括号折叠,对比两个图,可以找出规律:最外层的“{”FoldLevel是1024,第二个“{”是1025,第三个“{”是1026;它们的FoldLevel都大于8192(wx.stc.STC_FOLDLEVELHEADERFLAG),这表示了他们是折叠的开始。
剩下的行,凡属于代码块的行,都会比折叠的开始行要小。
控件就会根据每行的FoldLevel值不一样,产生了折叠效果。

这里有个设置每行FoldLevel值的代码片段,供产考:

def MakeFoldLevel(self, begin = 0):
	beginPosition = 0

	endPosition = self.editor.GetTextLength()

	currentLine  = self.editor.LineFromPosition(beginPosition)
	currentLineLevel = self.editor.GetFoldLevel(currentLine) & wx.stc.STC_FOLDLEVELNUMBERMASK
	prevLineLevel = currentLineLevel

	i = 0
	while beginPosition + i < endPosition:
		pos = beginPosition + i
		currentChr = chr(self.editor.GetCharAt(pos))

		if self.editor.GetStyleAt(pos) == styleIndex['bracket']:
			if currentChr == '{':
				currentLineLevel += 1
			elif currentChr == '}':
				currentLineLevel -= 1

		if (currentChr=="\n") or (currentChr=="\r" and chr(self.editor.GetCharAt(pos+1))!="\n"):

			level = prevLineLevel

			if currentLineLevel > prevLineLevel:
				level |= wx.stc.STC_FOLDLEVELHEADERFLAG

			if level != self.editor.GetFoldLevel(currentLine):
				self.editor.SetFoldLevel(currentLine, level)

			currentLine += 1
			prevLineLevel = currentLineLevel

		i += 1

	if currentLineLevel<>prevLineLevel:
		self.editor.SetFoldLevel(currentLine, prevLineLevel)
	else:
		self.editor.SetFoldLevel(currentLine, currentLineLevel)

这不是教程,只是对实现思路的探讨,更多内容请参考官方文档,谢谢关注 ^_^

二月 01

NeatEditor是一个文本编辑器,我会用它编辑各种文本文件,编码肯定也是五花八门:UTF-8,GBK,BIG5 等等。
NeatEditor使用wxpython的StyledTextCtrl作为编辑控件,StyledTextCtrl只处理UTF-8的文本;这就需要在打开文件后,把内容转换成UTF-8编码。python中的编码转换,首先需要将来源转换成unicode,然后再把unicode格式的内容转成所需的编码。为了能将内容正确转换成unicode编码,就需要在转换时候指定源编码:content = unicode(content, ‘utf-8′)

作为一个为文本编辑器,是不知道所编辑的文件是源编码;我观察了几款文本编辑器这方面的处理,当打开一个Cyrillic(斯拉夫语系,也就是俄语的编码)编码的文件,EditPlus会弹出选择编码的对话框,这时候如果选择了GBK编码,EditPlus就会提示出错,请重新选择编码,直到正确转换为止;当然也可以跳出。

根据这个思路,NeatEditor在处理这个问题时,首先会尝试用UTF-8对源文件进行转码,如果跑出异常则尝试ANSI(ANSI是当前操作系统的默认编码),再有异常就弹出对话框让用户选择编码!

try:
	content = unicode(content, 'utf-8')
except:
	try:
		content = unicode(content, Common.defaultEncoding)
	except:
		if Dialog.EncodingAlert(self.win):
			while True:
				try:
					encoding = Dialog.EncodingSelect(self.win)
					content = unicode(content, encoding)
					break
				except:
					if not Dialog.EncodingAlert(self.win):
						break

二月 01

多年来,非常习惯使用EditPlus,也非常痛恨EditPlus没有一个方便的File Explorer侧边栏和完善的代码折叠…
但本人有个怪癖,极为钟情EditPlus的PHP代码高亮,尤其是变量$的单独高亮,市面上的编辑器还真就没有符合我这个要求的。

自己写吧…随便学习!再此记录,督促…

当前已经实现了代码高亮,折叠还有基于文件夹的Project,也就是File Explorer。

根据团队习惯,命名为 NeatEditor

二月 01

最近在使用wxpython制作类资源管理器的文件树,为了更直观显示文件以及文件夹,想使用系统图标,,效果:

在wxpython中不能直接得到系统图标,经过查阅可以使用windows API函数SHGetFileInfo得到图标的resource,然后转成wxBitmap。

关键代码片段:

from win32com.shell import shell, shellcon
from win32con import FILE_ATTRIBUTE_NORMAL
import win32con

def GetFileIcon(path):
	flags = shellcon.SHGFI_SMALLICON | shellcon.SHGFI_ICON
	retval, info = shell.SHGetFileInfo(path,FILE_ATTRIBUTE_NORMAL,flags)

	assert retval

	hicon, iicon, attr, display_name, type_name = info

	# Get the bitmap
	icon = wx.EmptyIcon()
	icon.SetHandle(hicon)
	return wx.BitmapFromIcon(icon)

变量path是字符串,标示路径,比如”d:\”,这样就可以得到D盘的图标数据;也可以是某个文件”D:\file.py”,得到的是此文件的图标数据。值得注意的是,这里面的路径分隔符必须是单个”/”,否者就会报错。
这样就可以加到TreeCtrl控件的ImageList对象中进行显示方面的处理,这块不用多说。
效果就是上图所示了。

preload preload preload