基础08-用户界面在这一章我们将学习程序员最重要任务之一把像素放到屏幕上艺术_第1页
基础08-用户界面在这一章我们将学习程序员最重要任务之一把像素放到屏幕上艺术_第2页
基础08-用户界面在这一章我们将学习程序员最重要任务之一把像素放到屏幕上艺术_第3页
基础08-用户界面在这一章我们将学习程序员最重要任务之一把像素放到屏幕上艺术_第4页
基础08-用户界面在这一章我们将学习程序员最重要任务之一把像素放到屏幕上艺术_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

,在这一章,学习程序员最重要的任务之一:把像素放到屏幕上艺术。在F#中,所要API.NET平台,就更加多样。第一个户;还是想创建应用程序,应用程序的界面用HTML定义,然后,通过浏览器渲染。.NET创建桌面应用程序,可以有四种选择:WinForms、WindowsPresentationFoundation(WPF,[原文这里有笔误])、GTK#和DirectX。在这一章学习WinForms、WPF和GTK#,但不包括DirectX。WinForms、WPF和GTK#对窗口和控件有基本相同的隐喻,(metaphors)[不懂说的是什么]。WinForms最古老也最简单,我们已经遇到过几个WinForms的示例了;WPFWinForms稍微复杂一些,但是,也更一致,提供了的功能包括令人印象深刻的3D图形;GTK#提供了比其他两个库更好的平台。MonoWinForms可以运行在所有平台上,MonoGTK#运行在非Windows平台。DirectX3D图形的游戏制造商;WPF[]提供了更简单的产生3D图形的方法,因此,本书不讨论DirectX。要创建应用程序,可以使用ASP.NET框架,它提供了简单的方法创建基于服务器的、动态HTML的应用程序。ASP.NET提供了灵活的方式产生HTML,以响应来自浏览器的HTML请求。近年来,应用程序已经有了极大地进步,因此,ASP.NET平台的进步也毫示用F#生成HTML的基础知识。介绍WinForms是包含在System.Drawing.dll和System.Forms.Windows.dll的类,编译所有的WinForms都需要添加对它们的。这个库是基于System.Windows.Forms.Form类的,它必须创建一个事件循环(eventloop,它可以保证用户响应与窗口的交互;通过调用System.Windows.Application.Runopenopen//createanewletform=newForm(BackColor=Color.Purple,Text="Introducing//showtheform[1、需要2、交互运行用以下]F#fsifsifsiShowVisibletrue。看下openopenWinForms,有两种可选的方案:自己画窗体,或者使用控件构建。下面我们首先看一Windows自己画窗体,就要负责把像素表示到屏幕上。这种低级方法对许多F#用户仍有,因为他们相信许多WinForms库中控件不可能非常适合显示一些数据结构,或函数和算法的为了画WinForm,需要将事件处理程序附加到窗体或控件的Paint事件上。就是说,每次WindowsGraphics,它包含一个类的实例,也叫Graphics,这个类的方法(如DrawLine)可以在窗体上绘制像letform//createanewformsettingtheminimumlettemp=newForm(MinimumSize=newSize(96,//repainttheformwhenitisresizetemp.Resize.Add(fun_->temp.Invalidate())//abrushtoprovidetheshapescolorletbrush=newSolidBrush(Color.Red)temp.Paint.Add(fune->//calculatethewidthandheightoftheletwidth,height=temp.Width-64,temp.Height-//drawtherequirede.Graphics.FillPie(brush,32,16,width,height,0,//returntheformtothetoplevel//8-18-1.自己,这是通过把事件处理函数附加到Resize事件实现的。在这个函数中,调用窗体的Invalidate方法,告诉窗体需要重画自己。Tree类型,在下面的代码中定义,显示结果如图8-2。//Thetreetypetype'aTree=|Nodeof'aTree*'a|Leafof//Thedefinitionofthetreelettree=LeafNode(Leaf"two",Leaf"three")),Node(Leaf"four",Leaf"five"),Leaf"six"))8-2.可以用8-1的代码画出这个树8-1画树openopenopen//Thetreetypetype'aTree=|Nodeof'aTree*'a|Leafof//Thedefinitionoftheteelettree=LeafNode(Leaf"two",Leaf"three")),Node(Leaf"four",Leaf"five"),Leaf"six"))//AfunctionforfindingtheumdepthofatreeletgetDeptht=letrecgetDepthInnertd=matchtwith|Node(l,r)->(getDepthInnerld+1.0F)(getDepthInnerrd+|Leafx->dgetDepthInnert0.0F//Constantsrequiredfordrawingtheformletbrush=newSolidBrush(Color.Black)letpen=newPen(Color.Black)letfont=newFont(FontFamily.GenericSerif,//ausefulfunctionforcalculatingtheum//ofnodesatanygivendepthletraise2ToPower(x:float32)=Convert.ToSingle(Math.Pow(2.0,letdrawTree(g:Graphics)t//constantsthatrelatetothesizeand//oftheletcenter=g.ClipBounds.Width/letmaxWidth=32.0F*raise2ToPower(getDepth//functionfordrawingaleafletdrawLeaf(x:float32)(y:float32)v=letvalue=sprintf"%A"vletl=g.MeasureString(value,g.DrawString(value,font,brush,x-(l.Width/2.0F),//drawaconnectorbetweenthenodeswhennecessaryletconnectNodes(x:float32)yp=matchp|Some(px,py)->g.DrawLine(pen,px,py,x,|None->//themainfunctiontowalkthetreestructuredrawing//nodesasweletrecdrawTreeInnertdwp=letx=center-(maxWidth*w)lety=d*32.0FconnectNodesxypmatchtwith|Node(l,r)-g.FillPie(brush,x-3.0F,y-3.0F,7.0F,7.0F,0.0F,letd=(d+drawTreeInnerld(w+(1.0F/d))(Some(x,y))drawTreeInnerrd(w-(1.0F/d))(Some(x,|Leafv->drawLeafxyvdrawTreeInnert0.0F0.0FNone//createtheformobjectletform=lettemp=newForm(WindowState= temp.Resize.Add(fun_->temp.Invalidate())(fune->e.Graphics.Clip<-newRegion(newRectangle(0,0,temp.Width,temp.Height))drawTreee.Graphicstree)letdrawTree(g:Graphics)tWinFormGraphics对象和需要画的数据类型,为了实现drawTree,首先计算出这个函数的两个常量center和maxWidth。不能在函数drawTree的外边看到这些常量这样在函数drawTree的而不必须作为参数来传//constantsthatrelatetothesizeand//oftheletcenter=g.ClipBounds.Width/letmaxWidth=32.0F*raise2ToPower(getDepthdrawLeaf//functionfordrawingaleafletdrawLeaf(x:float32)(y:float32)v=letvalue=any_to_stringvletl=g.MeasureString(value,g.DrawString(value,font,brush,x-(l.Width/2.0F),connectNodes//drawaconnectorbetweenthenodeswhennecessaryletconnectNodes(x:float32)yp=matchp|Some(px,py)->g.DrawLine(pen,px,py,x,|None->drawTreeInnerTree//themainfunctiontowalkthetreestructuredrawing//nodesasweletrecdrawTreeInnertdwpletx=center-(maxWidth*w)lety=d*32.0FconnectNodesxypmatchtwith|Node(l,r)-letd=(d+drawTreeInnerld(w+(1.0F/d))(Some(x,y))drawTreeInnerrd(w-(1.0F/d))(Some(x,|Leafv->drawLeafxy86F#代码,就提供了数就会迅速膨胀,规则出所有的几何图形是非常耗时的。为了有效地控制复杂性,F#可以WinFormSystem.Drawing.dllSystem.Drawing命名空GraphicsDraw或Fill的方法。表8-1中汇总了Graphics对象的方法。8-1System.Drawing.Graphics第二个需要关注的部分是与System.Drawing.Graphics对象密切相关的System.Drawing的GraphicsIconImagePenBrush对象。表8-2展示了如何通过各自的构造函数创建这些对象。8-2System.Drawing.Graphics创建一个新的genericserif字体、 点newnewnew 如果你喜欢使用标准对象,可以使用System.Drawing命名空间中的几个类,它预定义了一openletmyPen=letmyFont=WinFormSystem.Windows.Forms.Control,由此类派生出的任何类都能显示在窗体上,只要将它添加到窗体对象的Controls集合中。现在我们看一下用控件画树形的方法。WinFormsTreeView类,这是专门用于显Nodes集合中。这个控件准备好以后,就可以将它添加到窗体的Controls集合。历树形结构,创建TreeNode图形。8-2中的程序产生图8-3的树。8-2用控件TreeView画树open//Thetreetypetype'aTree=|Nodeof'aTree*'a|Leafof//Thedefinitionofthetreelettree=LeafNode(Leaf"two",Leaf"three")),Node(Leaf"four",Leaf"five"),Leaf"six"))//AfunctiontotransformourtreeintoatreeofcontrolsletmapTreeToTreeNodet=letrecmapTreeToTreeNodeInnert(node:TreeNode)=matchtwith|Node(l,r)-letnewNode=newTreeNode("Node")node.Nodes.Add(newNode)|>ignoremapTreeToTreeNodeInnerlnewNodemapTreeToTreeNodeInnerrnewNode|Leafx-node.Nodes.Add(newTreeNode(sprintf"%A"x))|>ignoreletroot=newTreeNode("Root")mapTreeToTreeNodeInnertroot//createtheformobjectletform=lettemp=newlettreeView=newTreeView(Dock=DockStyle.Fill)treeView.Nodes.Add(mapTreeToTreeNodetree)|>ignore8-3.TreeView在这个例子中,使用“停靠(Dock)Dock属性为一个DockStyle枚举值。停靠的控件能更可能占用窗体上的可用空间,如果使用DckStyle.RigtDockStyleop;TopLeft属性控制其布局。用Anchor属性可以创建动态效果,把控件锚定(anchor)在窗体的边缘。下面的例子创建openopenletform//createalettemp=new//createatextboxandsetitslettextBox=newTextBox(Top=8,Left=8,Width=temp.Width-30,Height=temp.Height-52,Anchor=(AnchorStyles.Left|||AnchorStyles.Right|||AnchorStyles.Top|||//addthetextboxtotheformandreturntheformdo[]容易出错。为了解决这种问题,VisualStudio提供了窗体设计器,可以可视化地创建窗体。F#F#C#设对于WinForm的程序员,使用控件的一个在于,如何从众多控件中进行选择。在这一章中,我们只讨论了一个控件。然而,说到学习,没有什么可以取代经验。MSDN 8-3WinForm通常,大多数其他控制应附带Label,以说明其用途。LabelText&,会使其后的一个字母有下划默认情况下文本框是单行,如果将Multiline属性设置为trueWordWrapScrollBar属性;如果想让文本框中显示的文本可以、粘贴,可以通过设置ReadOnly属性实现。Label控件一按钮的Text属性的文本中加&,使其后的一个字母有下划线,通过按键可以跳到此按钮,方法是按Alt+<字这个控件的名字有点误导,它不像,而更像按钮,看起步讨论HTML文档,因为很多信息是以HTML把窗体分成不同的部分,配合HScrollBarVscrollBar水平滚动条,使Form或Panel容纳的信垂直滚动条,使Form或Panel容纳的信F#VisualStudio到现在,F.NET具有很强的互操作性,因此,很容F#VisualStudioF#库,Windows窗体中调用这个库中的函数;第二;创建一个窗体库,然后,在F#应用程序中使用。下面分别讨论这两种方法,并对比它们的优势与不足;示例都是计算斐波那契数列(Fibonacci,如图8-4。本书是有关F#的,对于主要素材,并不需要任何其他编程语言知识。然而,这一主程序。当然,如果你愿意,也很容易用VisualBasic.NET代码替换C#。8-4VisualStudio#.NET整数类型方面没有任何问题。为了让这个库更有效,还要创建一个斐波那契数列的延迟(lazy)列表,并定义一个函数,取第n个数:module//aninfinitesequenceofFibonaccinumbersletfibs=(0,1)|>Seq.unfold(fun(n0,n1)->Some(n0,(n1,n0+//afunctiontogetthenthfibonaccinumberletgetn=Seq.nthn[(0,1)|>(1,1)]很容易在窗体上使用这个函数,只需要在VisualStudio窗体项目中这个F#的.dll。如果是一个C#StrangelightsStrangelights.Fibonacci,这样Fibonacci就好像是C#中的一个类。下面的例子演示了如何在C#中调用这个函数,并把结果放到控件上。注意,因为这个窗体是用VisualStudio2005创建的,控件定义放在usingusingSystem.Windows.Forms;usingStrangelights;namespace{publicpartialclassFibForm:{public{}

