存档

2009年10月 的存档

一个小孩子玩的绘画软件 – Tux Paint

2009年10月30日

SourceForge上偶然发现一个开源的绘画软件Tux Paint,介绍是说专门针对小孩子的。便下载下来给四岁的女儿使用,她还真的很喜欢,在电脑上堆砌出一层一层的色彩和图案。
Tux Paint的界面十分易用,一个空的画布和左右很多有意思的工具,另外还配有有趣的声效。
Tux paint

Tux Paint的官方网站:http://www.tuxpaint.org/
下载:
官方网站,另外还有Zip版免安装文件
SourceForge下载

其它

Excel数独游戏

2009年10月11日

很久以前看WM Lee的《Programming Sudoku》那本书,根据里面的方法写了一个Excel数独游戏,但是一直有些地方没有完善,后来就搁下来了。
国庆的时候有些时间,重新翻出来,修改了原来的代码,添加了一些其它的功能。

这是一个完整的数独游戏,功能如下:

  1. 提供不同难度的数独游戏生成(两种方法);
  2. 提供逐步提示和全解功能;
  3. 可从互联网下载指定难度的游戏;
  4. 提供帮助/编辑模式;
  5. 提供保存、导入和打印功能。

下载:SkyDrive

界面:

Excel Sudoku

VBA , ,

Excel窗体和谷歌拼音输入法的冲突

2009年10月10日

之前写一些带窗体的Excel宏时,经常发现关闭文件和Excel后会出现一个Excel错误问题窗口。
msgbox of excel userform conflict
一直以为是代码的问题,后来点击上面的“此错误报告包含什么数据?”的链接,发现居然和谷歌拼音有关系。
info of excel userform conflict

试了试各种情况。
如果先开启Excel,打开带有窗体(窗体可以不带任何控件)的Excel文件,再开启谷歌拼音,然后开启窗体,然后关闭窗体,关闭文件,退出Excel,过几秒种后就会出现上面的错误窗口。
然而在打开Excel文件之前开启谷歌拼音,再打开文件以及窗体,关闭文件和Excel之后则不会出现错误窗口。
很奇怪的一个冲突。

VBA , ,

OpenOffice.org宏学习笔记4

2009年10月3日

前面介绍了OpenOffice.Org SpreadSheet宏的IDE和UNO,现在可以开始编写代码了。这里主要介绍怎样使用宏操作工作表,我们将学会怎样:

  • 打开和关闭文件
  • 使用多个工作表
  • 在工作表中操作数据
  • 使用OOo的内置函数
  • 使用单元格和区域

打开和关闭电子表格

在前面我们已经知道了怎样打开和关闭电子表格

  1. 使用starDeskTop对象访问电子表格
  2. 使用loadComponentFromURL函数载入电子表格
  3. 使用close方法关闭电子表格
  4. 使用fileExists函数判断文件是否存在
  5. 使用storeAsUrl方法保存电子表格。

oosmacro0401
接着我们开始操作电子表格的内容。

操作电子表格单元格

我们知道:

  • 每个电子表格包括一个或多个工作表(一般默认是3个,最多可以到256个)
  • 每个工作表由8192000个单元格组成(256列乘以32000行)— OpenOffice.org Calc 3.0已经增加到67108864个单元格(1024乘以65536行)
  • 每个工作表可以通过一个序号(0到255)来指认
  • 每个单元格可以通过getCellByPosition方法使用一个格子坐标来指认它的位置

oosmacro0402

下面这个代码在一个工作表的单元格中填充内容:

Sub singleFile
   Dim oDoc as Object
   Dim oSheet as Object
   Dim oCell as Object
   oDoc = starDeskTop.loadComponentFromUrl _
      ("private:factory/scalc", "_blank",0,Array ())
   oSheet = oDoc.sheets (0)
   oCell = oSheet.getCellByPosition (0,0)
   oCell.String = now 'This function returns the current date and time
End Sub

这个宏打开一个空白电子表格,获得第一个工作表,然后获得最左上角的单元格,写入当前时间到该单元格。
内容可以以三种方式写入到单元格—公式、字符串、数值。这个很重要,参考下面的代码:

oCell = oSheet.getCellByPosition (0,1)
oCell.Value = 20
oCell = oSheet.getCellByPosition (0,2)
oCell.Value = 30
oCell = oSheet.getCellByPosition (1,1)
oCell.String = "=A2+A3"
oCell = oSheet.getCellByPosition (2,1)
oCell.Formula = "=A2+A3"
oCell = oSheet.getCellByPosition (3,1)
oCell.Value = "=A2+A3"

尽管我们输入的信息差不多,但是结果却完全不同。
oosmacro0403
如果简单一些的话,上面的代码也可以写成:

oSheet.getCellByPosition (0,1).Value = 20
oSheet.getCellByPosition (0,2).Value = 30
oSheet.getCellByPosition (1,1).String = "=A2+A3"
oSheet.getCellByPosition (2,1).Formula = "=A2+A3"
oSheet.getCellByPosition (3,1).Value = "=A2+A3"

使用OOo内置函数

我们会经常在Calc中使用OOo的内置数学函数。在宏中我们也可以使用它们。例如,我们可以:

oCell1 = oSheet.getCellRangeByName ("A1")
oCell2 = oSheet.getCellRangeByName ("B1")
oCell1.value = 23.1
oCell2.value = SIN(oCell1.value)

也可以这样:

oCell2.formula = "=SIN(A1)"

有什么区别呢?前面的代码将值-0.9放入B1单元格,而后面的代码则在B1单元格中放入一个公式。
然而,只有一部分函数可以这样使用。例如,下面的代码可以运行:

For r = 0 to 9
   i = r + 1
   oCell1 = oSheet.getCellByPosition (0,r)
   oCell1.Value = i
   oCell2 = oSheet.getCellByPosition (1,r)
   oCell2.Formula = "=ROMAN(A" + i + ")"
Next r
oLetters = Array("I","V","X","L","C","D","M")
For r = 0 to ubound(oLetters)
   i = r + 1
   oCell1 = oSheet.getCellByPosition (2,r)
   oCell1.String = oLetters(r)
   oCell2 = oSheet.getCellByPosition (3,r)
   oCell2.Formula = "=ARABIC(C" + i + ")"
Next r

运行上面的代码,将在工作表中显示下面有趣的结果。
oosmacro0404
但是如果我们试下面的代码:

oCell2.value =ARABIC(oCell1.String)

将会得到下面的错误提示:
oosmacro0405

但这并不表示我们不能使用内置函数,只是需要使用另外一种方法(有些类似于Excel VBA中的Application.WorksheetFunction)。

oFunction = createUnoService("com.sun.star.sheet.FunctionAccess")
oCell4.value = oFunction.callFunction("ARABIC", _
Array(oCell3.String))

注意传递给函数CallFunction的第二个参数是一个数组。

命名工作表和单元格

我们可以使用序号通过Sheets集合来访问工作表,但是在删除或添加工作表或者工作表的顺序改变后,使用现有的序号访问工作表时可能会发生错误。因此最好使用工作表名称来访问它们。

访问现有命名的工作表和单元格

使用序号访问:

oSheet = oDoc.sheets(0)

使用名称访问:

oSheet = oDoc.Sheets.getByName("PPI Accounts")

访问到工作表后,也可以使用名称访问单元格。
使用位置访问:

oCell = oSheet.getCellByPosition(0,1)

使用名称访问:

oCell = oSheet.getCellRangeByName("Daily Total")

创建新的命名工作表和单元格

命名一个已存在的单元格很简单:

oSheet.name =  "PPI Client Details"

创建一个新的单元格也差不多简单:

oSheet = oDoc.createInstance ( "com.sun.star.sheet.Spreadsheet" )
oDoc.Sheets.insertByName ( "PPI Daily Tasks", oSheet )

给一个单元格命名则稍微麻烦点:

Dim oCellAddress As new com.sun.star.table.CellAddress
Dim oNamedRanges
oNamedRanges = oDoc.NamedRanges
oNamedRanges.addNewByName("Total", "$Sheet1.$A$8", oCellAddress, 0)

删除工作表

