
2011年9月30日
学习新的图形库时有个习惯,就是将罗云彬先生的一个闹钟小程序移植到这个图形库下。
原理也很简单,就是通过图片以第一个点的颜色为透明色创建窗体,但Gtk#创建就有些费劲了,主要是因为Gtk#的原生库Gtk+为C写的,有很多指针操作,在C#下有些麻烦,查了好多资料才写了下面几句代码。
然后用Cairo绘制时钟的时间,也是一张图片,然后按时、分、秒截取图形的一部分绘制到不透明窗体上。
在Windows 7、Ubunu 11.04下运行,效果相同。
见代码:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using Cairo;
6 using Gdk;
7 using Gtk;
8 using Window = Gtk.Window;
9 using WindowType = Gtk.WindowType;
10
11 namespace GClock
12 {
13 public class MainWindow : Window
14 {
15 bool timer = true;
16 readonly Pixbuf _pixbufNumber; // 时钟时间图片,为0-9十个数字和:以及空白部分组成
17
18 public MainWindow()
19 : base(WindowType.Toplevel)
20 {
21 _pixbufNumber = new Pixbuf(GetType().Assembly, "GClock.Bmp.Number06.bmp");
22
23 // 从嵌入资源中获取Pixbuf
24 var pixbufO = new Pixbuf(GetType().Assembly, "GClock.Bmp.Clock03.bmp");
25 // 取Pixbuf第一个点的rgb值
26 byte r, g, b;
27 unsafe {
28 // Pixbuf的Pixels未记录图片每个点信息值
29 // 取(x,y)的rgb值,以下代码中x,y均为0
30 // var p = (byte*)pixbufO.Pixels.ToPointer() + y * pixbufO.Rowstride + x * pixbufO.NChannels;
31 var p = pixbufO.Pixels.ToPointer();
32 r = *(byte*)p;
33 g = *((byte*)p + 1);
34 b = *((byte*)p + 2);
35 }
36 // 依据第一个点的rgb值增加透明通道
37 var pixbuf = pixbufO.AddAlpha(true, r, g, b);
38
39 Decorated = false; // 不设置窗体边框
40 AppPaintable = true; // 应用程序绘制界面
41 SetDefaultIconFromFile("Clock00.ico");
42 //SetDefaultSize(pixbuf.Width, pixbuf.Height);
43 SetDefaultSize(500, 500);
44 SetPosition(WindowPosition.Center);
45
46 Realize(); // 创建Window的资源,若不调用则this.GdkWindow为null
47
48 DeleteEvent += delegate { Application.Quit(); };
49 // 添加鼠标点击事件
50 AddEvents((int)EventMask.ButtonPressMask);
51 GLib.Timeout.Add(100, OnTimer); // 时间事件
52
53 Pixmap pixmap, pixmask;
54 // 依据Pixbuf创建Pixmap以及对应的蒙板Pixmap
55 pixbuf.RenderPixmapAndMask(out pixmap, out pixmask, 128);
56 ShapeCombineMask(pixmask, 0, 0);
57 GdkWindow.SetBackPixmap(pixmap, false);
58
59 ShowAll();
60 }
61
62 protected override bool OnButtonPressEvent(EventButton evnt)
63 {
64 // 鼠标左键点击移动窗体
65 if (evnt.Type == EventType.ButtonPress && evnt.Button == 1) {
66 BeginMoveDrag((int)evnt.Button, (int)evnt.XRoot, (int)evnt.YRoot, evnt.Time);
67 }
68 return base.OnButtonPressEvent(evnt);
69 }
70
71 protected override bool OnExposeEvent(EventExpose evnt)
72 {
73 base.OnExposeEvent(evnt);
74
75 using (var cr = CairoHelper.Create(evnt.Window)) {
76 var curTime = DateTime.Now;
77 int tenDigit, entriesDigit;
78
79 var x = 25;
80 const int y = 80;
81 cr.Save();
82 // 绘制左侧空白
83 cr.Translate(x, y);
84 CairoHelper.SetSourcePixbuf(cr, _pixbufNumber, -(15 * 10 + 8), 0);
85 cr.Rectangle(0, 0, 2, 25);
86 cr.Clip();
87 cr.Paint();
88
89
90 // HH
91 DecToBcd(curTime.Hour, out tenDigit, out entriesDigit);
92 x += 2;
93 cr.Restore();
94 cr.Save();
95 cr.Translate(x, y);
96 CairoHelper.SetSourcePixbuf(cr, _pixbufNumber, -15 * tenDigit, 0);
97 cr.Rectangle(0, 0, 15, 25);
98 cr.Clip();
99 cr.Paint();
100
101 x += 15;
102 cr.Restore();
103 cr.Save();
104 cr.Translate(x, y);
105 CairoHelper.SetSourcePixbuf(cr, _pixbufNumber, -15 * entriesDigit, 0);
106 cr.Rectangle(0, 0, 15, 25);
107 cr.Clip();
108 cr.Paint();
109
110 // :
111 x += 15;
112 cr.Restore();
113 cr.Save();
114 cr.Translate(x, y);
115 CairoHelper.SetSourcePixbuf(cr, _pixbufNumber, -15 * 10, 0);
116 cr.Rectangle(0, 0, 8, 25);
117 cr.Clip();
118 cr.Paint();
119
120 // MM
121 DecToBcd(curTime.Minute, out tenDigit, out entriesDigit);
122 x += 8;
123 cr.Restore();
124 cr.Save();
125 cr.Translate(x, y);
126 CairoHelper.SetSourcePixbuf(cr, _pixbufNumber, -15 * tenDigit, 0);
127 cr.Rectangle(0, 0, 15, 25);
128 cr.Clip();
129 cr.Paint();
130
131 x += 15;
132 cr.Restore();
133 cr.Save();
134 cr.Translate(x, y);
135 CairoHelper.SetSourcePixbuf(cr, _pixbufNumber, -15 * entriesDigit, 0);
136 cr.Rectangle(0, 0, 15, 25);
137 cr.Clip();
138 cr.Paint();
139
140 // :
141 x += 15;
142 cr.Restore();
143 cr.Save();
144 cr.Translate(x, y);
145 CairoHelper.SetSourcePixbuf(cr, _pixbufNumber, -15 * 10, 0);
146 cr.Rectangle(0, 0, 8, 25);
147 cr.Clip();
148 cr.Paint();
149
150 // SS
151 DecToBcd(curTime.Second, out tenDigit, out entriesDigit);
152 x += 8;
153 cr.Restore();
154 cr.Save();
155 cr.Translate(x, y);
156 CairoHelper.SetSourcePixbuf(cr, _pixbufNumber, -15 * tenDigit, 0);
157 cr.Rectangle(0, 0, 15, 25);
158 cr.Clip();
159 cr.Paint();
160
161 x += 15;
162 cr.Restore();
163 cr.Save();
164 cr.Translate(x, y);
165 CairoHelper.SetSourcePixbuf(cr, _pixbufNumber, -15 * entriesDigit, 0);
166 cr.Rectangle(0, 0, 15, 25);
167 cr.Clip();
168 cr.Paint();
169
170 // 绘制右侧空白
171 x += 15;
172 cr.Restore();
173 cr.Save();
174 cr.Translate(x, y);
175 CairoHelper.SetSourcePixbuf(cr, _pixbufNumber, -(15 * 10 + 8), 0);
176 cr.Rectangle(0, 0, 2, 25);
177 cr.Clip();
178 cr.Paint();
179
180 cr.Restore();
181 }
182
183 return true;
184 }
185
186 bool OnTimer()
187 {
188 if (!timer) return false;
189
190 QueueDraw();
191 return true;
192 }
193
194 // 依据两位数获取该数字的十位、个位数
195 private static void DecToBcd(int decimalNum, out int tenDigit, out int entriesDigit)
196 {
197 tenDigit = decimalNum / 10;
198 entriesDigit = decimalNum % 10;
199 }
200 }
201 }
主窗体背景图片:
时钟数字图片:
程序运行图片:

posted @ 2011-09-30 16:00 山伟 阅读(225) 评论(1)
编辑

2010年9月20日
问题:请写一个方法,两个参数,来判断第二个参数在第一个参数中出现了几次
1)用正则表达式,非常容易得出结果:
static int
FindCountInStringByRegex(string str, string pattern)
{
if (string.IsNullOrEmpty(str) ||
string.IsNullOrEmpty(pattern)) {
return 0;
}
if (pattern.Length > str.Length) {
return 0;
}
return
Regex.Matches(str, pattern).Count;
}
很简洁,但问题是,若str为"aaaa"、pattern为"aa",上面的方法结果为2,而实际要得到的应该是3。 这个用正则表达式还真就不知道怎么实现了。
2)无奈还是用最基本的方法实现吧:
static int
FindCountInString(string str, string pattern)
{
if (string.IsNullOrEmpty(str) ||
string.IsNullOrEmpty(pattern)) {
return 0;
}
if (pattern.Length > str.Length) {
return 0;
}
int count = 0, index = 0;
while (index < str.Length) {
index =
str.IndexOf(pattern, index);
if (index >= 0) count++;
else break;
index++;
}
return count;
}
posted @ 2010-09-20 20:24 山伟 阅读(17) 评论(0)
编辑
问题:一个日志文件,记录形如访问时间、url这样的记录,每行一条记录。请按每个url访问的次数进行逆排序
一、很简单的一个问题,首先用很普通的思维来解决:
1)先模拟来生成一个类似的文件:
private static void GenerateUrlLog()
{
string[] urlList = new string[7];
urlList[0] = "http://www.sohu.com";
urlList[1] = "http://www.baidu.com";
urlList[2] = "http://www.google.com";
urlList[3] = "http://www.sina.com.cn";
urlList[4] = "http://www.cnblogs.com";
urlList[5] = "http://www.yahoo.com";
urlList[6] = "http://www.csdn.net";
StreamWriter writer = new StreamWriter("url.data");
Random random = new Random(20);
int i = 0;
while (i < 40) {
int index = random.Next(7);
DateTime now = DateTime.Now;
Console.WriteLine(string.Format("{0}\t{1}", now, urlList[index]));
writer.WriteLine(string.Format("{0}\t{1}", now, urlList[index]));
i++;
Thread.Sleep(2000);
}
writer.Flush();
writer.Dispose();
Console.WriteLine("-------------------------------------");
}
2)顺序遍历文件,用Dictionary<string, int>来记录每个url的访问次数:
private static void ParseUrlLog()
{
StreamReader reader = new StreamReader("url.data");
string urlLog = null;
Dictionary<string, int> dicLogInfo = new Dictionary<string, int>();
while ((urlLog = reader.ReadLine()) != null) {
string[] logProperty = urlLog.Split('\t');
if (dicLogInfo.ContainsKey(logProperty[1])) {
dicLogInfo[logProperty[1]] = dicLogInfo[logProperty[1]] + 1;
} else {
dicLogInfo[logProperty[1]] = 1;
}
}
reader.Dispose();
Console.WriteLine("-------------------------------------");
int urlLogCount = dicLogInfo.Count;
for (int i = 0; i < urlLogCount; i++) {
int max = 0;
string maxUrl = "";
foreach (string key in dicLogInfo.Keys) {
if (max < dicLogInfo[key]) {
max = dicLogInfo[key];
maxUrl = key;
}
}
dicLogInfo.Remove(maxUrl);
Console.WriteLine(string.Format("{0}\t{1}", maxUrl, max));
}
Console.WriteLine(result.Count());
Console.WriteLine("-------------------------------------");
}
二、既然都.net 4.0了,就用新的方式来处理一下:
1)还是生成日志文件,改用.net 4的并行方式:
private static void GenerateUrlLog()
{
string[] urlList = new string[7];
urlList[0] = "http://www.sohu.com";
urlList[1] = "http://www.baidu.com";
urlList[2] = "http://www.google.com";
urlList[3] = "http://www.sina.com.cn";
urlList[4] = "http://www.cnblogs.com";
urlList[5] = "http://www.yahoo.com";
urlList[6] = "http://www.csdn.net";
StreamWriter writer = new StreamWriter("url.data");
Random random = new Random(20);
Parallel.For(0, 40, j => {
int index = random.Next(7);
DateTime now = DateTime.Now;
Console.WriteLine(string.Format("{0}\t{1}", now, urlList[index]));
writer.WriteLine(string.Format("{0}\t{1}", now, urlList[index]));
Thread.Sleep(2000);
});
writer.Flush();
writer.Dispose();
Console.WriteLine("-------------------------------------");
}
生成文件速度比之前的方式快,毕竟并行嘛,当然之前的方式也可以改用多线程来做,类似。
2)用LinQ来查询数据:
private static void ParseUrlLog()
{
StreamReader reader = new StreamReader("url.data");
string urlLog = null;
Dictionary<string, int> dicLogInfo = new Dictionary<string, int>();
while ((urlLog = reader.ReadLine()) != null) {
string[] logProperty = urlLog.Split('\t');
PrintParseLog(logProperty[0], logProperty[2]);
if (dicLogInfo.ContainsKey(logProperty[2])) {
dicLogInfo[logProperty[2]] = dicLogInfo[logProperty[2]] + 1;
} else {
dicLogInfo[logProperty[2]] = 1;
}
}
reader.Dispose();
Console.WriteLine("-------------------------------------");
var result = from url in dicLogInfo orderby url.Value descending select url;
foreach (var item in result) {
Console.WriteLine("{0}\t{1}", item.Key, item.Value);
}
Console.WriteLine(result.Count());
Console.WriteLine("-------------------------------------");
}
查数据部分少了很多代码,最重要的是打印出url访问次数后,Dictionary<string,int>还可以使用,不像上面的方式打印完后Dictionary也就清空了,而且result也可以多次使用。
3)既然LinQ是查数据的,为什么还要构建一个Dictionary,直接查不可以吗?可以:
private static void ParseUrlLog2()
{
StreamReader reader = new StreamReader("url.data");
List<string> urlLog = new List<string>();
string tempUrl = null;
while ((tempUrl = reader.ReadLine()) != null) {
urlLog.Add(tempUrl);
}
reader.Dispose();
Console.WriteLine("-------------------------------------");
var result = urlLog.GroupBy(url => url.Split('\t')[1]).OrderByDescending(s => s.Count());
foreach (var item in result) {
Console.WriteLine("{0}\t{1}", item.Key, item.Count());
}
Console.WriteLine(result.Count());
Console.WriteLine("-------------------------------------");
}
posted @ 2010-09-20 20:14 山伟 阅读(79) 评论(0)
编辑