privatevoidcalculate_Click(objectsender,EventArgs{//convertinputtoanintn=//caculatetheapropreatefibonaccinumbern=Fibonacci.get(n);//displayresulttouserresult.Text=n.ToString();}}}[]F#C#创建的窗体,需要把特定的控件公开为属性;并不需要公开所F#C#实现;另外,usingusingnamespace{publicpartialclassFibForm:{//publicconstructorfortheformpublicFibForm(){}//exposethecalculatebuttonpublicButtonCalculate{get{returncalculate;}//exposetheresultslabelpublicLabelResult{get{returnresult;}//exposetheinputstextboxpublicTextBoxInput{get{returninput;}}}后面的事情就很简单了,从F#中这个C#的.dll,创建窗体的实例,然后使用。下面openSystem.Windows.FormsopenStrangelights.Forms//aninfinitesequenceofFibonaccinumbersletfibs=(0,1)|>Seq.unfold(fun(n0,n1)->Some(n0,(n1,n0+//afunctiontogetthenthfibonaccinumberletgetFibn=Seq.nthnletform//createanewinstanceoftheformlettemp=newFibForm()//addaneventhandlertotheform'sclickevent(fun_-//convertinputtoanintegerletn=inttemp.Input.Text//caculatetheapropreatefibonaccinumberletn=getFibn//displayresulttousertemp.Result.Text<-stringn)C#F#C#一起。另外,在C#中使用一些F#类型是很,比如,联合类型。基于这两点,我通常是写一个C#库,供F#使用。在第十四章讨论写F#库供其他.NET语言使用。WinForms在第七章我们讨论过事件(Event)模块,它能够用于处理WinForms中的事件。当处理WinForms中的事件时,通常会遇到没有完全符合想要事件的情况。例如,当鼠标的左、右MouseButtonEvent.filter函数可能会很有用,用它创建一个新的事件,只响应鼠标左键的单击。看下openSystem.Windows.Formsletform=//createanewformlettemp=new//subscribethemouseclickeventfilteringsoit//reactstotheleftbutton|>Event.filter(fune->e.Button=|>Event.add(fun_->MessageBox.Show("Leftbutton")|>//returntheformfilterlisten函数,把事件处理程序加到事件中,[这一段应该是忘记改了,从程序来看,已经使用事件的add]Addif表达式来实现,8-3演示了如何使用几个事件函数创建一个简单的画图程序(8-。这里以另一种方式使用MouseDown事件:首先,用它来监视鼠标是否按下;然后,用分区函数8-3用事件实现一个简单的画图程序openopenopenletform//createthelettemp=newForm(Text="Scribble//somerefrencecellstoholdtheapplicationsstateletpointsMasterList=ref[]letpointsTempList=ref[]letmouseDown=reffalseletpen=ref(new//subscribetothemousedowneventtemp.MouseDown.Add(fun_->mouseDown:=true)//createaleftmousedownandrightmousedowneventsletleftMouse,rightMouse=|>Event.partition(fune->e.Button=//usethenewleftandrightmouseeventstochoosethecolorleftMouse.Add(fun_->pen:=newPen(Color.Black))rightMouse.Add(fun_->pen:=newPen(Color.Red))//themouseupeventhandlerletmouseUp_=mouseDown:=ifList.length!pointsTempList>1thenletpoints=List.toArray!pointsTempListpointsMasterList:=(!pen,points)::!pointsMasterListpointsTempList:=[]//themousemoveeventhandlerletmouseMove(e:MouseEventArgs)=pointsTempList:=e.Location::!pointsTempList//thepainteventletpaint(e:PaintEventArgs)ifList.length!pointsTempList>1then(!pen,List.toArray|>(fun(pen,points)->e.Graphics.DrawLines(pen,points))//wireuptheeventhandlerstemp.MouseUp|>Event.addmouseUp|>Event.filter(fun_->|>Event.addmouseMovetemp.Paint|>Event.addpaint//returntheformobjectdo8-5.另外程序员在处理Windows窗体事件时的一个很大的问题就是可用的事件的数量,这是很难选择的。可能非常奇怪,大多数事件都定义在控件(control)类中,只有么,它也可以在其他控件上使用。表8-4提供了Control类中的常见事件的汇总:8-4Control使用鼠标单击引起,当[焦点]在控件上时,也可能由按回车键或空Validated事件。在窗体类中这个事件被抑制,应该用Activated[Dectivate为了获得第一次按键的详细信息,使用KeyDown,当键释放时,用户移动控件时该事件该事件用于发现鼠标是否悬停控件上,能够给用户提供有关该当Windows刷新窗体时该事件。如果你想自己绘制控件,应该理这个事件。信息看本章前面的“画Windows窗体用户改变窗体大小时该事件。用于调整窗体的布局大小时应该到目前为止我们看到的程序还只是风格用现有的窗体和控件快速把窗体放在一起。.NET语言时,就会受到限制;在这些情况下,必须Windows窗体应用程序时,有一些窗体需要重复使用;此外,通常类,从System.Windows.Forms派生,来实现的。8-4就是这样一个例子,使用第五章8-4创建新的窗体类型openopen//aclassthatderivesfrom"Form"andaddsomeusercontrolstypeMyForm()asx=inheritForm(Width=174,//createsomecontrolstoaddtheletlabel=newLabel(Top=8,Left=8,Width=40,Text="Input:")lettextbox=newTextBox(Top=8,Left=48,Width=40)letbutton=newButton(Top=8,Left=96,Width=60,Text="Push//addaeventtothebuttondobutton.Click.Add(fun_-letform=newMyForm(Text=textbox.Text)//addthecontrolstotheformdox.Controls.Add(label)dox.Controls.Add(textbox)dox.Controls.Add(button)//exposethetextboxasapropertymemberx.Textbox=textbox//createannewinstanceofourformletform=lettemp=newMyForm(Text="MyForm")temp.Textbox.Text<-"Next!"do8-68-6.面的例子中,创建的窗体有三个字段:label、textboxbutton;然后,就可以用外部textboxTextMouseClick事件以创建LeftMouseClick:open//aformwithaddationLeftMouseClickeventtypeLeftClickForm()asx=inherit//createthenewletevent=new//wiretheneweventupsoitfireswhenthe//mousebuttonisclickeddox.MouseClick|>Event.filter(fune->e.Button=|>Event.add(fune->event.Trigger//exposetheeventaspropertymemberx.LeftMouseClick=。以这种基于组件(component-based)的方式创建的窗体,无疑要比以更化方式创建的窗体容易使用;但是,在创建用于其他.NET语言的窗体库时,仍有缺陷有关创建F#库用于其他.NET语言的内容,参考第十三章。。WindowsPresentationWPF是一个库,为开发用户界面提供了全新的模型,用它创建桌面的应用程序比使用Windows窗体更有优势;WPF还提供了新的基于XML的语言XAML,用于处理大量的窗体布局,而让F#专注于开发应用程序的感部分。(WYSWIG然后,用为其添加交互性。例如,Mobiform提供的设计器/eng/auroa.html,提供的设计器Expressionblend/defaut.msxWPF.NET3.0Vista,默认情况下已经安装;[Windows7及以上版本,.NET3.0.NETWPF;其他的Windows用户需要安装.NET3.0才能WPF,最好的方法是WindowsSDKforWindowsServer2008and.NETFramework3.5()。这一节中的示例需要以下的dll:PresentationCore.dll、PresentationFramework.dll和WindowsBase.dll。我们看到的第一个例子演示了如何用XAML创建一个简单窗体,然后用F#显示出来。示例显示了窗体XAML定义有四个控件:两个,一个文本框,一个按钮。8-5用XAML创建的简单窗体xmlns="/winfx/2006/xaml/presentation"xmlns:x="/winfx/2006/xaml"><ColumnDefinitionWidth="64"<ColumnDefinitionWidth="128"<ColumnDefinitionWidth="128"<ColumnDefinitionWidth="128"<RowDefinition<LabelGrid.Row="0"Grid.Column="0"<TextBoxName="input"Grid.Column="1"Text="o"<LabelName="output"Grid.Row="0"Grid.Column="2"<ButtonName="press"Grid.Column="3">Press使用窗体的XAML定义,需要做两件事情:第一,加载窗的定义并显示。但是,如果仅做F#为控件添加事件处理程序。在这里,我们为按钮添加事件处理程序,把文本框的内容显示到第二个中。函数createWindow是一个通用的函数,用于加载XAML窗体。用windowFindName方法,找出窗体中的控类的实例,并用它显示窗体(见8-8-6XAML窗体并为它添加事件处理程序openopenSystem.Collections.GenericopenSystem.WindowsopenSystem.Windows.ControlsopenSystem.Windows.MarkupopenSystem.Xml//createsthewindowandloadsthegivenXAMLfileintoitletcreateWindow(file:string)=using(XmlReader.Create(file))(funstream->(XamlReader.Load(stream):?>Window))//createthewindowobjectandaddevent//tothebuttoncontrolletwindow=lettemp=createWindow"..\..\Window1.xaml"letpress=temp.FindName("press"):?>Buttonlettextbox=temp.FindName("input"):?>TextBoxletlabel=temp.FindName("output"):?>Labelpress.Click.Add(fun_->label.Content<-textbox.Text)//runtheapplicationletmain()=letapp=newApplication()app.Run(window)|>ignoredomain()[前面,]为了编译这个程序,必须添加:PresentationCore.dllPresentationFramework.dll和WindowsBase.dll,它们通常在C:\ProgramFiles\Reference 编译器会自动库。图8-7是前面示例创建的窗体。8-7XAMLF#[第一步,创建一个Fsharp应用程序,把8-6的代码过去Window1.xaml,把清单8-5的代码过去;第三步,添加PresentationCore.dll、PresentationFramework.dll和WindowsBase.dll,还要加两个System.Xml.dll、System.Xaml.dll;Window1.xaml"..\..\Window1.xaml",]WindowsPresentationFoundationWPF的另一个巨大优势在于它提供了大量的控件,要深入探讨的一个控件是Viewport3DWindows窗体库中还没有。我displaya3Dplaneandthenmapanequationoverit.这个例子[见后面的8-7]首选有一个XAML。XAML和3D图形都是巨大的主己再专门研究这些下面的XAML描述了有一个控件Viewport3D的窗口这个脚道你正在看场景中的哪一个方向,这需要用到<Viewport3D.Camera>元素:<Model3DGroup>内描述了场景的外观,<AmbientLightColor="White"/>描述如何照亮场景,<GeometryModel3D.Geometry>描述场景中的三维形状。<MeshGeometry3D<MeshGeometry3DFXAML更容易实现。<GeometryModel3D.Material>标记描述形状的外观:>>AutoReverse="True"/>8-78-7定义三维场景的XAMLxmlns="xmlns:x="<Viewport3D<MeshGeometry3DAutoReverse="True"/>下面将用F#对8-7进行扩展,在8-8中,它借用了8-6中的函数。注意,8-7中的代码应该保存文件名为Window2.xaml。用createWindow函数加载窗口,用类型的主函数显示窗口;然后,用findMeshes函数找出图中所有网络(meshes,网络是用于描述三的一组点。通过在Viewport3D中遍历各种对象,找出网络,并建立一个//findsalltheMeshGeometry3Dinagiven3DviewportletfindMeshes(viewport:Viewport3D)=|>(function:?ModelVisual3Dasc->Some(c.Content)|_->|>(function:?Model3DGroupasmg->Some(mg.Children)|_->|>|>(function:?GeometryModel3Dasmg->Some(mg.Geometry)|_->|>(function:?MeshGeometry3Dasmv->Some(mv)|_->应该保持这个函数为泛型,它才能处理任意Viewport3D。我们很可能想三维场景中的所有XAMLF#F#以某种方式来网格;然后,用createPlaneItemList、createSquare、createPlanePoints、createIndicesPlaneaddPlaneToMeshmapPositionsCenterchangePositions,重复映射函数movingWaves,每秒钟穿过平面10次。这个函数的是从Point3D对象创建一个新的Point3Dcollection,老集合中的对象用函数movingWaves决定新的Z位置:letchangePositions()letdispatcherTimer=newDispatcherTimer()(fune-lett=(floatDateTime.Now.Millisecond)/2000.0letnewPositions=|>Seq.map(funposition->letz=movingWavestposition.Xposition.YnewPoint3D(position.X,position.Y,z))mesh.Positions<-newPoint3DCollection(newPositions))dispatcherTimer.Interval<-newTimeSpan(0,0,0,0,100)DispatcherTimer为创建平滑的动画效果,每秒钟至调用这个类10次(8-8是完整的示例。8-8显示三维场景Listing8-8.DisplayingandInteractingwitha3DXAMLSceneopenSystemopenSystem.IOopenopenSystem.Windows.MarkupopenSystem.Windows.MediaopenSystem.Windows.Threadingopen//createsthewindowandloadsthegivenXAMLfileintoitletcreateWindow(file:string)=(funstream->lettemp=XamlReader.Load(stream):?>Windowtemp.Height<-400.0temp.Width<-temp.Title<-"F#meetsXaml"//findsalltheMeshGeometry3Dinagiven3DviewportletfindMeshes(viewport:Viewport3D)=|>(function:?ModelVisual3Dasc->Some(c.Content)|_->|>(function:?Model3DGroupasmg->Some(mg.Children)|_->|>|>(function:?GeometryModel3Dasmg->Some(mg.Geometry)|_->|>(function:?MeshGeometry3Dasmv->Some(mv)|_->//loopfunctiontocreateallitemsnecessaryforaplaneletcreatePlaneItemListf(xRes:int)(yRes:int)=letlist=newList<_>()forx=0toxRes-1dofory=0toyRes-1doflistxy//functiontoinitializeapointletpointxy=newPoint(x,y)//functiontoinitializea"dletpoint3Dxy=newPoint3D(x,y,//createallthepointsnecessaryforasquareintheplaneletcreateSquaref(xStep:float)(yStep:float)(list:List<_>)(x:int)(y:int)=letx'=floatx*xSteplety'=floaty*yStepCHAPTER8USERINTERFACESlist.Add(fx'list.Add(f(x'+xStep)list.Add(f(x'+xStep)(y'+yStep))list.Add(f(x'+xStep)(y'+yStep))list.Add(fx'(y'+yStep))list.Add(fx'//createallitemsinaletcreatePlanePointsfxResyRes=letxStep=1.0/floatxResletyStep=1.0/floatcreatePlaneItemList(createSquarefxStepyStep)xRes//createthe3Dpositionsforaplane,i.e.,thethingthatsays//theplanewillbein3DletcreatePlanePositionsxResyResletlist=createPlanePointspoint3DxResyResnewPoint3DCollection(list)//createthetexturemapsforaplane,i.e.,thething//mapsthe2Dimagetothe3DplaneletcreatePlaneTexturesxResyRes=letlist=createPlanePointspointxResyResnewPointCollection(list)//createindiceslistforallourtrianglesletcreateIndicesPlanewidthheight=letlist=newSystem.Collections.Generic.List<int>()forindex=0towidth*height*6donew//centertheplaneinthefieldofletmapPositionsCenter(positions:Point3DCollection)=letnewPositions=|>Seq.map(funposition->newPoint3D((position.X-0.5)*-(position.Y-0.5)*-1.0,new//createaplaneandaddittothegivenletaddPlaneToMesh(mesh:MeshGeometry3D)xResyRes=mesh.Positions<-mapPositionsCentermesh.TriangleIndices<-createIndicesPlanexResyResletmovingWaves(t:float)xy=(Math.Cos((x+t)*Math.PI*4.0)/3.0)*(Math.Cos(y*Math.PI*2.0)/3.0)//createourletwindow=createWindowletmesh//grabthe3Dview//findallthemeshesandgetthefirstoneletmeshes=findMeshesviewportletmesh=Seq.head//addplanetothemeshaddPlaneToMeshmesh2020letchangePositions()letdispatcherTimer=newDispatcherTimer()(fune-lett=(floatDateTime.Now.Millisecond)/2000.0letnewPositions=|>Seq.map(funposition->letz=movingWavestposition.Xposition.YnewPoint3D(position.X,position.Y,z))mesh.Positions<-newPoint3DCollection(newPositions))dispatcherTimer.Interval<-newTimeSpan(0,0,0,0,100)letmain()letapp=newApplication()//showtheapp.Run(window)|>ignoredo[注:需要Fsharp.PowerPack.dll;注意一下路径的问题,加上..\..\;需要把一个图像文件venus.jpg也到.\bin\Debug\]8-88-12XAMLF#中运行了然后,以动态更改应于平面函。原始的有几要做小修改。首先,必以交互格l件:#r@"PresentationFramework.dll";;#r@"WindowsBase.dll";;#I@"C:\FSharp-\bin";;然后,把changePositions//mutablefunctionthatisusedwithinchangePositionsfunctionletmutablef=(fun(t:float)(x:float)(y:float)->0.0)//functionforchangingtheplaneovertimeletchangePositions()=letdispatcherTimer=newDispatcherTimer()(fune-lett=(floatDateTime.Now.Millisecond)/2000.0letnewPositions=|>Seq.map(funposition->letz=ftposition.Xmesh.Positions<-newPoint3DCollection(newPositions))dispatcherTimer.Interval<-newTimeSpan(0,0,0,0,100)最后,用.Show()方法显示窗口,不能用Application类的Run方法了。记设Topmost属性为true,这样,能够更方便与窗互,并看到结果//showthewindow,setitthetop,andactivatethefunctionthat//setitmovingchangePositions()最后[怎么又是最后,接下来,],需要定义一些函数来映射跨平面。它可以是任意函数,有三个浮点数的参数(第一个表示时间,后两个分别表示X、Y的座标,返回值也是浮点数,表示Z座标。我非常喜欢使用正弦和余弦函数,可以生成有趣的波形。下面的代码是letcosXY_xyMath.Cos(x*Math.PI)*Math.Cos(y*letmovingCosXY(t:float)xyMath.Cos((x+t)*Math.PI)*Math.Cos((y-t)*f<-8-98-19XAMLWPF框架包含大量的类型与控件值得程序员花时间去学习。幸运的是,互联网上有许多资源,比较好的站点有,NetFx3WPF(htt ),还有MSDN中的WPF GTK#Windows用户就可以跳过。]GTK#是对流行的跨平台图形用户界面库(GUI)GTK+的包装。如果打算构建一个本地应用Windows平台上,GTK可能是一个合理的选择。GTK#的运行类WindowsWPFGTK#Gtk.Window的,小插件(widgets,相当于控件)是基于Gtk.Widget类的。GTK#是随Mono项目一同发布的,因此,想使用它的最好方法是安装 /mono-downloads/download.htmlGTK#的类分成了四个部分:atk-sharp.dll、gdk-sharp.dll、glib-sharp.dllgtk-sharp.dll,要运行本节的示例,需要这些.dll。GTK#Application.Init()GTK环境进行初始化;在控件可()Application.Quit()关闭事件循环。在这个GTK#示(8-9)中,只有一个窗口因此当这个窗口关闭时,就可以退出GTK环境了://closetheeventloopwhenthewindowcloseswin.Destroyed.Add(fun_->Application.Quit())使用叫HBox或VBox的小插件来布局GTK#应用程序,这些小插件与Windows的类不8-9中,我们创建了一个VBox,表示其中的小插件是水平布局的://createanewvboxandaddthesubcontrolsletvbox=newVBox()8-9是完整的示例,代码的运行结果产生图像如图8-10所示。Listing8-9.ASimpleExampleofaGTK#ApplicationopenGtkletmain()//initalizetheGTKenvironment//createtheletwin=newWindow("GTK#andF#//setthewindowssizewin.Resize(400,400)//createaletlabel=new//createabuttonandsubscribe//itsclickedletbutton=newButton(Label="PressMe!")button.Clicked.Add(fun_->//createanewvboxandaddthesubcontrolsletvbox=newVBox()//addthevboxtothewindow//showthewindow//closetheeventloopwhenthewindowcloseswin.Destroyed.Add(fun_->Application.Quit())//starttheeventloopdo8-10LinuxGTKASP.NET2.0是打算用来简化创建页的技术,最简化的方法是通过实现接口IHttpHandlerHTTP请求。本章的下一节会解释具IHttpHandlerASP.NET2.0ASP.NET能够通过组WebHTML。这样做的好处是,程序员能够用HTML.aspx文件中。.aspx文件基本上只包含不出现在F#代码中的静态HTML,再加上动态控件的占位符。这种方法非常适合F#编程,因为表现窗体布局的代码和控制窗体行为的代码分开F#中看起来有点长;ASP.NETXMLweb.config使用ASP.NET也有,它需要配置服务器以承载ASP.NET应用程序。配置的差异取FileNewWebSiteC#VisualBasicNET写F项目到解决方案中,然后,手工修改解决方案文件,使它驻留在这个站点听起来有点烦具体做来很容易把.fsharpp文件到站点,.sln.fsharppbin子。这似乎有很多工作,但这之后你只需要按F5,项目就编译和运行,如果没有VisualStudio,最好的办法是选择用IIS承载。某些方面,比用VisualStudio承载更容易;但是,不方便的是,IIS需要编程结束,才能执行。为了用IIS承载代码,需要创建一个IIS的虚拟,有子bin;然后.aspx页面和web.config文件到这个虚拟。,ASP.NET.NET框架的一部分了,因此,完成示例的演示,不需要安装任何额外的功能;然而,这一节中的所有示例都需要System.Web.dll。创建要充分利用ASP.NET,最简单的方法是创建IHttpHandler。它是一个简单的接口,有两个成员。第一个成员是只读的布尔属性IsReusable,表示运行时是否可以重用这个对象的实例,通常最好将其设置为false。ProcessRequestweb请求时调用。它有一个参数,HttpContentRequestResponse属性响应请求。下面的IHttpHandler例子用简单的字符串"<h1>oWorld</h1>"响应请求:openSystem.Web//ahttphandlerclasstypeSimpleHandler()=//ltheASP.NETruntimeifthehandlercanbereusedmemberx.IsReusable=false//Themethodt

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论