Visual Basic项目开发案例精粹
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

第3章 电子相册

电子技术越来越发达,数码相机也越来越普及,和普通相册管理纸制照片一样,电子相册被用于管理数码照片。电子相册可以批量浏览数码照片,也可以自动或手动浏览单张照片,还可以方便地浏览不同文件下的照片,并能修改照片的名称等。本章要设计一个电子相册程序,可以实现上述数码照片管理功能。

3.1 需求分析

使用电子相册管理数码照片的主要目的就是能够对数码照片分类显示、修改名称、放大浏览和自动浏览等,本章设计的电子相册包括以下一些基本功能。

(1)打开电子相册时,自动显示默认地址路径下的照片。

(2)使用树形文件结构显示所有的照片分类文件夹。

(3)能够同时一页预览多张照片,并能通过翻页按钮预览其他页的照片。

(4)在预览照片时,双击其中任一照片即可放大浏览该照片,并将该照片的名称显示在标题栏上。

(5)双击放大浏览的照片可以返回照片预览界面。

(6)放大浏览照片时,可以设置自动浏览照片,也可以停止自动浏览照片。

(7)可以从移动存储器或磁盘上将照片导入到默认路径下。

(8)可以修改照片的名称。

(9)可以修改存放照片的文件夹名称。

(10)浏览照片时,具有上拉、下拉、左拉和右拉显示照片的效果。

(11)浏览照片时,具有左上拉、右上拉、左下拉和右下拉显示照片的效果。也可以选择普通浏览效果。图3-1为电子相册效果图。

图3-1 电子相册效果图

3.2 技术要点

本章使用ExplorerTree控件来设计的电子相册树形文件结构管理所有照片文件夹。ExplorerTree控件的使用方法和技术在第2章已经详细介绍过,本章会用到其中的部分内容。

照片预览功能是在同一页中使用小图片来显示多张照片,本章设计的电子相册将在一页显示6张照片,并且还能以大图片形式浏览单张照片。从本质上来讲,预览小图片和浏览大图片所使用的技术是一样的,都是使用Image控件实现的。

Image控件有个Stretch属性,该属性用于返回或设置是否调整图形大小,以适应Image控件的大小。Stretch属性的默认值是False,即需要调整Image控件大小,与图形大小相同。如果将Stretch属性设置为True,则需要调整图形大小,与Image控件大小相同。

因此,如果纯粹使用Stretch属性会产生两个问题。其一,设置Stretch属性值为False,那么Image控件为了和图形大小相同,可能会变得很大,这样在预览的时候就会有部分被遮挡。其二,设置Stretch属性值为True,那么图形为了和Image控件大小相同,可能会缩放,长宽变化比例不一致,导致照片变形失真。本章将使用Stretch属性,通过计算图形长宽比例,使得Image控件同比例缩放显示图形。设计思路是:先将Stretch属性设置为False,使Image控件与图形大小相同,确定长宽比例;再根据所得到的长宽比例同步缩放Image控件到期望的大小;再将Stretch属性设置为True,使图形大小适应Image控件。

此外,根据照片长和宽的比例,缩放后需要将Image控件的位置调整到显示区域的中间,如此视觉效果更佳。

3.3 系统结构

创建一个新的工程,添加一个Form窗体。在该Form窗体上添加ExplorerTree、PicturBox、ImageList、FileListBox、Label、TextBox和Timer等控件。工程的对象及其属性值,如表3-1所示。

表3-1 工程的对象及其属性值

此外,还要为Form窗体添加一个菜单栏,用于实现自动浏览照片和停止自动浏览照片的功能。Form窗体的菜单栏列表如表3-2所示。

表3-2 菜单栏列表

需要指出的是“浏览”菜单项是弹出式菜单,不要选中“浏览”菜单项的“可见”选项,但是“自动浏览”和“停止浏览”的“可见”选项需要选中。“浏览效果”的子菜单项中有9个命令项,其名称都为mnuEffects,其索引分别为0~8。

3.4 实现过程

