WindowsPhone开发之简略画图板的实现

WindowsPhone开发之简单画图板的实现

这两天在摸索WindowsPhone应用程序的开发,实现了一个简单的画图板应用程序和一个简单的手机端与电脑端的通信应用程序。今晚先总结一下自己实现的画图板,画图板能够实现基本的画直线,矩形,三角形和圆形,废话少说,先上图,下面是实现的画图板的截图:


WindowsPhone开发之简略画图板的实现
 

首先是在Visual Studio2010中新建一个WindowsPhone应用程序项目,按照以前Java实现画图板的思路,首先是在界面上显示几个按钮和一个面板。在WindowsPhone中组件的添加和android中是差不多,都是以类似于XML标签的形式添加的,然后可以设置各个标签的属性值。在我的程序中是添加四个按钮和一个面板,具体的代码(MainPage.xaml文件)如下:

<phone:PhoneApplicationPage 
    x:Class="Drawer.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <!--LayoutRoot 是包含所有页面内容的根网格-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel 包含应用程序的名称和页标题-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="我的画图板" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="画图" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - 在此处放置其他内容-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="120"/>
                <ColumnDefinition Width="100"/>
                <ColumnDefinition Width="100"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Button Name="save" HorizontalAlignment="Stretch" Content="长方形" 
                    Height="80" Background="Blue"  FontFamily="Arial" FontSize="20" 
                    Margin="-6,1,1,1" />
            <Button Grid.Column="1" Name="reck" Content="直线" FontFamily="Arial" FontSize="20"
                    Height="80" Background="Blue" Margin="0,1" HorizontalAlignment="Right" Width="100" />
            <Button Grid.Column="2" Name="line" HorizontalAlignment="Stretch" Content="圆形" 
                    Height="81" Background="Blue"  FontFamily="Arial" FontSize="20" 
                    Margin="1,1,5,0" />
            <Button Grid.Column="3" Name="rect" HorizontalAlignment="Stretch" Content="三角形" 
                    Height="80" Background="Blue"  FontFamily="Arial" FontSize="20" 
                    Margin="1,1,1,1" />
        </Grid>
        <Grid Grid.Row="2">
            <Canvas Name="canvas" Background="White">
                
            </Canvas>
        </Grid>
        
    </Grid>
</phone:PhoneApplicationPage>

 

需要注意的一点是<Grid.RowDefinitions></Grid.RowDefinitions>标签之间添加一行<RowDefinition Height="Auto" />,意思就是在原有界面上在划分出一行,因为原先刚创建工程时,界面上默认的只划分两行,同样可以以同样的方式添加更多的行。在一行中要定义列的话,是在<Grid.ColumnDefinitions></Grid.ColumnDefinitions>这一对标签之间添加,用<ColumnDefinition/>标签。

 

然后是要给各个组件添加监听器,添加监听器有两种方式,一种是以标签属性的方式添加的,就像写JS中的事件处理一样。另外一种是在MainPage.g.i.cs文件的public void InitializeComponent() 方法中添加,我的程序中是用到这一种方式的,添加的方式如下所示:

//给各个按钮添加点击事件监听器,监听器的方法:onButtonClick()
            this.save.Click += new RoutedEventHandler(this.onButtonClick);
            this.reck.Click += new RoutedEventHandler(this.onButtonClick);
            this.line.Click += new RoutedEventHandler(this.onButtonClick);
            this.rect.Click += new RoutedEventHandler(this.onButtonClick);
            //给Canvas添加鼠标左键按下和松开事件监听器,方法分别为:mouseLeftEnter()和mouseLeftUp()
            this.canvas.MouseLeftButtonDown += new MouseButtonEventHandler(this.mouseLeftEnter);
            this.canvas.MouseLeftButtonUp += new MouseButtonEventHandler(this.mouseLeftUp);

 以第二种方式添加监听器的时候,我发现了一个奇怪的现象:在添加保存之后关闭工程再重新打开,发现MainPage.g.i.cs文件中添加的代码不见,但是还是能够响应事件的发生,但是在不知道修改什么东西情况下,再运行程序,就不能够响应事件的发生了。可以能如MainPage.g.i.cs文件开头的注释所说:“对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。”为了稳妥方便些,建议还是以第一种方式添加监听器。

 

如上面加监听器所示的代码,在MainPage.xaml.cs文件中定义的方法如下:

