فصل ۱۶ — شیء DoCmd
DoCmd یک Object Model ویژه در Access VBA است. ساختار آن نسبتاً ساده است، اما Methodهای بسیار مفیدی برای توسعهدهندهٔ Access دارد. نوشتن یک Application پیچیدهٔ Access بدون استفاده از DoCmd در جایی از برنامه تقریباً غیرممکن است.
Methodهای DoCmd تقریباً Actionهایی را که در Macro Sheetها در اختیار توسعهدهنده است به VBA میآورند؛ بنابراین Functionهای Macro عملاً از داخل VBA در دسترساند. بعضی Methodها در نسخههای جدید Access منسوخ شدهاند و دیگر عمل واقعی خود را انجام نمیدهند، اما برای Backward Compatibility باقی ماندهاند تا اجرای Code قدیمی با Error متوقف نشود. مشکل این است که چنین Methodی ممکن است بدون Error اجرا شود ولی نتیجهٔ مورد انتظار را ندهد.
استفاده از DoCmd ساده است. برای مثال:
DoCmd.Quit
Database و Application را کاملاً میبندد.
Methodهای اصلی DoCmd
Beep
Beep در صورتی که Speaker کاربر Mute نباشد صدای کوتاهی پخش میکند:
DoCmd.Beep
راه بسیار سادهای برای تولید صداست ولی انعطاف محدودی دارد. برای Soundهای متنوعتر، فصل ۲۰ و API Callها را ببینید.
Close
Close Objectی مانند Form یا Report را میبندد؛ Object Typeهای دیگری نیز قابل تعییناند:
Docmd.Close (ObjectType,ObjectName,Save)
هر سه Parameter اختیاریاند. ObjectType Constant از نوع acObjectType مانند acForm یا acReport است؛ ObjectName نام Object و Save Constant از نوع acCloseSave برای تعیین ذخیرهشدن یا نشدن Object است. این Method اغلب در Codeِ Button «Close» خود Form/Report اجرا میشود و در آن حالت Parameterها لازم نیستند. حتی اگر کاربر بتواند با X پنجره را ببندد، Code میتواند Control بیشتری روی فرایند Close داشته باشد.
CloseDatabase
همان کاری را میکند که انتخاب «Close Database» از رابط Access انجام میدهد و Parameter ندارد:
DoCmd.CloseDatabase
Hourglass
Cursor را به Hourglass/Busy تبدیل میکند یا آن را به Cursor معمولی برمیگرداند. چون هنگام اجرای VBA همیشه Busy Cursor خودکار ظاهر نمیشود، این Method به کاربر اطمینان میدهد Process هنوز در حال اجراست:
DoCmd.Hourglass True
DoCmd.Hourglass False
اگر Hourglass را روشن کردید حتماً در پایان خاموش کنید. اگر Code پیش از برگرداندن Cursor Crash کند، کاربر ممکن است تصور کند برنامه هنوز در حال اجراست.
Maximize و Minimize
Maximize Active Window را تمامصفحه میکند؛ معمولاً در Eventهای Open یا Activate مربوط به Form و Report استفاده میشود تا اختلاف Screen Resolution کاربران ظاهر طراحی را خراب نکند:
DoCmd.Maximize
Parameter ندارد. کتاب یادآوری میکند نام Method با حرف z یعنی Maximize نوشته میشود. Minimize نیز به همان شیوه Active Window را کوچک میکند.
OpenForm
Form را باز میکند و برای Applicationهایی که User میان Hierarchyای از Formها حرکت میکند بسیار مفید است:
DoCmd.OpenForm _
(FormName,View,FilterName,WhereCondition,DataMode,WindowMode,OpenArgs)
FormName اجباری و بقیه اختیاریاند:
- View: Constant از
acFormView؛ Default برابر acNormal.
- FilterName: نام یک Query در Database جاری.
- WhereCondition: SQL WHERE Clause بدون خود کلمهٔ WHERE.
- DataMode: Constant از
acFormOpenDataMode برای Data Entry Mode.
- WindowMode: Constant از
acWindowMode برای حالت Window.
- OpenArgs: Propertyِ
OpenArgs Form را تعیین میکند.
OpenQuery
Query را باز میکند تا کاربر Resultها را مرور کند. نویسنده پیشنهاد میکند در بسیاری از موارد Form مبتنی بر Query را بهصورت Datasheet باز کنید تا Filtering کاملتر در اختیار کاربر باشد:
DoCmd.OpenQuery(QueryName,View,DataMode)
QueryName اجباری است. View و DataMode اختیاریاند و بهترتیب View و Data Entry Mode را کنترل میکنند. Action Queryهایی مثل Delete، Insert یا Append نیز قابل اجرا هستند، اما میتوان از:
CurrentDb.Execute "MyQuery"
نیز استفاده کرد.
OpenReport
DoCmd.OpenReport _
(ReportName,View,FilterName,WhereCondition,WindowMode,OpenArgs)
ReportName اجباری و بقیه اختیاریاند. View حالت نمایش، FilterName نام Query، WhereCondition شرط SQL بدون WHERE، WindowMode حالت Window و OpenArgs مقدار Property متناظر را تعیین میکند.
OpenTable
Table را برای Browse کردن Recordها باز میکند، گرچه نویسنده استفاده از Form مبتنی بر Table به شکل Datasheet را برای Filtering مناسبتر میداند:
DoCmd.OpenTable(TableName,View,DataMode)
TableName اجباری و View/DataMode اختیاریاند.
PrintOut
Active Object مانند Form، Report یا Datasheet را Print میکند:
DoCmd.PrintOut(PrintRange,PageFrom,PageTo,PrintQuality,Copies,CollateCopies)
همهٔ Parameterها اختیاریاند:
- PrintRange: Constant از
acPrintRange؛ Default acPrintAll.
- PageFrom / PageTo: ابتدا و انتهای Page Range؛ اگر PrintRange برابر acPages باشد اجباری میشوند.
- PrintQuality: Constant از
acPrintQuality؛ Default acHigh.
- Copies: تعداد Copy؛ Default برابر 1.
- CollateCopies: True بهصورت Default یا False.
Quit
DoCmd.Quit(Options)
Options اختیاری و از نوع acQuitOption است؛ Default برابر acQuitSaveAll. اگر کاربر Filterی روی Form گذاشته باشد، Save شدن همهچیز ممکن است Filter را نیز ذخیره کند و کاربر بعدی همان Filter را ببیند؛ بنابراین این رفتار باید با دقت مدیریت شود.
RunCommand
DoCmd.RunCommand(Command)
Command اجباری و از نوع acCommand است. بعضی Commandها در نسخههای جدید Access دیگر وجود ندارند و ممکن است برای یافتن موارد عملی آزمون لازم باشد؛ acCmdPrintSelection بهعنوان نمونهٔ معتبر ذکر شده است.
SetWarnings
System Warningها را نمایش میدهد یا سرکوب میکند. مثلاً Delete Query معمولاً هشدار حذف Recordها را نشان میدهد؛ در VBA ممکن است نخواهید این Message اجرای Procedure را متوقف کند:
Docmd.SetWarnings True
Docmd.SetWarnings False
True پیامهای سیستم را نمایش میدهد و False آنها را خاموش میکند. اگر Warningها را خاموش کردید حتماً پس از پایان Code دوباره روشن کنید؛ اثر این Setting در کل Application باقی میماند. برای مثال اگر Queryی را اشتباه ویرایش کنید و ببندید، در حالت Warning=False سؤال Save Changes نمایش داده نمیشود و Default ممکن است Save باشد؛ در نتیجه نسخهٔ اشتباه جای Query قبلی را میگیرد.
TransferSpreadsheet
راه سادهای برای انتقال داده بین Excel Spreadsheet و Table است. در Export میتوان Query را نیز بهعنوان Source استفاده کرد:
DoCmd.TransferSpreadsheet _
(TransferType,SpreadsheetType,TableName,FileName,HasFieldNames,Range,UseOA)
Argumentها در Syntax اختیاریاند:
- TransferType:
acImport یا acExport.
- SpreadsheetType: Constant از
acSpreadsheetType برای Format Spreadsheet؛ Format نسخههای قدیمی Excel و حتی Lotus 123 نیز در فهرست پشتیبانی دیده میشود.
- TableName: Table مقصد/مبدأ؛ هنگام Export میتواند Query باشد.
- FileName: نام کامل و Path فایل Spreadsheet.
- HasFieldNames: True/False برای وجود Field Name در Row نخست؛ Default False.
- Range: هنگام Import محدودهٔ Cellها را تعیین میکند؛ هنگام Export باید خالی باشد.
- UseOA: طبق متن کتاب استفاده نمیشود.
TransferText
برای ارتباط با Text Fileهاست و مشابه گزینههای Text File در بخش External Data رابط Access عمل میکند. پیش از Automation بهتر است Import/Export را یک بار دستی بهعنوان «Dry Run» انجام دهید تا مشکلات Format مشخص شوند. اگر نتیجه درست بود، Import/Export Specification را با Name مشخص ذخیره کنید تا Method سادهتر و قابلاعتمادتر شود.
DoCmd.TransferText _
(TransferType,SpecificationName,TableName,FileName,HasFieldNames, _
HTMLTableName,CodePage)
- TransferType: Constant از
acTextTransferType، معمولاً acImportDelim، acImportFixed، acExportDelim یا acExportFixed. Default برابر acImportDelim. مشخص میکند Import/Export و Fieldها Delimited یا Fixed-width باشند.
- SpecificationName: نام Specification ذخیرهشده از Dry Run؛ شامل Fieldهای واردشونده، نحوهٔ Dateها، Delimiter و تنظیمات دیگر.
- TableName: Table مقصد/مبدأ؛ در Export میتواند Query Name باشد.
- FileName: نام کامل و Path Text File.
- HasFieldNames: True/False برای وجود Field Name در Row نخست؛ Default False.
- HTMLTableName: نام Table/List در HTML File؛ فقط برای HTML.
- CodePage: Long Value مشخصکنندهٔ Character Set مربوط به Code Page.
صفحهٔ بعدی در نسخهٔ اصلی عمداً خالی است.
فصل ۱۷ — استفاده از Access برای تعامل با دیگر برنامههای Office
تمام Applicationهای Microsoft Office از VBA بهعنوان زبان Macro زیرین خود استفاده میکنند و هرکدام Object Model مخصوص خود را دارند. به همین دلیل، Access VBA برای کنترل دیگر برنامههای Office نسبت به زبانهای غیر-Microsoft مزیت بزرگی دارد. برای مثال میتوانید از داخل Access یک Word Document بسازید، حتی بدون اینکه Word روی Screen ظاهر شود.
ممکن است Code شما دادهای را در Database پردازش کند و User خروجی را در Word Document بخواهد. Access میتواند Word Document خارجی را باز کند، داده را داخل آن قرار دهد و فایل را Save کند، بدون اینکه لازم باشد ساختار داخلی File Formatِ Word را بدانید.
این کار با CreateObject انجام میشود. پیش از آن باید Reference مناسب Office Object Library، در اینجا Microsoft Word Object Library، را به Project اضافه کنید. اگر Office نصب باشد Library معمولاً در فهرست References موجود است. با افزودن Reference، Objectها و Object Model آن Application از VBA Access قابل استفاده میشوند.
از منوی VBE گزینهٔ Tools | References را انتخاب کنید، Microsoft Word Object Library را تیک بزنید و OK کنید. Location پایین پنجره به فایل OLB مربوط به Object Library اشاره میکند.
شکل ۱۷-۱ — انتخاب Microsoft Word Object Library
نمونهٔ ساخت Word Document جدید و Save کردن آن:
Sub Test_Word()
Dim oWd As Word.Application, oWdoc As Word.Document
Set oWd = CreateObject("Word.Application")
Set oWdoc = oWd.Documents.Add
oWdoc.Sections(1).Range.Text = "My new Word Document"
oWdoc.SaveAs ("MyTest")
oWdoc.Close
oWd.Quit
Set oWdoc = Nothing
Set oWd = Nothing
End Sub
خط نخست Variableهای Application و Document را تعریف میکند. چون Reference به Word Object Library اضافه شده، هنگام تایپ Code، Word Objectها، Methodها و Propertyها در List Boxها ظاهر میشوند. بدون Reference، VBA این Object Typeها را نمیشناسد.
oWd Object ساختهشدهٔ Word Application را نگه میدارد. Argumentِ String برابر "Word.Application" Class Nameِ Application Object در Word است و چون String است Auto-completion برای خود متن آن وجود ندارد. سپس oWdoc یک Document جدید را نگه میدارد؛ درست مانند بازکردن Word و ساختن Document جدید.
عبارت "My new Word Document" به نخستین Section Document نوشته میشود. Document با نام MyTest در Documents Folder ذخیره و سپس بسته میشود. بستن Document مهم است؛ اگر باز بماند، Instance مجازی Word ممکن است روی File Reservation داشته باشد و دیگران فقط Read-only به آن دسترسی پیدا کنند.
Instance ساختهشده با Code ممکن است روی Taskbar دیده نشود و فقط در Task Manager قابل تشخیص باشد. اگر Objectها درست Close و Release نشوند، حتی پس از بستهشدن Access ممکن است Word در Memory بماند و هنگام Shutdown Windows دربارهٔ Save شدن Document سؤال کند. برای جلوگیری از این وضعیت، oWdoc و oWd به Nothing تنظیم میشوند.
فایل ساختهشده یک Word Document عادی است. این مثال ساده میتواند گسترش یابد؛ مثلاً Standard Document با Tableهایی داشته باشید که Macro آنها را با دادهٔ Database پر کند.
نویسنده مثالی عملی از Report مربوط به SLA یا Service Level Agreement ذکر میکند. Report یک Word Document شامل Table و Chartهای متعدد بود و Input از چند Database میآمد. VBA دادهٔ مرتبط را استخراج و در Tableها و Chartهای درست Word وارد میکرد. کاری که دستی حدود نیمروز طول میکشید با Code در کمتر از پنج دقیقه انجام شد.
Sub Test_Word()
Dim oWd As Word.Application, oWdoc As Word.Document
Dim orx As Word.Range, ot As Word.Table
Set oWd = CreateObject("Word.Application")
Set oWdoc = oWd.Documents.Add
Set orx = oWdoc.Range
Set ot = oWdoc.Tables.Add(orx, 4, 5)
ot.Cell(1, 1).Range.Text = "test"
oWdoc.SaveAs ("MyTest")
oWdoc.Close
oWd.Quit
Set oWdoc = Nothing
Set oWd = Nothing
End Sub
در این نمونه یک Table چهارردیفی و پنجستونی در Word ساخته و متن test در Cell نخست نوشته میشود. چنین Automationای از منوی Access تنها با Copy/Paste دستی قابل تقلید است؛ VBA امکان انجام خودکار کارهای فراتر از Menu Structure را میدهد.
کنترل Microsoft Outlook
همین تکنیک را میتوان برای Microsoft Outlook به کار برد تا از Database ایمیل ارسال شود یا اطلاعات Address Book خوانده شود. Access قابلیتهای Email داخلی دارد، اما این روش Control دقیقتری روی محتوای ارسالی میدهد. باید Microsoft Outlook نصب باشد؛ Outlook Express یا Windows Mail کافی نیست. خود Outlook لازم نیست در لحظهٔ اجرا روی Screen باز باشد.
از Tools | References در VBE، Microsoft Outlook Object Library را انتخاب کنید:
شکل ۱۷-۲ — انتخاب Object Library مربوط به Microsoft Outlook
Sub Test_Outlook()
Dim oFolder As Outlook.MAPIFolder
Dim oItem As Outlook.MailItem
Dim oOutlook As New Outlook.Application
Dim MoOutlook As Outlook.NameSpace
Set MoOutlook = oOutlook.GetNamespace("MAPI")
Set oFolder = MoOutlook.GetDefaultFolder(olFolderOutbox)
Set oItem = oFolder.Items.Add(olMailItem)
With oItem
.Recipients.Add ("richard.shepherd@anywhere.com")
.Subject = "Test Access Email"
.Body = "This is a test of an email from Access VBA"
.Importance = olImportanceHigh
.Send
End With
Set oItem = Nothing
Set oFolder = Nothing
End Sub
هنگام اجرا ممکن است Outlook Warning بدهد که Code در حال دسترسی به اطلاعات Email Address است؛ این Security برای مقابله با Email Virusهایی است که از تکنیک مشابه استفاده میکنند.
Variableها برای Outlook Application، NameSpace، Folder و MailItem ساخته میشوند. MoOutlook به NameSpace از نوع MAPI اشاره میکند؛ MAPI لایهٔ Messaging Service Provider مورد استفاده Outlook برای Data Storage است و تنها NameSpace پشتیبانیشده در Outlook محسوب میشود.
oFolder به Default Outbox Folder متصل میشود و oItem Mail Item جدیدی داخل آن میسازد، مشابه بازکردن New Message در Outlook. سپس Recipient، Subject، Body و Importance تعیین و Send فراخوانی میشود.
اگر Recipient داخل Network و در Outlook Address List باشد، میتوان صرفاً Name را استفاده کرد. برای Line Break در Body میتوان Chr(13)، Chr(10) یا vbCrLf را به کار برد. Constantهای Importance:
olImportanceHigholImportanceNormalolImportanceLow
پس از Send، Objectها به Nothing تنظیم میشوند تا Memory آزاد شود.
کتاب هشدار میدهد این Technology همان چیزی است که بعضی Email Virusها، از جمله Love Bug، از آن سوءاستفاده کردهاند. Code نادرست ممکن است تعداد زیادی Email خودکار ارسال، Mail System را شلوغ و Recipientها را ناراضی کند. نسخههای جدید Outlook Security بیشتری اضافه کردهاند و ممکن است پیش از ارسال Email از کاربر تأیید بگیرند؛ دستورالعمل Application باید این رفتار را برای User توضیح دهد.
کنترل Access از دیگر برنامههای Office
همانطور که Access میتواند Word یا Outlook را کنترل کند، دیگر Applicationها نیز میتوانند Access را کنترل کنند. مثلاً Macro در Word یا Excel میتواند Tableهای Access را پر کند و حتی Queryهایی را که Data برنمیگردانند اجرا کند. لازم نیست خود Access از قبل در حال اجرا یا Database روی Screen قابل مشاهده باشد. اگر Database باز هم باشد، Multiuser بودن Access مانع این سناریو نمیشود.
مثال کتاب از داخل Excel در Table یک Access Database داده مینویسد. VBA در تمام Office Applicationها از نظر Language مشابه است، اما Object Model هر Application متناسب با Functionality آن متفاوت است.
ابتدا در Access یک Table نمونه بسازید که یک Text Field با نام MyText داشته باشد. متن منبع در دستور ساخت، نام TestAccess را برای Table ذکر میکند و در Code بعدی از نام MyTable استفاده میشود. برای مثال Primary Key ضروری نیست. سپس Excel را باز و با ALT+F11 VBE را اجرا کنید.
در Excel باید Reference به Microsoft Access Object Library و نیز DAO Object Library اضافه شود. در Tools | References بالاترین Version موجود هر Library را انتخاب کنید.
شکل ۱۷-۳ — انتخاب Access Object Library
Code زیر فرض میکند Database در C:\Temp\TestAccess.accdb قرار دارد:
Sub Test_Access()
Dim oAApp As Access.Application, oRSet As DAO.Recordset
Set oAApp = CreateObject("Access.Application")
oAApp.OpenCurrentDatabase "C:\Temp\TestAccess.accdb"
Set oRSet = oAApp.CurrentDb.OpenRecordset("MyTable")
oRSet.AddNew
oRSet!MyText = "Test String"
oRSet.Update
oRSet.Close
Set oRSet = Nothing
Set oApp = Nothing
End Sub
oAApp Access Application Object و oRSet DAO Recordset را نگه میدارند. CreateObject("Access.Application") یک Instance از Access میسازد، سپس Database باز و Recordset به Table نمونه متصل میشود. AddNew Record جدید میسازد، MyText برابر Test String میشود، Recordset Update و Close میشود و Objectها برای آزادسازی Memory به Nothing تنظیم میشوند.
بستن صحیح و Set کردن Objectهای ساختهشده به Nothing اهمیت زیادی دارد. در غیر این صورت Memory مصرفشده ممکن است آزاد نشود و Instance برنامه پس از Exit نیز در Memory باقی بماند. فصل با تأکید بر قدرت VBA در دستکاری و Automation دیگر Microsoft Applicationها پایان مییابد.