根据表3-1向窗体上添加控件,控件的放置方式如图3-1所示。显示照片的控件是Image控件,其黑色背景是PictureBox控件。用于预览照片的6个区域事实上是通过添加控件数组实现的,用于前后和首尾翻页的按钮是Label控件数组。此外,用于放大显示照片的Image控件及其黑色背景PictureBox控件的大小需要覆盖所有6个照片预览区域。

双击图3-1中预览区域的照片,电子相册即可将该照片按比例放大到整个照片浏览区域。图3-2为照片放大浏览或自动浏览时的效果图。

图3-2 照片放大浏览或自动浏览效果图

在照片放大浏览时,可以右击鼠标弹出浏览设置菜单,选择“自动浏览”命令,电子相册会根据所设置的浏览方式进行自动浏览。在自动浏览照片时,也可以通过选择弹出式菜单中的“停止浏览”命令,结束自动浏览照片。

以右下拉方式浏览照片为例,先从“浏览效果”菜单项中选择“右下拉”命令;然后,右击鼠标并从弹出的快捷菜单中选择“自动浏览”命令即可。图3-3 为右下拉自动浏览效果图,照片会沿着图3-3中虚线箭头方向进入照片浏览区域,其余浏览方式与此类似。

图3-3 右下拉自动浏览效果图

该虚线箭头事实上在相册中是不存在的,是作者用于演示和说明而加入到图中的。

根据电子相册的功能,可以将该程序设计分为程序初始化、预览照片、翻页预览照片、预览其他文件夹中照片、浏览放大的照片、自动浏览照片和修改照片名称等部分。

3.4.1 程序初始化

在开始设计电子相册的功能程序之前,需要声明一些有用的变量,并在程序加载的时候,初始化这些变量和控件。程序代码如程序清单3-1所示。

程序清单3-1变量声明和初始化程序

        1.   Private intCurrentPage As Integer         '当前预览页
        2.   Private strOldName As String            '照片原来路径和名称
        3.   Private strNewName As String           '照片修改后路径和名称
        4.   Private intPhotoCount As Integer          '用于记数自动浏览到的照片
        5.   Private intBrowseEffect As Integer        '用于记数特殊浏览效果时图片的移动数
        6.   Private intEffectIndex As Integer          '用于记录特殊浏览效果
        7.
        8.   Private Sub Form_Load()
        9.       Dim i As Integer
        10.
        11.      exptPhoto.BrowseFrom=App.Path&"\Photo Database"
        12.      flPhotoList.Path=App.Path&"\Photo Database"
        13.      intCurrentPage=0
        14.      intPhotoCount=0
        15.
        16.      For i=0 To 5
        17.         txtPhotoName.Item(i).Text=""
        18.         txtPhotoName.Item(i).Locked=True
        19.         imgPhoto.Item(i).Visible=False
        20.      Next
        21.
        22.      PhotoBrowse
        23.      intBrowseEffect=0
        24.      intEffectIndex=8
        25.   End Sub

程序说明:第1~6行在Form窗体中声明的一些变量,在后面功能模块程序之间具有数据传递功能。第11 行是将ExplorerTree控件直接连接到默认的照片存放文件夹Photo Database,该文件夹需要创建在程序所在的文件夹中。第12行是用FileListBox控件列出Photo Database文件夹中的JPEG照片,以便显示在预览区域。第16~20行使用循环语句初始化照片预览区域的控件。第18行是将显示照片名称的文本框TextBox控件锁定,防止照片名称被误修改。第22行是调用照片预览程序PhotoBrowse过程,该过程的程序将在下一节介绍。第23~24行初始化和特殊效果浏览的变量。

3.4.2 预览照片

预览照片是电子相册最基本的功能,本章编写的PhotoBrowse程序即可实现照片预览功能。在PhotoBrowse程序中,已经考虑到了照片长、宽缩放比例的一致性和照片位置的居中放置。程序代码如程序清单3-2所示。

