posts - 21,  comments - 60,  trackbacks - 3
  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(500500);
 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, 00);
 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(00225);
 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(001525);
 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(001525);
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 * 100);
116                 cr.Rectangle(00825);
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(001525);
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(001525);
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 * 100);
146                 cr.Rectangle(00825);
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(001525);
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(001525);
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(00225);
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) 编辑
  2006年2月22日
同一个局域网内A、B、C三台机器,均安装.net 1.1和2.0
其中A安装有SQL Server 2K,B和C都没有安装SQL Server 2K,但C安装有SQL Server 2005 Express
同样的程序,.net 1.1编译后在A、B、C运行都能访问A机器的SQL Server 2K
.net 2.0编译后,在A中能访问SQL Server 2K,在B中不能,C中却可以
请问哪位大侠遇到过这种情况?该怎么做才能使B中的程序也能访问A的SQL Server 2K

2006-2-23:
刚做完测试,问题解决了,是端口问题,狂郁闷啊!
想当年学Oracle的时候客户端也总是连不上服务器,郁闷了好几天最后把防火墙关掉就好使了,类似的问题这次却没想到。
不过还是有些不明白为什么1.1编译的程序为什么可以在不打开端口的情况下访问数据库。
posted @ 2006-02-22 13:19 山伟 阅读(269) 评论(2) 编辑
  2006年1月1日
      好久没在园子里发过帖子了,2006年的第一天本该回首05年的点滴、展望未来的,无奈总结从圣诞夜就开始写到现在都没写完。 
      最近在看Bill Wagner的《Effectie C#》,本来想把书中提到的50条提高效率的方法逐一翻译出来也写成一系列博客,后来在MSDN看到李建忠的《Effective C#》 翻译札记,知道他在翻译这本书,于是我也就不再献丑了,只写一些体会吧。

      Item 1: Always Use Properties Instand of Accessbile Data Members
      Item 2: Prefer readonly to const

      关于第一条李建忠已经有很好的说明了,但我在这里想说的却是如果一开始用一个public字段而以后发现有必要改成属性的时候带来的麻烦。
      Effective C#更多的是以大型的组件式的开发为讨论基础的,所以往往是很多模块的,你在一个DLL里定义的public字段如果改成属性,那么所有使用这个DLL的模块都得重新编译一次才行(public字段和属性编译成IL后的代码就不再贴出来了,有兴趣的朋友可以自己尝试一下),而如果一开始就使用属性,那么只要重新编译一次修改的DLL就可以了。孰优孰劣,不同的情景要进行不同的权衡。
      关于第二条,就会提到一件令我汗颜很久的事。学C那会儿,声明一个常量数组是很方便的,到C#后发现用private const int[] m=new int[] {10, 20, 30};是编译不过去的,后来想想也就明白为什么了,因为数组是按引用类型处理的,而const却只能用在一些简单类型上,比如int、float、enums、string等简单数据上,引用类型是不行的。但怎么去声明一个只读的数组我却很久没有解决,直到看了Effective C#,也很简单的,就是用readonly来做(汗颜啊)。
      这里要说的也和第一条类似,在一个DLL里定义一个类:
1public class UsefulValues
2{
3    public static readonly int StartValue = 5;
4    public const int EndValue = 10;
5}
     然后在另一个程序集里去使用这些数据:
1for(int i = UsefulValues.StartValue; i < UsefulValues.EndValue; i++)
2    Console.WriteLine("value is {0}", i);
得到的结果是
      value is 5
      value is 6
      ……
      value is 9

      好,现在把UsefulValues里的数据改一下,StartValue=105,EndValue = 120,然后重新编译这个DLL,然后再运行一下第二个程序集,你希望的结果是
      value is 105
      value is 106
      ……
      value is 119
      但结果呢,你什么输出也没得到。还是看IL代码,会发现在第二个程序集里EndValue是被替换成10了,这是编译时的行为,而如果用readonly来定义的只读值却是在运行时才确定是哪个值的。

      Effective C#很多时候都考虑到发生改变的情况,正如李建忠所说,如果是一个“一次编写、N年都run”的项目,这些规则其实并不是一定要遵守的。还是那句话,权衡很重要。
posted @ 2006-01-01 12:10 山伟 阅读(633) 评论(1) 编辑
  2005年11月18日
摘要: 现在手头做的工作是给一家公司做奖金结算系统,之前也是有个程序员做的(我也纳闷儿,怎么现在做的都是别人失败了才让我做),在用他的程序计算了两个月左右的时候发现总出计算错误,然后这家公司让我做。用我的计算了这么长时间了,也没出过什么问题,前天忽然说因为前面的出错的已经都发出去了,和现在数据库里的数据不一致,要把数据库里的数据改过来(现在终于明白了什么情况下错的也要当成正确的)。我一看不能让用我程序的文...阅读全文
posted @ 2005-11-18 07:08 山伟 阅读(339) 评论(2) 编辑
  2005年11月2日
摘要: 因为要给师弟们讲课,我写了异型窗体制作(两种方法) 这篇博客。后来有个师弟说他把我的代码修改成了一个组件,想把这个组件拖拽到窗体里,经过简单设置就能实现不规则窗体,但是没有成功。经过实验,我这里重新把原来的代码整理了一下,下面这个组件CusomForm编译后就可以使用,拖拽到窗体后需要设置ParentForm、BackImage、TranTransparentColor三个属性,并且不用再写代码处...阅读全文
posted @ 2005-11-02 13:04 山伟 阅读(1133) 评论(4) 编辑
  2005年11月1日
摘要: 有memberinfo和updatelog两个表,通过memberinfo的memberid和updatelog的memberid对两个表进行关联,memberinfo纪录会员基本信息,updatelog纪录会员的升级信息。 memberinfo数据如下 memberid star 001 1 002 1 003 2 updatelog数据如下 memberid endstar update...阅读全文
posted @ 2005-11-01 12:56 山伟 阅读(415) 评论(7) 编辑
  2005年10月24日
摘要: 因为要做一个类似Windows Update的东西,以免程序更新时跑来跑去麻烦,虽然类似的工具很多,但是大都很复杂,于是决定自己做一个类似的简单程序。 对比客户端和服务器端的程序版本,并把服务器端新版本程序拷回来都好做(用VPN,相当于局域网内文件复制),但是安装新版本程序就有问题了,因为Windows Installer安装程序时如果发现有以前的版本就会要求你自己删除旧版程序后再重新安装,但我要...阅读全文
posted @ 2005-10-24 21:44 山伟 阅读(1278) 评论(2) 编辑
<2012年2月>
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910

昵称:山伟
园龄:6年10个月
粉丝:0
关注:0

搜索

 
 

常用链接

随笔分类(19)

随笔档案(21)

最新评论

阅读排行榜

评论排行榜

推荐排行榜