11.4.2 在照片浏览器中缓存值

来源:互联网 发布:c语言中>> 编辑:程序博客网 时间:2024/06/05 11:42
11.4.2 在照片浏览器中缓存值



    在下一个示例中,我们要写一个应用程序,找出指定文件夹中的所有照片,并显示为一个列表。当用户选择一张照片,应用程序调整它的大小,并显示在一个窗口中。(为了简便起见,我们不会允许用户调整窗口大小)。当我们画了这张照片时,需要调整其大小以适合屏幕,然后,显示调整大小后的图像。

    很明显,我们不想在应用程序启动时调整所有照片的大小:对于大型的照片集,需要花大量的时间。我们也不想在每次我们画出来时,调整照片的大小,因为,这会一次又一次调整相同照片的大小。从说明来看,相当明显,延迟值可以帮助我们。我们将演示如何在 F# 中写这个应用程序,你可以在本书的网站上找到对应的 C# 版本。



使用延迟值缓存



    这个应用程序最有趣的部分是,应用程序启动时,代码已执行。它在指定的目录中找到所有文件,并用每个文件的信息创建一个数组。信息包含文件名,和为了调整 preview 大小计算的延迟值。清单 11.21 显示了如何创建此数据结构。



Listing 11.21 Creating a collection of photo information (F#)



open System.IO
open System.Drawing

type ImageInfo = { Name : string; Preview : Lazy<Bitmap> }

let dir = @"C:\My Photos"
let createLazyResized(file) =
  lazy( use bmp = Bitmap.FromFile(file)  
          let resized = new Bitmap(400, 300)
          use gr = Graphics.FromImage(resized)

          let dst = Rectangle(0, 0, 400, 300)
          let src = Rectangle(0, 0, bmp.Width, bmp.Height)
          gr.InterpolationMode <- Drawing2D.InterpolationMode.High
          gr.DrawImage(bmp, dst, src, GraphicsUnit.Pixel)
          resized)

let files =
  Directory.GetFiles(dir, "*.jpg") |> Array.map (fun file –>;
    { Name = Path.GetFileName(file)
       Preview = createLazyResized(file) })



    我们首先声明一个记录类型,表示有关照片的信息。可以看到,preview 的类型是 Lazy<Bitmap>,这是一个延迟计算,在我们需要它时,会给我们一个位图(Bitmap)。接下来,我们实现一个函数,返回表示已调整大小的位图的延迟值。要绘制 preview ,我们写了常规代码,调整位图对象,并把整个函数体使用 lazy 关键字打包起来。

    接下来,我们创建包含照片有关信息的数据结构。使用通常的 .NET 法调用获得一个文件数组,并使用 Array.map 函数,为每张照片创建一个  ImageInfo 值。在这个 lambda 函数的内部,创建一个记录值,包含名字,和由 createLazyResized 函数返回的延迟 preview。

    这个程序的一个有趣属性是,我们可以删除所有使用 lazy 的关键字,把所有类型从Lazy<'T> 改为 'T,删除所有使用的 Value 属性,代码会仍正常工作,只是所有都会提前计算。



实现用户界面



现在,我们已经有了有关这些照片所需要的所有数据,下面,就使用 Windows 窗体可以添加一个简单的 GUI。在清单 11.22 中,我们将创建几个控件以显示数据和代码,显示选定的照片。



Listing 11.22 Adding a user interface for the photo browser (F#)



open System
open System.Windows.Forms

let main = new Form(Text="Photos", ClientSize=Size(600,300))
let pict = new PictureBox(Dock=DockStyle.Fill)
let list = new ListBox(Dock=DockStyle.Left,  
                               DataSource=files,
                               DisplayMember = "Name")
list.SelectedIndexChanged.Add(fun _ –>;;
  let info = files.[list.SelectedIndex]
  pict.Image <- info.Preview.Value)
main.Controls.Add(pict)
main.Controls.Add(list)

[<STAThread>]
do Application.Run(main)



    为显示 ListBox(列表框)控件中的图片列表,我们使用了数据绑定,这是一个可用于很多 .NET 控件的功能。我们只是指定控件的数据源(DataSource)是文件的数组。若要指定如何显示内容,可以设置 DataMember 属性,为想要显示的记录成员的名字(Name)。

    接下来,我们注册一个 lambda 函数,作为列表框的 SelectedIndexChanged 事件的处理程序。当它被触发后,我们选择 ImageInfo 值,并使用 Value 属性来获取已调整大小的位图。如果该位图是第一次显示,将在这里重新调整大小;如果之前已经浏览过,可以立即使用缓存中的结果。清单 11.22 显示的代码,是一个独立的应用程序,这意味着,我们用 Application.Run() 方法来运行。在 F# Interactive 中,可以使用 main.Show () 来显示窗体。可以看到,应用程序的外观如图 11.2。



图 11.2 照片可以从左侧的列表中选择。由于使用了延迟值,调整大小后的版本被自动缓存。



    如果运行这个应用程序,使用的文件夹中包含大型图片的话,由于使用延迟所带来的差别是明显的。选择"新"照片可能需要一些时间,但是如果你重新浏览已经看过的照片,它会立即呈现。



注意



    你可能想知道,我们是否可以使用多线程来改进这个应用程序。有两个地方使用多线程是有帮助的。首先,当用户选择文件时,可以开始计算,而不要阻止用户界面。目前,应用程序是被冻结的,直到图像调整大小之后。为此,我们可以使用异步编程技术,如 F# 异步工作流,在第 13 章中会讨论。

    另一个可能性是,应用程序可以在背景中预先调整位图的大小。不是什么也不做,提前调整某些图版的大小,使用户当单击照片时不必等待。在第 14 章,我们将看到,这是相当简单的,Task<T> 类型,就像 Lazy<T> 一样,除了它不延迟以外,另外,它在后台线程计算值。



    我们确信对于在 C# 中如何使用 Lazy<T> 类,实现相同的应用程序,你已经有了一个很好的概念,所以,我们不会在本书中讨论。可以在这本书的网站找到应用程序的源代码。在 C# 版本中,一个很有趣的地方是,可以使用 C# 3.0 的匿名类型来表示照片的信息,如果写的的代码在一个单独的方法内。



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 ae中没有mpg格式怎么办 淘宝小二处理不公怎么办 遇到卖保险的人怎么办 租房合同没理家电清单怎么办 普雪油烟机坏了怎么办 我累了 真的累了怎么办 u盘15g变成4g了怎么办 属兔的买了东户怎么办 玩时时彩输了2万怎么办 胸变的又软又小怎么办 u盘16g变成4g了怎么办 1岁宝宝吃了就吐怎么办 脚崴了肿了很痛怎么办 九格拼图5在9那怎么办 4s锁屏密码忘了怎么办 6p触屏偶尔乱跳怎么办 新办劳务公司的劳务资质怎么办 汽车没电了打不着火怎么办 吃凉的甜的牙疼怎么办 学车对点对不上怎么办 发现老公有外遇最明智的怎么办 想开个童装店但是没经验怎么办 母乳不够吃宝宝又不喝奶粉怎么办 掉头发很厉害怎么办有什么偏方 红米2a刷死机了怎么办 公司退市我们买的股票怎么办 黑魂3把npc杀了怎么办 摔倒了膝盖摔肿了又痛怎么办 厕所堵了怎么办疏通马桶有妙招 月经不来怎么办如何让它快点来 苹果手机进水了开不了机怎么办 苹果5s进水了怎么办修要多少钱 吃了过期3年的药怎么办 离婚后孩子的抚养费不给怎么办 小车钥匙丢了怎么办配要多少钱 一键启动的车钥匙丢了怎么办 股票退市了手里的股票怎么办 3d硬金以后要换怎么办 偏指甲红肿长在了肉里怎么办 牙齿黄怎么办教你牙齿美白小窍门 2岁孩门牙磕断了怎么办