程序清单3-2预览照片

        1.   Private Sub PhotoBrowse()
        2.       Dim i As Integer
        3.
        4.       For i=0 To 5
        5.          imgPhoto.Item(i).Visible=False
        6.          txtPhotoName.Item(i).Text=""
        7.
        8.          If flPhotoList.ListCount>0 And_
        9.                 flPhotoList.ListCount>i+intCurrentPage*6 Then
        10.             imgPhoto.Item(i).Picture=LoadPicture(flPhotoList.Path_
        11.                    &"\"&flPhotoList.List(i+intCurrentPage*6))
        12.
        13.             imgPhoto.Item(i).Stretch=False
        14.             imgPhoto.Item(i).Left=240
        15.             imgPhoto.Item(i).Top=120
        16.
        17.             If imgPhoto.Item(i).Width>imgPhoto.Item(i).Height Then
        18.                imgPhoto.Item(i).Height=imgPhoto.Item(i).Height/_
        19.                                     (imgPhoto.Item(i).Width/3000)
        20.                imgPhoto.Item(i).Width=3000
        21.
        22.                imgPhoto.Item(i).Top=(3200-imgPhoto.Item(i).Height)/2
        23.             Else
        24.                imgPhoto.Item(i).Width=imgPhoto.Item(i).Width/_
        25.                                     (imgPhoto.Item(i).Height/3000)
        26.                imgPhoto.Item(i).Height=3000
        27.
        28.                imgPhoto.Item(i).Left=(3500-imgPhoto.Item(i).Width)/2
        29.             End If
        30.
        31.             imgPhoto.Item(i).Stretch=True
        32.             imgPhoto.Item(i).Visible=True
        33.
        34.             txtPhotoName.Item(i).Text=flPhotoList.List(i+intCurrentPage*6)
        35.         End If
        36.      Next
        37.   End Sub

程序说明:第5~6行是将显示照片的Image控件和照片名称的TextBox控件初始化。第8~9行判断FileListBox控件中是否列出了当前文件夹下所有照片,如果有,并且还没显示到最后一张照片,那么就将照片显示出来。第10行就是给对应的Image控件加载照片。第13行将Image控件的Stretch属性设置为False,使得Image控件适应照片的大小。第17~29行是根据不同的照片的长宽比例和期望显示照片的大小,设置Image控件的长宽尺寸及其位置。第31行将Image控件的Stretch属性设置为True,使得照片适应Image控件的大小。

需要说明的是,当程序执行到第29行时,Image控件中的照片只显示了左上角的一小部分,这部分被显示的区域大小是由第18~20行或者第24~26行的程序所确定的。只有程序执行了第31行后,才能显示完整的缩放后的照片。

3.4.3 翻页预览照片

如果当前文件夹中的照片比较多,不能在一页全部显示完,那么就需要分多页显示这些照片,因此需要添加翻页预览照片的功能。程序代码如程序清单3-3所示。

程序清单3-3翻页预览照片

        1.   Private Sub lblPhotoBrowse_MouseDown(Index As Integer,Button As Integer,_
        2.                                   Shift As Integer,X As Single,Y As Single)
        3.       lblPhotoBrowse.Item(Index).BorderStyle=1
        4.
        5.       Select Case Index
        6.          Case 0     '首页
        7.              intCurrentPage=0
        8.          Case 1     '前一页
        9.              If intCurrentPage>0 Then
        10.                intCurrentPage=intCurrentPage-1
        11.             End If
        12.         Case 2     '后一页
        13.             If flPhotoList.ListCount>(intCurrentPage+1)*6 Then
        14.                intCurrentPage=intCurrentPage+1
        15.             End If
        16.         Case 3     '尾页
        17.             If(flPhotoList.ListCount Mod 6)>0 Then
        18.                intCurrentPage=Int(flPhotoList.ListCount/6)
        19.             Else
        20.                intCurrentPage=Int(flPhotoList.ListCount/6)-1
        21.             End If
        22.      End Select
        23.
        24.      PhotoBrowse
        25.   End Sub
        27.
        28.   Private Sub lblPhotoBrowse_MouseUp(Index As Integer,Button As Integer,_
        29.                              Shift As Integer,X As Single,Y As Single)
        30.      lblPhotoBrowse.Item(Index).BorderStyle=0
        31.   End Sub

程序说明:本段程序的技术要点是确定相应动作所对应的页数即可。翻页按钮事实上是一个Label控件数组,Index属性0~3分别对应着首页、前一页、后一页和尾页按钮。为了使翻页按钮具有立体感,在鼠标按下时,第3行设置Label控件的BorderStyle属性值为1;而鼠标弹起时,第30行设置属性为0。

3.4.4 预览其他文件夹中照片

树形控件ExplorerTree的主要功能就是列出照片Photo Database文件夹中的所有文件夹,并能通过鼠标单击选择预览其他文件夹中的照片。其设计思路是在ExplorerTree控件的OnDirChanged事件过程中将所选择的地址路径赋给FileListBox控件,使得FileListBox控件列出该文件夹中所有照片。程序代码如程序清单3-4所示。

程序清单3-4预览其他文件夹中照片

        1.   Private Sub exptPhoto_OnDirChanged()
        2.       flPhotoList.Path=exptPhoto.Path
        3.       intCurrentPage=0
        4.       tmrAutoView.Enabled=False
        5.       tmrAutoView.Enabled=False
        6.       picView.Visible=False
        7.       frmMain.Caption="电子相册"
        8.       PhotoBrowse
        9.   End Sub

程序说明:第2行是将所选择的地址路径赋给FileListBox控件,FileListBox控件将自动列出该文件夹中的所有照片。第3~7行是初始化一些变量,第8行调用PhotoBrowse过程达到预览照片的效果。

本章使用FileListBox控件列出文件夹中的照片,然后从中依次提取照片文件名,将其显示出来。使用FileListBox控件实现这一过程十分简单,只要将ExplorerTree控件的地址路径赋给FileListBox控件,即可自动列出所有照片文件名。

3.4.5 浏览放大的照片

前面三节介绍了使用小图片的形式同时预览6张照片,本节要介绍的浏览放大的照片的实现过程实质上与预览照片是相同的。程序代码如程序清单3-5所示。

程序清单3-5浏览放大的照片

        1.   Private Sub imgPhoto_DblClick(Index As Integer)
        2.       Dim i As Integer
        3.
        4.       If imgPhoto.Item(Index).Visible=True Then
        5.          picView.Visible=True
        6.          imgView.Left=240
        7.          imgView.Top=120
        8.          imgView.Stretch=False
        9.          imgView.Picture=imgPhoto.Item(Index).Picture
        10.
        11.         If imgView.Width/imgView.Height>=10200/7400 Then
        12.             imgView.Height=imgView.Height/(imgView.Width/10200)
        13.             imgView.Width=10200
        14.
        15.             imgView.Top=(7600-imgView.Height)/2
        16.         Else
        17.             imgView.Width=imgView.Width/(imgView.Height/7400)
        18.             imgView.Height=7400
        19.
        20.             imgView.Left=(10600-imgView.Width)/2
        21.         End If
        22.
        23.         imgView.Stretch=True
        24.         frmMain.Caption="电子相册——"&txtPhotoName.Item(Index).Text
        25.         intPhotoCount=Index
        26.      End If
        27.   End Sub
        28.
        29.   Private Sub imgView_DblClick()
        30.      tmrAutoView.Enabled=False
        31.      picView.Visible=False
        32.      frmMain.Caption="电子相册"
        33.   End Sub

程序说明:第5~9行是初始化控件并向Image控件中加载要放大浏览的照片,第11~21行是设置Image控件的长宽尺寸及其位置,第29~33行是返回照片预览界面。

3.4.6 自动浏览照片

自动浏览照片是通过时钟控件Timer的Timer事件实现的。其设计思路是:在照片区域右击鼠标弹出快捷菜单,执行“自动浏览”菜单项的命令,将Timer控件的Enable属性设置为True即可。程序代码如程序清单3-6所示。

程序清单3-6自动浏览照片

        1.   Private Sub imgView_MouseDown(Button As Integer,Shift As Integer,_
        2.                               X As Single,Y As Single)
        3.       If Button=2 Then
        4.          PopupMenu mnuView
        5.       End If
        6.   End Sub
        7.
        8.   Private Sub mnuAutoView_Click()
        9.       tmrAutoView.Enabled=True
        10.      mnuBrowseEffect.Enabled=False
        11.   End Sub
        12.
        13.   Private Sub mnuStopView_Click()
        14.      tmrAutoView.Enabled=False
        15.      mnuBrowseEffect.Enabled=True
        16.   End Sub
        17.
        18.   Private Sub tmrAutoView_Timer()
        19.      If intBrowseEffect>130 Then
        20.         intPhotoCount=intPhotoCount+1
        21.         If intPhotoCount=flPhotoList.ListCount Then
        22.             intPhotoCount=0
        23.         End If
        24.
        25.         imgView.Visible=False
        26.
        27.         imgView.Stretch=False
        28.         imgView.Picture=LoadPicture(flPhotoList.Path&"\"&_
        29.                              flPhotoList.List(intPhotoCount))
        30.
        31.         If imgView.Width/imgView.Height>=10200/7400 Then
        32.             imgView.Height=imgView.Height/(imgView.Width/10200)
        33.             imgView.Width=10200
        34.         Else
        35.             imgView.Width=imgView.Width/(imgView.Height/7400)
        36.             imgView.Height=7400
        37.         End If
        38.
        39.         Select Case intEffectIndex
        40.             Case 0              '上拉
        41.                imgView.Left=(10600-imgView.Width)/2
        42.                imgView.Top=7600-(7600-imgView.Height)/2
        43.
        44.             Case 1              '下拉
        45.                imgView.Left=(10600-imgView.Width)/2
        46.                imgView.Top=(7600-imgView.Height)/2-imgView.Height
        47.
        48.             Case 2              '左拉
        49.                imgView.Left=10600-(10600-imgView.Width)/2
        50.                imgView.Top=(7600-imgView.Height)/2
        51.
        52.             Case 3              '右拉
        53.                imgView.Left=(10600-imgView.Width)/2-imgView.Width
        54.                imgView.Top=(7600-imgView.Height)/2
        55.
        56.             Case 4              '左上拉
        57.                imgView.Left=10600-(10600-imgView.Width)/2
        58.                imgView.Top=7600-(7600-imgView.Height)/2
        59.
        60.             Case 5              '右上拉
        61.                imgView.Left=(10600-imgView.Width)/2-imgView.Width
        62.                imgView.Top=7600-(7600-imgView.Height)/2
        63.
        64.             Case 6              '左下拉
        65.                imgView.Left=10600-(10600-imgView.Width)/2
        66.                imgView.Top=(7600-imgView.Height)/2-imgView.Height
        67.
        68.             Case 7              '右下拉
        69.                imgView.Left=(10600-imgView.Width)/2-imgView.Width
        70.                imgView.Top=(7600-imgView.Height)/2-imgView.Height
        71.
        72.             Case 8              '普通
        73.                imgView.Left=(10600-imgView.Width)/2
        74.                imgView.Top=(7600-imgView.Height)/2
        75.         End Select
        76.
        77.         imgView.Stretch=True
        78.         imgView.Visible=True
        79.         frmMain.Caption="电子相册——"&flPhotoList.List(intPhotoCount)
        80.         intBrowseEffect=0
        81.
        82.      ElseIf intBrowseEffect<=100 Then
        83.         Select Case intEffectIndex
        84.             Case 0              '上拉
        85.                imgView.Top=7600-(7600-imgView.Height)/2_
        86.                       -imgView.Height/100*intBrowseEffect
        87.
        88.             Case 1              '下拉
        89.                imgView.Top=(7600-imgView.Height)/2_
        90.                       -imgView.Height/100*(100-intBrowseEffect)
        91.
        92.             Case 2              '左拉
        93.                imgView.Left=10600-(10600-imgView.Width)/2_
        94.                       -imgView.Width/100*intBrowseEffect
        95.
        96.             Case 3              '右拉
        97.                imgView.Left=(10600-imgView.Width)/2_
        98.                       -imgView.Width/100*(100-intBrowseEffect)
        99.
        100.            Case 4              '左上拉
        101.                imgView.Left=10600-(10600-imgView.Width)/2_
        102.                       -imgView.Width/100*intBrowseEffect
        103.                imgView.Top=7600-(7600-imgView.Height)/2_
        104.                       -imgView.Height/100*intBrowseEffect
        105.
        106.            Case 5              '右上拉
        107.                imgView.Left=(10600-imgView.Width)/2_
        108.                       -imgView.Width/100*(100-intBrowseEffect)
        109.                imgView.Top=7600-(7600-imgView.Height)/2_
        110.                       -imgView.Height/100*intBrowseEffect
        111.
        112.            Case 6              '左下拉
        113.                imgView.Left=10600-(10600-imgView.Width)/2_
        114.                       -imgView.Width/100*intBrowseEffect
        115.                imgView.Top=(7600-imgView.Height)/2_
        116.                       -imgView.Height/100*(100-intBrowseEffect)
        117.
        118.  .          Case 7              '右下拉
        119.                imgView.Left=(10600-imgView.Width)/2_
        120.                       -imgView.Width/100*(100-intBrowseEffect)
        121.                imgView.Top=(7600-imgView.Height)/2_
        122.                       -imgView.Height/100*(100-intBrowseEffect)
        123.         End Select
        124.         intBrowseEffect=intBrowseEffect+10
        125.     Else
        126.         intBrowseEffect=intBrowseEffect+1
        127.     End If
        128.  End Sub

程序说明:第1~6 行是右击放大的照片弹出快捷菜单。第8~11 行设置Timer控件的Enable属性为True,启动定时器,并将浏览效果菜单设置为不能用。当定时时刻到来后,执行Timer事件中的代码。第18~128行就是自动浏览照片的程序代码,其基本结构和设计思路主要是根据所设置的不同的浏览效果,使用程序设置照片的初始位置和浏览过程中照片的运动路径。第20~37行加载照片,并设置图片框Image控件的大小。第39~75行根据不同的浏览效果,设置照片的初始位置。第83~123行在照片的移动过程中,不断更新Image控件的Left和Top属性,以确定照片的位置。

3.4.7 修改照片名称

通常数码相机拍摄的照片是按照顺序命名的,电子相册提供的修改照片名称功能可以将照片命名为用户喜欢或个性的名称。修改照片名称其实是修改图片的文件名,可以使用Name语句重新命名指定的文件。

本章使用TextBox控件显示照片名称。不修改的时候TextBox控件是被锁定的,防止误修改,即设置其Locked属性为True。修改的时候要双击TextBox控件,解除锁定,即设置其Locked属性为False,然后修改名称,以键入Enter键作为修改结束,重新锁定TextBox控件。程序代码如程序清单3-7所示。

程序清单3-7修改照片名称

        1.   Private Sub txtPhotoName_DblClick(Index As Integer)
        2.       If txtPhotoName.Item(i).Text<>""Then
        3.          txtPhotoName.Item(i).Locked=False
        4.          strOldName=flPhotoList.Path&"\"&txtPhotoName.Item(Index).Text
        5.       End If
        6.   End Sub
        7.
        8.   Private Sub txtPhotoName_KeyPress(Index As Integer,KeyAscii As Integer)
        9.       If KeyAscii=13 Then
        10.         strNewName=flPhotoList.Path&"\"&txtPhotoName.Item(Index).Text
        11.         Name strOldName As strNewName
        12.         txtPhotoName.Item(Index).Locked=True
        13.      End If
        14.   End Sub

程序说明:第1~6行在TextBox控件的DblClick事件中解除锁定。第4行是通过变量保存照片修改前的存储路径和名称。第9行判断是否键入Enter键,以键入Enter键作为修改结束。第10行照片新的存储路径和名称。第11行使用Name语句重新命名文件名。第12行重新锁定TextBox控件。

Name语句可以重新命名一个文件、目录或文件夹。如果重命名前后路径不同,可以将文件移动到新的路径下。Name语句不能重新命名一个已经被打开的文件。本章使用LoadPicture函数将照片加载到Image控件中,事实上并没有打开照片文件。因此,在预览照片的时候可以修改照片名称,不用担心会产生错误。修改存放照片文件夹与修改照片相似,请读者参考光盘中的源程序。