• 跟我做WinForm开发


    2012-01-07 12:03 by 空逸云, 3710 visits, 收藏编辑

    前言

    前阵子,学英文的时候听发音,意外之中发现Google的发音相比大部分TTS发音更准确,而且读句子也没有普通TTS那种一听就是机器人的声音,心血来潮,想利用Google发音做一个小软件,所以就有了本文。

    image

    这是最后的UI成品图,可以看到,没有了常见的按钮,也没有了常见的Title框,整个布局随心所欲,GDI+?No。下面,就带大家跟我一起来用最简单的方式开发你所期望的UI吧!

    自定义窗体

    WinForm开发中,我们都知道窗体和控件的作用,实际上,以上的UI实现也是通过自定义窗体和用户控件实现,那该如何做,才能让窗体变成我们所想要的样子呢?

    首先,新建一个窗体,在这里,我命名为MainForm.cs,打开我们就可以见到以往的样子:

    imageimage

    选中窗体,右键=》属性,将FormBorderStyle设置成None, 窗体就变成了右图所示;接着,我再将其拖拉成我需要的长度和宽度,此时若编译运行,会发现实际上什么都东西都看不到,这正是我们所需要的效果,接着,就防止我们想呈现的元素。接着,我将其拉成一个长方形,并在四周放4个PictureBox,正中间放一个Panel。

    image

    这里需要注意的就是4个PictureBox的宽度,长度和未知,实际上我也不是拖控件,而是通过修改控件是属性,这里就需要精确到像素,聪明的你应该想到它们就是4条边框线和中间的内容块了,在这里我推荐一个软件,MarkMan,传说中的标注神器,做UI方面,特别是开发人员,很有帮助。

    image

    在将所需的图片填充上去就可以了。

    private Image GetResourceImg(string name)
    {
        return Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(name));
    }
    
    void InitFormStyle()
    {
        //边框
        var borderImg = GetResourceImg(@"Speaker.Resource.Images.border.jpg");
        Bitmap borderMap = new Bitmap(borderImg);
        borderMap.MakeTransparent(Color.FromArgb(255, 0, 255));
        this.pb_borderLeft.BackgroundImage = borderMap;
        this.pb_borderRight.BackgroundImage = borderMap;
        this.pb_borderTop.BackgroundImage = borderMap;
        this.pb_borderBottom.BackgroundImage = borderMap;
        //主面板
        var mainImg = GetResourceImg(@"Speaker.Resource.Images.main.jpg");
        this.pl_main.BackgroundImage = new Bitmap(mainImg);
        //Logo
        var logoImg = GetResourceImg(@"Speaker.Resource.Images.logo.jpg");
        this.btn_setting.NormalImage = new Bitmap(logoImg);
        btn_setting.Reset();
        //Speak Button
        var normalImg = GetResourceImg(@"Speaker.Resource.Images.button.png");
        var moveImg = GetResourceImg(@"Speaker.Resource.Images.buttonMove.png");
        var downImg = GetResourceImg(@"Speaker.Resource.Images.buttonDown.png");
        btn_speak.NormalImage = normalImg;
        btn_speak.MoveImage = moveImg;
        btn_speak.DownImage = downImg;
        btn_speak.Reset();
    }
    

    编译通过之后,边框雏形就出现了~:-)

    自定义控件

    窗体我们已经有了,接下来就是里面一些控件的实现,这里,我主要用到了两个控件,ImageButton和LightTextBox,顾名思义,ImageButton就是一个图片按钮,但它还提供鼠标按下,悬移时的图片选择;LightTextBox是一个TextBox,鼠标悬移的时候,边框高亮;

    LightTextBox

    新建用户控件LightTextBox,选中控件,右键=》属性,将BorderStyle改为None,这样,控件也不可见了!拖出一个TextBox,并标注为MultiLine,至此,UI就这样了,接着是控件的绘制编码;

    public LightTextBox()
    {
        SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
        InitializeComponent();
        BackColor = Color.Transparent;
        
        txt.Location = new Point(3, 6);
        txt.MouseEnter += new EventHandler(txt_MouseEnter);
        txt.MouseLeave += new EventHandler(txt_MouseLeave);
    }
    

    实现TextBox的鼠标悬移事件就是为了实现边框高亮效果;

    #region Events
    
    void txt_MouseLeave(object sender, EventArgs e)
    {
        _isFouse = false;
        this.Invalidate();
    }
    
    void txt_MouseEnter(object sender, EventArgs e)
    {
        _isFouse = true;
        this.Invalidate();
    }
    #endregion
    

    方法部分(控件实现的主要方法)

    #region Methods
    protected override void OnPaint(PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        g.SmoothingMode = SmoothingMode.HighQuality;
    
        txt.Width = Width-6;
        CalculateSizeAndPosition();
        Draw(e.ClipRectangle, e.Graphics);
    
    
        base.OnPaint(e);
    }
    
    private void CalculateSizeAndPosition()
    {
        if (!txt.Multiline)
        {
            Height = txt.Height + 9;
        }
        else
        {
            txt.Height = Height - 9;
        }
    }
    private void Draw(Rectangle rectangle, Graphics g)
    {
    
        #region 画背景
        using (SolidBrush backgroundBrush = new SolidBrush(Color.White))
        {
            g.FillRectangle(backgroundBrush, 2, 2, this.Width - 4, this.Height - 4);
        }
        #endregion
    
        #region 画阴影(外边框)
    
        Color drawShadowColor = _shadowColor;
        if (!_isFouse)    //判断是否获得焦点
        {
            drawShadowColor = Color.Transparent;
        }
        using (Pen shadowPen = new Pen(drawShadowColor))
        {
            if (_radius == 0)
            {
                g.DrawRectangle(shadowPen, new Rectangle(rectangle.X, rectangle.Y, rectangle.Width - 1, rectangle.Height - 1));
            }
            else
            {
                g.DrawPath(shadowPen, DrawHelper.DrawRoundRect(rectangle.X, rectangle.Y, rectangle.Width - 2, rectangle.Height - 1, _radius));
            }
        }
        #endregion
    
        #region 画边框
        using (Pen borderPen = new Pen(_borderColor))
        {
            if (_radius == 0)
            {
                g.DrawRectangle(borderPen, new Rectangle(rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 3, rectangle.Height - 3));
            }
            else
            {
                g.DrawPath(borderPen, DrawHelper.DrawRoundRect(rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 3, rectangle.Height - 2, _radius));
            }
        }
        #endregion
    }
    
    #endregion
    

    由于字段,属性比较多,我就不贴出来了,感兴趣的可以在后续的源码中查看;此时,若将该控件放到窗体中,鼠标移

    动上去,则可发现边框有一层光晕;

    ImageButton

    这里的自定义控件实现方式一致,都先去掉了BorderStyle,再自己控制呈现内容,所以才能达到显示特殊UI的目的;ImageButton的UI设计就不详述了,直接放出后台实现主代码;

    public ImageButton()
    {
        this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
        InitializeComponent();
        Reset();
    }
    
    #region Methods
    public void Reset()
    {
        if (_normalImage != null)
        {
            this.BackgroundImage = _normalImage;
            this.Size = new Size(_normalImage.Width, _normalImage.Height);
        }
    }
    private void MakeTransparent(Image image)
    {
        Bitmap bitmap = image as Bitmap;
        bitmap.MakeTransparent(Color.FromArgb(255, 0, 255));
    }
    #endregion
    
    private void ImageButton_MouseEnter(object sender, EventArgs e)
    {
        if (_moveImage != null)
            this.BackgroundImage = _moveImage;
    }
    
    private void ImageButton_MouseLeave(object sender, EventArgs e)
    {
        this.BackgroundImage = _normalImage;
    }
    
    private void ImageButton_MouseDown(object sender, MouseEventArgs e)
    {
        if (_downImage != null)
            this.BackgroundImage = _downImage;
    }
    
    private void ImageButton_MouseUp(object sender, MouseEventArgs e)
    {
        if (_moveImage != null)
            this.BackgroundImage = _moveImage;
    }
    

    MainForm

    万事俱备,只欠东风;把控件都放入MainForm中,并初始其状态即可(上面第一部分代码已放出);此时,编译运行;已达到我们预期的UI效果;但是,UI效果是有了,移动效果,缩小(点击任务栏图标)等却都失效了,该怎么办?Win32API千呼万唤使出来~

    private void pl_main_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            Win32.ReleaseCapture();
            Win32.SendMessage(Handle, 274, 61440 + 9, 0);
        }
    }
    

    这里实际上是调用了Win32API,在这里,又有一个好东西分享;平时做这些Win32API交互/C#与C++交互,需

    要做类型转换,特别是C++里面一些指针什么的,很是纠结,http://clrinterop.codeplex.com能帮到你;它能根据你输入的C++函数生成C#的代码;不可谓不是一大杀器啊!

    移动解决了,那缩小的问题,也必须解决了;

    protected override CreateParams CreateParams
    {
        get
        {
            const int WS_MINIMIZEBOX = 0x00020000;  // Winuser.h中定义
            CreateParams cp = base.CreateParams;
            cp.Style = cp.Style | WS_MINIMIZEBOX;   // 允许最小化操作  
            return cp;
        }
    }
    

    重写CreateParams属性就可以了;到这里,我们的应用已经能正常显示出我们所想要的UI;但还不够,大部

    分辅助类型的软件都有最小化的功能,那,我们也将其加上去吧;

    NotifyIcon

    这个其实很简单,就是拖一个NotifyIcon到窗体中,并绑定一个ContextMenu到这个NotifyIcon中就可以了;然后在触发一些事件;

    private void MainForm_Resize(object sender, EventArgs e)
    {
        if (WindowState == FormWindowState.Minimized)
        {
            this.Visible = false;
        }
    }
    

    后面,我还主要用NotifyIcon来通知用户,做提示,错误提示等;到这里,整个UI方面就已经完成了;只

    剩下后面的逻辑处理,就是输入句子能发音,并且支持快捷键屏幕取词等;

    随笔分类 -C#

    计算一个数字有多少种排列可能

    2012-02-03 09:14 by 空逸云, 613 visits, 网摘收藏编辑
     

    跟我做WinForm开发(2)-后台逻辑操作

    2012-01-08 12:32 by 空逸云, 2495 visits, 网摘收藏编辑
     

    跟我做WinForm开发(1)-自定义UI

    2012-01-07 12:03 by 空逸云, 3711 visits, 网摘收藏编辑
     

    细说文件读写操作(读写锁)

    2011-11-15 00:20 by 空逸云, 1580 visits, 网摘收藏编辑
     

    您真的了解类型转换吗?请止步,解惑!

    2011-08-29 00:11 by 空逸云, 1888 visits, 网摘收藏编辑
     

    您真的了解类型转换吗?请止步,求解!

    2011-08-24 23:57 by 空逸云, 3744 visits, 网摘收藏编辑
     

    基于AppDomain的"插件式"开发

    2011-08-01 09:58 by 空逸云, 1921 visits, 网摘收藏编辑
     

    青梅煮酒论C#:Specification pattern

    2011-01-16 13:56 by 空逸云, 1757 visits, 网摘收藏编辑
     

    你正确的使用Out/Ref了吗?

    2010-12-03 19:19 by 空逸云, 379 visits, 网摘收藏编辑
     

    【More Effective C#】Partial Class是怎样炼成的?

    2010-10-28 08:14 by 空逸云, 1949 visits, 网摘收藏编辑
     

    【More Effective C#】掩藏在Nullable<T>后的秘密

    2010-10-27 08:19 by 空逸云, 1780 visits, 网摘收藏编辑
     

    【More Effective C#】IEnumerable和IQueryable的那点事

    2010-10-22 08:08 by 空逸云, 2145 visits, 网摘收藏编辑
     

    【More Effective C#】区分早期执行和晚期执行

    2010-10-20 08:19 by 空逸云, 1739 visits, 网摘收藏编辑
     

    【More Effective C#】Lambda表达式优化

    2010-10-19 08:09 by 空逸云, 2673 visits, 网摘收藏编辑
     

    【More Effective C#】LINQ表达式与方法调用的映射

    2010-10-15 08:05 by 空逸云, 411 visits, 网摘收藏编辑
     

    【More Effective C#】延迟求值

    2010-10-14 18:30 by 空逸云, 416 visits, 网摘收藏编辑
     

    【More Effective C#】仅声明非虚的事件

    2010-10-13 08:17 by 空逸云, 178 visits, 网摘收藏编辑
     

    【More Effective C#】扩展方法

    更多资料

    跟我学做c#皮肤美化

    WinAPI使用大全

    跟我做WinForm开发(2)-后台逻辑操作

    作者:空逸云
    出处:http://kongyiyun.cnblogs.com 
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    本来一行可以代替的树节点搜索
    mssql 重新开始标识
    TabContainer实现服务器端回传
    CSS中图片路径的问题
    Javascript在IE下设置innerHTML时出现"未知的运行时错误"
    sql union和union all的用法及效率
    关于动态添加TabPanel遇到的问题以及思考
    关于linq to sql调用存储过程,出现"无法枚举查询结果多次"的问题
    SQL Server 2005连接服务器时的26号错误解决!
    SQL 2000和2005 获取两表的差集
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2337170.html
Copyright © 2020-2023  润新知