//画图起始点的坐标
        private double x1, x2, y1, y2;
        //形状的类型
        private String shapetype = "reck";
        
        // 构造函数
        public MainPage()
        {
            InitializeComponent();
        }

        //按下鼠标左键
        public void mouseLeftEnter(object sender, MouseButtonEventArgs e)
        {
            Point p = e.GetPosition(this.canvas);
            x1 = p.X;
            y1 = p.Y;
            //System.Windows.MessageBox.Show("x1:"+x1+"<>"+"y1:"+y1, "友情提示", MessageBoxButton.OK);
        }

        //松开鼠标左键得到坐标
        public void mouseLeftUp(object sender, MouseButtonEventArgs e) 
        {
            Point p = e.GetPosition(this.canvas);
            x2 = p.X;
            y2 = p.Y;

            if (shapetype.Equals("reck"))
            {
                //画直线
                Line line = new Line();

                line.Stroke = new SolidColorBrush(Colors.Blue);
                line.StrokeThickness = 5;
                line.X1 = x1;
                line.Y1 = y1;
                line.X2 = x2;
                line.Y2 = y2;

                this.canvas.Children.Add(line);
            }
            else if (shapetype.Equals("save"))
            {
                //画长方形
                Line line1 = new Line();
                Line line2 = new Line();
                Line line3 = new Line();
                Line line4 = new Line();
                line1.Stroke = new SolidColorBrush(Colors.Blue);
                line1.StrokeThickness = 5;
                line2.Stroke = new SolidColorBrush(Colors.Blue);
                line2.StrokeThickness = 5;
                line3.Stroke = new SolidColorBrush(Colors.Blue);
                line3.StrokeThickness = 5;
                line4.Stroke = new SolidColorBrush(Colors.Blue);
                line4.StrokeThickness = 5;

                line1.X1 = Math.Min(x1, x2);
                line1.Y1 = Math.Min(y1, y2);
                line1.X2 = Math.Max(x1, x2);
                line1.Y2 = Math.Min(y1, y2);

                line2.X1 = Math.Min(x1, x2);
                line2.Y1 = Math.Min(y1, y2);
                line2.X2 = Math.Min(x1, x2);
                line2.Y2 = Math.Max(y1, y2);

                line3.X1 = Math.Min(x1, x2);
                line3.Y1 = Math.Max(y1, y2);
                line3.X2 = Math.Max(x1, x2);
                line3.Y2 = Math.Max(y1, y2);

                line4.X1 = Math.Max(x1, x2);
                line4.Y1 = Math.Min(y1, y2);
                line4.X2 = Math.Max(x1, x2);
                line4.Y2 = Math.Max(y1, y2);

                this.canvas.Children.Add(line1);
                this.canvas.Children.Add(line2);
                this.canvas.Children.Add(line3);
                this.canvas.Children.Add(line4);
            }
            else if (shapetype.Equals("line"))
            {
                //画圆形
                Ellipse ellipse = new Ellipse();
                ellipse.Stroke = new SolidColorBrush(Colors.Blue);
                ellipse.StrokeThickness = 5;
                ellipse.Height = x1;
                ellipse.Width = y1;
                this.canvas.Children.Add(ellipse);
            }
            else if (shapetype.Equals("rect"))
            {
                //画三角形
                Line line1 = new Line();
                Line line2 = new Line();
                Line line3 = new Line();
                line1.Stroke = new SolidColorBrush(Colors.Blue);
                line1.StrokeThickness = 5;
                line2.Stroke = new SolidColorBrush(Colors.Blue);
                line2.StrokeThickness = 5;
                line3.Stroke = new SolidColorBrush(Colors.Blue);
                line3.StrokeThickness = 5;

                line1.X1 = Math.Min(x1, x2);
                line1.Y1 = Math.Max(y1, y2);
                line1.X2 = Math.Max(x1, x2);
                line1.Y2 = Math.Max(y1, y2);

                line2.X1 = Math.Max(x1, x2);
                line2.Y1 = Math.Max(y1, y2);
                line2.X2 = (x1 + x2) / 2;
                line2.Y2 = Math.Min(y1, y2);

                line3.X1 = Math.Min(x1, x2);
                line3.Y1 = Math.Max(y1, y2);
                line3.X2 = (x1 + x2) / 2;
                line3.Y2 = Math.Min(y1, y2);

                this.canvas.Children.Add(line1);
                this.canvas.Children.Add(line2);
                this.canvas.Children.Add(line3);
            }
            else
            {
                System.Windows.MessageBox.Show("其他形状还没实现", "友情提示", MessageBoxButton.OK);
            }

           //System.Windows.MessageBox.Show("x2:" + x2 + "<>" + "y2:" + y2, "友情提示", MessageBoxButton.OK);
        }
        
        //监听save按钮
        public void onButtonClick(object sender, RoutedEventArgs e)
        {
            shapetype = ((Button)sender).Name;
            System.Windows.MessageBox.Show(shapetype, "友情提示", MessageBoxButton.OK);
        }

 

在定义监听的方法时,需要注意的是方法名可以任意取,但是方法的参数要根据各种不同的监听情况传入。画各种形状时,不像Java中直接取得Graphic对象,然后画各种形状,也不像C#中可以通过createGraphic方法取得Graphic。在WindowsPhone中没有Graphic的对象,画各种二维图形很不方便,它是通过创建Line对象(直线)或者Ellipse对象(椭圆)等等,然后设置各种形状的值,最后把各种形状对象当做Canvas的子节点一样通过Canvas的Children对象的Add()方法添加到Canvas对象中,这样子画各种形状很没有灵活性。所以在我的程序中无法弄一个颜色选择器让用户选择颜色,只能在代码里面设置图形的颜色,线条的粗细,画的矩形是通过同时创建四个Line对象实现的,三角形也一样通过创建三个Line对象实现。而椭圆没有达到自己想要的效果,每次画出的椭圆都是和左边,上边的边相切的。在我查资料中发现有些人通过一个与平台无关的类库(PS:一下子记不起来了)取得Graphic2D对象就可以很方便的画出各种形状来。好了,现总结到这里吧。