2010年8月21日
周五快下班时,现场测试发邮件说中午发过去的补丁有bug,并标注了操作的步骤。
看完,我直接给本部测试大姐发腾讯通:“大姐,那边的大姐比你测得还变态...”,大姐有些不乐意:“你是说我...”
直接跑到大姐工位:明天反正我也得来,这问题明天再说吧。
大姐:可我不想来,今天加会儿班吧。
Boss(部门经理)也威胁我:要不你下周出差去现场得了。
我:我出差也行,这边的bug得有人给我清,别我回来上百个等我清。
Boss:你可以连远程清。
...
不废话了,改吧。改完发现按现场测试的测法是没完没了的问题(靠,不定个规则,让我处理所有情况啊,而且也不看客户到底想要什么样的),后来跟大姐和Boss说了一下,就告诉那边必须按规则输入。然后出补丁,结果平台给的出补丁工具巨麻烦,用了一个多小时出了补丁,又发现跟以前出的补丁冲突(新出的版本比旧的反而早),又重出...
好不容易九点半发出去了,跟Boss说:明天不想来了
Boss来了句:你不来怎么行
...
公司所在地巨偏僻,打不着车,搭Boss的车去城铁。
路上Boss说:可能现在的房价涨得太狠了,我发现你们这帮80后不如以前人踏实,X副总以前当老师的,住宿舍住了10年,后来才出来....
我:我承认,我们也想在领域里有建树,可这房价让我们看不到希望。
另一个同事:生活都有困难啊
...
无语啊...
Boss其实应该感到高兴,毕竟我们这些人都是比较老实的,不像其他部门,要么吵吵加薪要么离职的。
天天一堆bug,被人说成代码质量不高,拜托,大部分都是我维护的其他人的,我自己从头做到尾的bug又有多少?说没自测,看看一天那么多事,还老催着提交单元,哪有时间自测?如果我自测了,延误了提交单元,责任不还在我这儿?从来不考虑是不是决策层的问题。
还有需求、设计这些岗位,一天到晚琢磨客户可能需要的是什么样吧,为什么不去现场问问?闭门造车做出的需求、设计,还指望程序员做出让客户满意的产品?整个项目组已经背离了公司创立当年的宗旨了...
周六大早上醒来发现正在下雨,好像还挺大,打开电脑查了一下周日没雨,那就周日去吧...
注:周五晚上那个其实也没什么大不了的功能,只不过是两个文本框一个录入前缀,一个录入流水号(按理流水号应该只能是数字字符组成) ,然后根据前缀+流水号生成一个序号。
比如前缀lot,流水号是0000
那么要生成lot0000、lot0001这样的序号(后一个是前一个的数字加1)
杯具在于没有规定前缀可以录几个字符,是不是可以录入数字,以及是怎么组合的;还有个杯具的是平台封装的文本框不支持正则表达式设置隐藏码,于是就可能流水号会录入非数字字符;于是就出现了杯具的形如前缀为lot00,流水号0000,那我怎么去判断lot000000是不是前缀lot,流水号000000?
最后处理为前缀必须为字符结尾或者干脆前缀为空:"(?<prefix>[\D*|\d*]*[\D]+)*(?<lotTrailNo>[0-9]+) "
posted @ 2010-08-21 09:31 山伟 阅读(56) 评论(1)
编辑