MENU

使用WinForm实现无边框窗口

February 2, 2014 • 程序

虽说新项目还没有提上议程,甚至第一次策划会议也一直没有召开,但是准备工作多多少少是有一点点了。项目难度最大的,就是开发桌面应用程序。这几乎是一个大家都没有多少了解的问题,所以下手比较困难。2013年初我们从TFDi Design处采购了smartCARS,同年7月Hans使用Visual Basic .Net开发了iTracker 2.0,这大概是我们选用.Net的原因吧。

2013年底(真正的年底),我开始使用Visual Studio 2013了。与Hans,不一样的是,我使用的是C#。我长期使用各种类C的程序语言,所以C#很快就能上手了。期间写过一些测试性的东西,写过一个即时通讯(上一篇日志提到过,服务端使用PHP with Swoole Extension)。VS的控件样式实话实说是很难看的;较新的VS,提供一些Flat的属性,磕磕巴巴地出来一些效果。如下图:

当然,我要寻求更好的解决方案。我找到了一篇文章Designing GitHub for Windows。自己向来非常认同GitHub的理念,便也想使用WPF尝试尝试。尝试的过程很艰辛,毕竟接触微软家的VS才一个月,Blend更是从来没有上过手。折腾了一个晚上,最后觉得太困难,还是暂时放弃了。我将目光转向WinForm。WinForm开发难度小得多,我刚开始使用VS便能顺利写出诸如“计算器”之类的小玩意儿;此时我甚至已有使用WinForm实现无边框窗口的想法。尝试了一下,确实可以。接下来我讲一讲我的做法。

首先,将窗口的FormBorderStyle设置为None。接着按照这个窗口的尺寸,制作一张图片;我使用窄的灰色阴影打底,并将其余部分透明处理;图片保存为png,并将窗口的BackgroundImage设置为背景图片。我们还需要写窗口的MouseDown、MouseMove事件,参考代码如下:

/**
 *这一部分是用来处理对窗口的拖动操作的
 *由于没有边框,我们需要来实现这个功能
 */
int oldX, oldY;//定义当前类的两个属性,下面会用到
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        this.oldX = e.Location.X;
        this.oldY = e.Location.Y;
    }
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        this.Left += e.Location.X - this.oldX;
        this.Top += e.Location.Y - this.oldY;
    }
}

接着是绘制右上角最小化、关闭等按键的图案。这些我都是基于GitHub for Windows设计的,所以最小化、关闭共需要绘制五个图片:灰色的各两个、白色的各两个、最小化还需要一张黑色的。这两个按钮还是使用按钮控件,然后将Image属性设为灰色图片就好。还需要注意一下,FlatAppearance里的MouseDownBackColor、MouseOverBackColor都需要调整好,来达到我们所需的效果。这些按钮的Click、MouseEnter和MouseLeave事件也需要写。参考代码如下:

/**
 *说明:closeBtn为关闭、minBtn为小化;
 *各个事件对应的方法应该是一目了然的。
 */
private void closeBtn_Click(object sender, EventArgs e)
{
    Application.Exit();//关闭程序
}
/**
 *我将所需图片都导入项目资源中
 *解决方案名称为TestApp
 */
private void closeBtn_MouseLeave(object sender, EventArgs e)
{
    closeBtn.Image = TestApp.Properties.Resources.close_btn_gray;//更换图片,下同
}
private void closeBtn_MouseEnter(object sender, EventArgs e)
{
    closeBtn.Image = TestApp.Properties.Resources.close_btn_white;
}
private void minBtn_Click(object sender, EventArgs e)
{
    this.WindowState = FormWindowState.Minimized;//最小化窗口
}
private void minBtn_MouseEnter(object sender, EventArgs e)
{
    minBtn.Image = TestApp.Properties.Resources.min_btn_black;
}
private void minBtn_MouseLeave(object sender, EventArgs e)
{
    minBtn.Image = TestApp.Properties.Resources.min_btn_gray;
}
private void minBtn_MouseDown(object sender, MouseEventArgs e)
{
    minBtn.Image = TestApp.Properties.Resources.min_btn_white;
}

这样一来就完成了,我们来看看最终效果。截图时,鼠标已在minBtn上按下(即调用minBtn_MouseDown方法)(VS上的东西不要在意)。

update: 最后再总结一下WinForm和WPF实现的区别:WPF是使用xaml标记语言、DirectX进行绘制的,都是矢量输出,可以根据显示器大小调整;WinForm是根据像素大小确定的,不管在什么显示器上都是占用这么大的像素面积。(但是我自己想,使用图片实现,性能可能高一些吧?)WPF实现同样也需要写窗口移动,按钮点击等事件;但鼠标进入、鼠标按下等都可以使用VisualStateManager来简化了(我是一直没弄懂怎么处理)。

Tags: c#
Archives Tip
QR Code for this page
Tipping QR Code