oDoc.Sheets.removeByName("Sheet3")

使用多个工作表

使用多个工作表和一个工作表的复杂程度是差不多的。

Sub sequencialFiles
   Dim oDoc as Object
   Dim oDesk as Object
   Dim oSheet as Object
   Dim oCell as Object
   oDoc = starDeskTop.loadComponentFromUrl _
      ("private:factory/scalc", "_blank",0,Array())
   oSheet = thisComponent.sheets (0)
   oCell = oSheet.getCellByPosition (0,0)
   oCell.String = now
   oDoc = starDeskTop.loadComponentFromUrl _
      ("private:factory/scalc", "_blank",0,Array())
   oSheet = thisComponent.sheets (0)
   oCell = oSheet.getCellByPosition (0,0)
   oCell.String = now + 1
End Sub

运行结果如图:
oosmacro0406
上面的代码使用一个对象变量来表示不同的对象,这样需要再转换到另外一个对象之前保证完成自己的操作。我们会发现如果对每个电子表格使用不同的对象会更有效一些,这样我们可以控制所有的操作。

Sub multiSheets
   Dim oURL1 as String
   Dim oURL2 as String
   Dim oDoc1 as Object
   Dim oDoc2 as Object
   Dim oCell1 as Object
   Dim OCell2 as Object
   oURL1 = "private:factory/scalc"
   oURL2 = "private:factory/scalc"
   oDoc1 = starDeskTop.loadComponentFromURL (oURL1, "_blank", 0, _
      Array() )
   oDoc2 = starDeskTop.loadComponentFromURL (oURL2, "_blank", 0, _
      Array() )
   oCell1 = oDoc1.Sheets (0).getCellByPosition (0,0)
   oCell1.String = now
   oCell1 = oDoc1.Sheets (0).getCellByPosition (0,1)
   oCell1.Value = 37.5
   oCell2 = oDoc2.Sheets (0).getCellByPosition (0,0)
   oCell2.String = now
   oCell2 = oDoc2.Sheets (0).getCellByPosition (0,1)
   oCell2.String = "Amount"
   oCell2 = oDoc2.Sheets (0).getCellByPosition (1,1)
   oCell2.String = "VAT"
   oCell2 = oDoc2.Sheets (0).getCellByPosition (2,1)
   oCell2.String = "Total"
   oCell2 = oDoc2.Sheets (0).getCellByPosition (0,2)
   oCell2.Value = oCell1.Value
   oCell2 = oDoc2.Sheets (0).getCellByPosition (1,2)
   oCell2.Value = oCell1.Value * 0.175
   oCell2 = oDoc2.Sheets (0).getCellByPosition (2,2)
   oCell2.Value = oCell1.Value * 1.175
End Sub

使用区域

除了使用单元格之外,我们还需要使用区域。下面的代码将第2个工作表中区域A1:A100的内容负责到第一个工作表相同的区域中。

oRange1 = oDoc1.Sheets (1).getCellRangeByName ("A1:A100")
oRange2 = oDoc2.Sheets (0).getCellRangeByName ("A1:A100")
oRange2.setDataArray (oRange1.getDataArray ())

也可以使用单元格位置来表示区域。

oRange1 = oDoc1.Sheets (0).getCellRangeByPosition (0,0,0,100)
oRange2 = oDoc2.Sheets (0).getCellRangeByPosition (0,0,0,100)

区域在使用某些函数时特别有用。

oCell1 = oSheet.getCellRangeByName ("A1")
oCell2 = oSheet.getCellRangeByName ("A2")
oCell3 = oSheet.getCellRangeByName ("A3")
oCell4 = oSheet.getCellRangeByName ("B3")
oCell1.Value = 36
oCell2.Value = 57
oCell3.Value = 42
oRange1 = oSheet.getCellRangeByName ("A1:A3")
'Remember to use callFunction
oCell4.Value = _
oFunction.callFunction("STDEV", Array(oRange1.getDataArray ()))

OpenOffice ,

国庆中秋快乐

2009年10月2日

国庆中秋长假,大家快乐。
大图片的图片新闻是很值得看的,昨天放上国庆60周年的图片。

其它