[工具]类QQ消息通知,提示博客园发布新文章(三)——有码
引言
不管在公司,还是在路上,听到最多的就是抢票俩字,搞的我不淡定了,心浮躁了......
不管怎样,今天还是将这个小工具,搞出来了,或许会有bug,没测试。
效果图
1.恶搞一下,此窗口为,在未抓取到内容时,一个gif的图片,为loading.gif 至于怎么动,下载源码,看看就知道了。
2.今天真巧,刚加载一篇文章,就看到一个妹子的头像,这是不是代表.... 窗体是半透明状态,标题过长,截取放在两个LinkLabel控件上,简介内容是一个textBox控件,其他的用到的控件头像picturebox,label等
3.单击链接,打开默认浏览器,跳转该文章内容。如图所示。并且,有最新文章时,出发托盘点击事件,弹出窗口。
遇到的问题
1.原来设计的时候,考虑放在一个list集合中,发现并不需要,只是取出第一条信息,再放在集合中,再从集合中取数据,绕了一圈,麻烦。最后,取出第一条,break跳出。
2.在设计如何当前数据是最新的,通过重写Blog实体类的Equals方法,比较所有的属性值是否相同。
3.事件注册时机,这个错误有点sb,竟然将注册事件,放在了timer_Tick(object sender, EventArgs e)这个事件方法中,最后结果可想而知,每10s注册一次,当你撒泡尿回来的时候,你单击一次,发现,电脑直接崩溃了。那是,你单击一次,打开了n多个页面。这低级错误,真sb
4.在提示最新数据,弹出窗口设计逻辑时,有时会出现,博客园第一篇文章和排名第二篇的文章,来回切换的情况,这个bug正在查找。
有码
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.IO; 7 using System.Linq; 8 using System.Net; 9 using System.Runtime.InteropServices; 10 using System.Text; 11 using System.Text.RegularExpressions; 12 using System.Threading.Tasks; 13 using System.Windows.Forms; 14 15 namespace Wolfy.Cnblogs 16 { 17 public partial class MainForm : Form 18 { 19 public MainForm() 20 { 21 InitializeComponent(); 22 } 23 private event GetBlogsEventHandler GetBlogs; 24 log4net.ILog myLogger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 25 Timer timer = null; 26 Blog preBlog = null;//用来存上一篇博客信息 27 Blog currentBlog = null;//当前博客信息 28 29 private void MainForm_Load(object sender, EventArgs e) 30 { 31 string exePath = AppDomain.CurrentDomain.BaseDirectory; 32 string rootPath = exePath.Substring(0, exePath.IndexOf("bin")); 33 pbLoading.ImageLocation = Path.Combine(rootPath, "Image/loading.gif");//当在未读到数据时 加载一张图片 遮盖 34 pbLoading.SizeMode = PictureBoxSizeMode.Zoom; 35 pbLoading.Width = this.panelContent.Width; 36 pbLoading.Height = this.panelContent.Height; 37 this.Opacity = 0.8d; 38 this.BackColor = Color.Green; 39 this.txtContent.BackColor = Color.Green; 40 //确定窗体位置 右下角 41 Rectangle rectangle = Screen.GetWorkingArea(this); 42 this.Location = new Point(rectangle.Right - this.Width, rectangle.Bottom - this.Height); 43 panelContent.MouseDown += panelContent_MouseDown; 44 linkLabelTitle.Focus(); 45 GetBlogs += MainForm_GetBlogs;//注册事件 46 linkLabelBreakWord.LinkClicked += linkLabelTitle_LinkClicked;//窗体加载时 注册链接单击事件 47 linkLabelTitle.LinkClicked += linkLabelTitle_LinkClicked; 48 timer = new Timer();//定时器 每十秒 抓去一次博客园文章 49 timer.Interval = 10000; 50 timer.Start(); 51 timer.Tick += timer_Tick; 52 } 53 54 void MainForm_GetBlogs(object sender, GetBlogsEventArgs e) 55 { 56 if (e != null) 57 { 58 currentBlog = e.Blog; 59 60 //判断如果当前的博客 和上一篇博客不同 则提示 61 if (preBlog != null && !preBlog.Equals(currentBlog)) 62 { 63 notifyIconCnblogs_Click(this, new GetBlogsEventArgs(currentBlog)); 64 } 65 Send(currentBlog); 66 } 67 } 68 private void Send(Blog blog) 69 { 70 //头像地址 71 pbHeader.ImageLocation = string.IsNullOrEmpty(blog.Header) ? "" : blog.Header.Trim(); 72 linkLabelTitle.Text = blog.Title.Length >= 23 ? blog.Title.Substring(0, 23) : blog.Title;//达到换行的目的 用两个linklabel 73 linkLabelBreakWord.Text = blog.Title.Length >= 23 ? blog.Title.Substring(23) : ""; 74 linkLabelBreakWord.Visible = blog.Title.Length >= 23 ? true : false; 75 linkLabelBreakWord.VisitedLinkColor = Color.Red; 76 linkLabelBreakWord.Tag = blog.Url; 77 78 linkLabelTitle.VisitedLinkColor = Color.Red; 79 linkLabelTitle.Tag = blog.Url;//存放url 80 txtContent.Text = string.IsNullOrEmpty(blog.Content) ? "" : blog.Content.Trim(); 81 82 lblAuthor.Text = blog.Author; 83 lblDate.Text = blog.Time.ToString("yyyy-MM-dd hh:mm"); 84 preBlog = blog;//显示后将词条信息 保存为上条 85 86 } 87 void linkLabelTitle_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 88 { 89 LinkLabel link = sender as LinkLabel; 90 System.Diagnostics.Process.Start("explorer.exe", link.Tag.ToString()); 91 } 92 93 private void timer_Tick(object sender, EventArgs e) 94 { 95 try 96 { 97 WebClient client = new WebClient(); 98 byte[] buffer = client.DownloadData("http://www.cnblogs.com/"); 99 //博客园采用的是utf-8 否则会出现乱码 100 string html = Encoding.UTF8.GetString(buffer, 0, buffer.Length); 101 //cnblog简单正则表达式 102 string regex = "<div\\s*class=\"post_item\">\\s*.*\\s*.*\\s*.*\\s*.*\\s*.*\\s*.*\\s*.*\\s*<div\\s*class=\"post_item_body\">\\s*<h3><a\\s*class=\"titlelnk\"\\s*href=\"(?<href>.*)\"\\s*target=\"_blank\">(?<title>.*)</a>.*\\s*<p\\s*class=\"post_item_summary\">\\s*(?<content>.*)\\s*</p>\\s*<div\\s*class=\"post_item_foot\">\\s*<a\\s*href=\".+?\"\\s*class=\"lightblue\">(?<author>.+?)</a>\\s*发布于\\s*(?<time>\\d{4}\\-\\d{2}\\-\\d{2}\\s*\\d{2}:\\d{2})"; 103 //过滤有标签的content内容 将头像src和内容过滤出来 104 string regex2 = "<a\\s+href=\"http://.+?\"\\s*target=\"_blank\"><img\\s*width=\"48\"\\s*height=\"48\"\\s*class=\"pfs\"\\s* src=\"(?<imgSrc>.+?)\".+?/></a>(?<content>.+)\\s*"; 105 MatchCollection matches = Regex.Matches(html, regex, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant); 106 107 foreach (Match match in matches) 108 { 109 if (match.Success) 110 { 111 112 Blog blog = new Blog(); 113 blog.Url = match.Groups["href"].Value; 114 blog.Title = match.Groups["title"].Value; 115 //其中content中 如果用户有头像 则content包含img标签 116 blog.Content = match.Groups["content"].Value; 117 Match m = Regex.Match(blog.Content, regex2); 118 if (m.Success) 119 { 120 if (!string.IsNullOrEmpty(m.Groups["imgSrc"].Value)) 121 { 122 blog.Header = m.Groups["imgSrc"].Value; 123 } 124 blog.Content = m.Groups["content"].Value; 125 } 126 blog.Author = match.Groups["author"].Value; 127 blog.Time = Convert.ToDateTime(match.Groups["time"].Value); 128 if (blog != null) 129 { 130 this.pbLoading.Visible = false; 131 this.pbLoading.Dispose(); 132 this.GetBlogs(this, new GetBlogsEventArgs(blog)); 133 break; 134 } 135 } 136 } 137 } 138 catch (Exception ex) 139 { 140 //MessageBox.Show(ex.Message); 141 myLogger.Error("错误信息", ex); 142 } 143 } 144 void panelContent_MouseDown(object sender, MouseEventArgs e) 145 { 146 //扑捉事件 147 WindowsHelper.ReleaseCapture(); 148 //发送消息给window Api 来实现 149 WindowsHelper.SendMessage(this.Handle, WindowsHelper.WM_SYSCOMMAND, WindowsHelper.SC_MOVE + WindowsHelper.HTCAPTION, 0);// 150 } 151 152 private void lblClose_Click(object sender, EventArgs e) 153 { 154 this.Hide(); 155 this.notifyIconCnblogs.Visible = true; 156 } 157 158 private void notifyIconCnblogs_Click(object sender, EventArgs e) 159 { 160 this.Visible = true; 161 this.WindowState = FormWindowState.Normal; 162 this.notifyIconCnblogs.Visible = true; 163 } 164 165 private void menuItem_Hide_Click(object sender, EventArgs e) 166 { 167 this.Hide(); 168 this.notifyIconCnblogs.Visible = true; 169 } 170 171 private void menuItem_Show_Click(object sender, EventArgs e) 172 { 173 this.Visible = true; 174 this.WindowState = FormWindowState.Normal; 175 this.notifyIconCnblogs.Visible = true; 176 } 177 178 private void menuItem_Aubot_Click(object sender, EventArgs e) 179 { 180 MessageBox.Show("博客园最新博客提示工具"); 181 } 182 183 private void menuItem_Exit_Click(object sender, EventArgs e) 184 { 185 this.Close(); 186 this.timer.Dispose(); 187 this.Dispose(); 188 } 189 } 190 }
1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Wolfy.Cnblogs 9 { 10 public class Blog 11 { 12 /// <summary> 13 /// 文章地址 14 /// </summary> 15 public string Url { set; get; } 16 /// <summary> 17 /// 文章标题 18 /// </summary> 19 public string Title { get; set; } 20 /// <summary> 21 /// 文章简介 22 /// </summary> 23 public string Content { set; get; } 24 /// <summary> 25 /// 头像地址 26 /// </summary> 27 public string Header { set; get; } 28 /// <summary> 29 /// 作者 30 /// </summary> 31 public string Author { set; get; } 32 /// <summary> 33 /// 发布时间 34 /// </summary> 35 public DateTime Time { set; get; } 36 /// <summary> 37 /// 比较是否相等 38 /// </summary> 39 /// <param name="obj"></param> 40 /// <returns></returns> 41 public override bool Equals(object obj) 42 { 43 Blog blog = obj as Blog; 44 return this.Url == blog.Url && this.Title == blog.Title && this.Content == blog.Content && this.Header == blog.Header && this.Author == blog.Author && this.Time == blog.Time; 45 } 46 47 48 } 49 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Runtime.InteropServices; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Wolfy.Cnblogs 9 { 10 public static class WindowsHelper 11 { 12 [DllImport("user32.dll")] 13 //方法扑捉 14 public static extern bool ReleaseCapture(); 15 [DllImport("user32.dll")] 16 public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); 17 public const int WM_SYSCOMMAND = 0x0112; 18 public const int SC_MOVE = 0xF010; 19 public const int HTCAPTION = 0x0002; 20 } 21 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Wolfy.Cnblogs 8 { 9 /// <summary> 10 /// 自定义事件参数类 11 /// </summary> 12 public class GetBlogsEventArgs : EventArgs 13 { 14 private Blog blog; 15 16 public Blog Blog 17 { 18 get { return blog; } 19 set { blog = value; } 20 } 21 public GetBlogsEventArgs(Blog blog) 22 { 23 this.blog = blog; 24 } 25 } 26 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Wolfy.Cnblogs 8 { 9 public delegate void GetBlogsEventHandler(object sender, GetBlogsEventArgs e); 10 }
无码下载:链接:http://pan.baidu.com/s/1eQrdEwi 密码:8z4e
总结
做一个小工具,只是觉得好玩,可能因为太懒了,不想每次都打开浏览器,在公司逛博客园,打开个浏览器,网速太卡了,另外是因为大屏幕,被发现,虽然老大不说,总觉得.....
虽然用的东西不是多深奥的技术,一个小工具,功能多强大,就说明这个程序员有多懒,如果功能还不够强大,只是懒的不够厉害。
写的过程中,有考虑用观察者模式的,唉,太懒了,不想写那么多类。典型的观察者模式......
文章写到最后,有个新文章,弹出来了,截图记录一下:
晒一下自己的,文章。
-
博客地址:http://www.cnblogs.com/wolf-sun/
博客版权:如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步! 再次感谢您耐心的读完本篇文章。