techtips8 面向VisualBasic程序员的杂志 第8版.docx
WelcometotheEighthEditionoftheVBPJTechnicalTipsSupplement!ThesetipsandtricksweresubmittedbyprofessionaldevelopersusingVisualBasic3.0,VisualBasic4.0,VisualBasic5.0,VisualBasic6.0,VisualBasicforApplications(VBA),andVisualBasicScript(VBS).TheeditorsatVisualBasicProgrammer,sJournalcompiledthetips.Insteadoftypingthecodepublishedhere,downloadthetipsfromthefree,Registered1.evelofTheDevelopmentExchangeat.Ifyou,dliketosubmitatiptoVisualBasicProgrammer,sJournal,pleasesendittoUserTips,FawcetteTechnicalPublications,209HamiltonAve.,PaloAlto,California,USA,94301-2500.Youcanalsofaxitto650-853-0230orsenditelectronicallytovbpjedit.Pleaseincludeaclearexplanationofwhatthetechniquedoesandwhyit,suseful,andindicateifit,sforVBA,VBS,VB3,VB416-or32-bit,VB5,orVB6.Pleaselimitcodelengthto20lines.Don,tforgettoincludeyoure-mailandmailingaddress.Ifwepublishyourtip,we,llpayyou$25orextendyourVBPJsubscriptionbyoneyear.VB5,VB61.evel:BeginningPreventCheckboxChangesYou,11oftenwanttodisplayacheckbox-stylelistboxtoshowusersthevaluestheyhaveselectedinanunderlyingdatabase.However,youdon,twanttoallowuserstochangetheselections-thatis,tochangewhichboxestheychecked.Youcan,tdisablethelistboxbecausethatstopstheuserfromscrollingthelisttoseewhichitemstheychecked.Youcan,tuse1.ocked,becausethelistboxdoesn,thavea1.ockedproperty.Here,sonesolution:PaintaCommandbuttonwiththecaptionttClicktotoggleenabledproperty,'andalistboxonaform,thenchangethelistboxstyleto1-Checkbox.Addthiscode:OptionExplicitDimmbDisabledAsBooleanPrivateSubCommandl_Click()mbDisabled=NotmbDisabledEndSubPrivateSub1.istl_ltemCheck(ltemAsInteger)IfmbDisabIedThen1.istl-SeIected(Item)=Not1.istl.SeIected(Item)EndIfEndSubWhenmbDisabledissettoTrue,thechangesmadebytheusertothelistboxselectionsareimmediatelyreversed.Itwillappearasiftheselectionshaven,tchangedatall,andthelistisstillscrollable.IanChamp,receivedbye-mail牟*余字*余*拿木*今*车窄*专*车*车*车窄*余*余*车本*余申*余*拿*拿*余*东*卒*车*余*京字*车*车*余辛*率*多*拿*VB432,VB5,VB61.evel:IntermediateEstablishaDataDictionaryIfyourSQ1.lookslikethis,youneedtoaskyourselfhowmuchcodeyou,dhavetoinspectandreviseifyoudecidedtochangeadatabasefieldortablename,asfrequentlyhappensduringdevelopment:SQ1.String="SE1.ECTfirstname,lastname,"&_"linepreferences"&_"FROMimagingusersWHEREusercode="_","&Trim(UCase(UserlDText.Text)&,11"ODBCstatus=SQ1.ExecDirect(ODBChandlel,SQ1.String,_1.en(SQ1.String)WhathappensifSQmandconventions(fieldnamedelimiters)change?Becauseacompiledoesn,trevealsuchnamemisspellingsorconventionflaws,codeinobscureprocedurescanbeinproductionbeforedefectsaredetected.Ourgroupestablishedatableandfielddictionaryinamoduleusedforarecentlargeproject.ThishelpedusensurethatwecorrectlypastedtableandfieldnamesintoallSQmands.Italsoprovidedarepositorythatsimplifiedmaintenance.Asdatabaseresourcenameschangedornewname-delimitingconventionswererequired,werevisedthedictionarybeforerecompiling.Wealsousedthedictionarytoconveydescriptiveinformationabouttablesandfieldstodevelopers.Ourdictionarylookslikethis:'tables:PublicConsttblUsersAsString="(imagingusers"'datafields:PublicConstfldFirstNameAsString="(firstname"'16charactersPublicConstfld1.astNameAsString="(lastname"'16charactersPublicConst(Id1.inePreferencesAsString=_"linepreferences"'20charactersPublicConstfldUserCodeAsString="usercode"'IOcharactersOurSQ1.lookslikethis:SQ1.String="SE1.ECT"&fldFirstName&_",&fld1.astName&_","&fld1.inePreferences&_"FROM,&tblUsers&_,WHERE"&fldUserCode&"="&_"'"&Trim(UCase(UserlDTe×t.Text)&","ODBCstatus=SQ1.ExecDirect(ODBChandlel,SQ1.String,_1.en(SQ1.String)Programmersdon'thavetoknowtheactualnamesofdatabasecomponents.Theyalwaysusetheconstantsthatrefertothedatabasecomponents.Acleancompileensuresyou,11usecorrectnamesandname-delimitingconventionsinyourSQ1.statements.DougIIagy,Greensburg,Pennsylvania余*牟申*率*率*牟*辛*牟*拿*本*车申*率*牟*车*拿*拿*率*多*余*牟*牟*辛*专*牟*柴*VB432,VB5,VB61.evel:IntermediateContext-SensitiveHelpforDisabledControlsIfyouwantaformtosupportcontext-sensitivehelp,settheWhatsThisButtonandWhatsThisHeIppropertiesontheformtoTrue,andsettheWhatsThisHelpIDpropertytoacorrespondinghelp-filetopicIDforanycontrolonthatformforwhichyouwanthelptobedisplayed.Unfortunately,thehelpisn,tshownifthecontrosEnabledpropertyissettoFalse.Tosolvethisproblem,createalabelunderthecontrolwiththesamedimensions,andclearitscaptiontomakeitinvisible.SettheWhatsThisHelpIDpropertytothesamevalueasthedisabledcontrosproperty.FrankAddati9Melbourne,Australia车*余*辛*车申*车*多*拿车*拿*拿*木*余辛*车*辛*车*车本*余*拿辛*专车*率*余?*拿*车*专*车本*车*拿*拿?*辛*拿*多*车*余本*VB3,VB416/32,VB5,VB61.evel:IntennediateImproveontheBubbleSortAbubblesort,sexecutiontimeisamultipleofthesquareofthenumberofelements.Becauseofthis,thebubblesortissaidtobeann-squaredalgorithm.Youcaneasilymakeimprovementstoabubblesorttospeeditup.Onewayistoreversethedirectionofpassesreadingthearray,insteadofalwaysreadingthearrayinthesamedirection.Thismakesout-of-placeelementstravelquicklytotheircorrectposition.Thisversionofabubblesortiscalledtheshakersort,becauseitimpartsashakingmotiontothearray:PublicSubShaker(ltem()AsVariant)DimExchangeAsBooleanDimTempAsVariantDimxAsIntegerDoExchange=FalseForX=(UBound(Item)To(1.Bound(Item)+1)Step-1Ifltem(×-1)>ltem(×)ThenTemp=ltem(×-1)ltem(x-1)=ltem(x)ltem(x)=TempExchange=TrueEndIfNextXForx=(1.Bound(Item)+1)To(UBound(Item)Ifltem(x-1)>ltem(x)ThenTemp=ltem(x-1)ltem(x-1)=ltem(×)ltem(x)=TempExchange=TrueEndIfNext×1.oopWhileExchangeEndSubAlthoughtheshakersortimprovesthebubblesort,itstillexecutesasann-squaredalgorithm.However,becausemostprogrammerscancodeabubblesortwiththeireyesclosed,thisisanicewaytoshave25to33percentofftherequiredexecutiontimewithouthavingtodigoutthealgorithmbooks.Still,youdon'twanttouseeitherabubbleorshakersortforextremelylargedatasets.TanShingHo,Kuala1.umpur,WestMalaysia专*专本*专*宇*今*车*专*与*冬*车才*拿*牟*多牟*专*车*今*拿*牟本*今*牟*拿*专今*牟*有今*卒*多*专*牟*专*VB432,VB5,VB61.evel:IntermediateSlamSelectedItemsintoanArrayUsethiscodetoretrieveallselectedlistitemsinamultiselect-stylelistboxinoneAPIcall.It,saloteasierthaniteratingthroughalargelistusingFor.Next.Thiscodeworksagainstbothnormalandcheckbox-stylelists:PrivateDeclareFunctionSendMessage1.ib"user32"Alias_"SendMessageA"(ByVaIhWndAs1.ong,ByVaIwMsg_As1.ong,ByVaIwParamAs1.ong,IParamAsAny)As1.ongPrivateConst1.B_GETSE1.COUNT=&H190PrivateConst1.B_GETSE1.ITEMS=&H191PrivateSubCommandl_Click()DimnumSelectedAs1.ongConst1.B_ERR=-1DimrAs1.ongDimiAsInteger,getthenumberofitemsselected.,lfthelistboxissingle-selectstyle,'numSelectedwillreturn-1(1.B_ERR).'Ifthelistboxismultiselectstyle,'andnothingisselected,numSelected'returns0.Otherwise,numSelectedreturns'thenumberselected(ala1.istl.SeICount)numSelected=SendMessage(1.istl.hWnd,1.B_GETSE1.COUNT,_0&,ByVaI0&)'debug.Debug.PrintnumSelected;"itemsselected:"Debug.Print"index","item"IfnumSelected<>1.B_ERRThen'dimanarraylargeenoughtohold'theindexesoftheselecteditemsReDimsSelected(lTonumSelected)As1.ong'passthearraysoSendMessagecanfill'itwiththeselecteditemindexesCallSendMessage(1.istl.hWnd,1.B_GETSE1.ITEMS,_numSelected,SSeIected(I)'debug.'printouttheitemsselected'notethattheirindexisO-basedFori=1TonumSelectedDebug.Print1.istl.1.ist(sSelected(i)NextEndIfEndSubRandyBirch,EastYork,Ontario,Canada*VB5,VB61.evel:IntermediateCallUpWindowsShellFeaturesHere,salittleroutinethatprovidesaquickanddirtywaytocallupsomeofthemoreoddballfeaturesoftheWindowsshell.Itworksbyemulatinguserkeystrokes,soyou,llneedtomodifythekeysfornon-Englishversions.SimplypastethiscodeintoastandardmoduleandpasstheEnumofchoice:PrivateDeclareSubkeybd_event1.ib"user32"(ByVaIbVkAs_Byte,ByVaIbScanAsByte,ByVaIdwFlagsAs1.ong,_ByVaIdwE×tralnfoAs1.ong)PublicEnumSystemKeyShortcutsExpIorerNew=&H45FindFiIes=&H46MinimizeAII=&H4DRunDiaIog=&H52StartMenu=&H5BStandbyMode=&H5EEndEnum,Asc("E'),Asc("F"),Asc("M")'Asc("R")'Asc(',")'Asc("a")-Win98only!PublicSubSystemActionVkActionAsSystemKeyShortcuts)ConstVK1.WIN=&H5BConstKEYEVENTF_KEYUP=&H2Callkeybd_event(VK_1.WIN,0,0,O)Callkeybd_event(VkACtion,0,0,0)Callkeybd_event(VK_1.WIN,O,KEYEVENTF.KEYUP,O)EndSubRandyBirch,EastYork,Ontario,Canada*VB5,VB61.evel:BeginningKeepTrackofIndexNumbersWhenusingcontrolarrays,Ifinditdifficulttokeeptrackoftheindexnumberofeachcontrol.Evenif1useconstants,Ioftenhavetolookuptheconstantnameforeachfield.Now,insteadofusingconstantsforeachindexnumber,Iusethiscode.First,Ideclareanenumeratedtypefortheindexnumbers:EnumFieIdConstants1.astName三OFirstName=1Age=2Address=3EndEnumIthencreateapropertywrapperforthecontrolarray.Thewrappertakesinanenumeratedconstantthatrepresentstheindexnumberandreturnsthecontrolinthearray:PropertyGetFields(ByValFieIdNumAsFieIdConstants)_AsTextBoxSetFields=txtFields(FieldNum)EndPropertyTheadvantagetothiswrapperisthatwhenyoutypethepropertyname,Fields,VBpromptsyouwiththeconstantnameslistedintheenumeratedtype.Thisway,youcanrefertocontrolsinthearraybyname,andyouneverhavetolookupconstantnamesagain.Also,itmakesthecodemorelegible:PrivateSubForm_1.oad()FieIds(1.astName),Text="Mojica"EndSubJoscMojica,Davie,Florida*拿*/*拿*拿*VB5,VB61.evel:BeginningIncludeCodeforDebuggingVBsupportsconditionalcompilation,justlikeVisualC+.However,VisualC+hasapredefinedconstantnamed_DEBUGthatmakesiteasytoincludecodeonlywhiledebugging,asinthiscode:#ifdef_DEBUGMessageBox(NU1.1.,"BeginProcedure",_"DebugMessage",MB_OK);#endifInVB,youcandothesamething,butyouneedtodeclarethevariableintheConditionalCompilationArgumentsfieldsintheMaketaboftheProjectpropertiesdialog,thenremembertoremoveitbeforeshippingtheexecutable.UsingtheDebug.Assertcommandisaneasierwaytohavestatementsexecutedonlywhiledebuggingandnotwhenrunningacompiledprogram.Forexample,thislinedisplaysamessageboxonlywhenrunningtheprograminthedesignenvironmentandnotinacompiledprogram:Debug-AssertMsgBox("BeginForm_1.oad")ThishappensbecauseDebug.Assertworksonlyinthedesignenvironment.Toevaluatetheassertion,VBexecutesthestatement.However,whenyoucompiletheprogram,thecompilerremovesthislinefromtheexecutable.JoseMojica,Davie,FloridaVB432,VB5,VB61.evel:IntermediateNlXTHEXSometimes,youwanttoshowaformthatyoudon,twantuserstobeabletocancelbyclickingontheXitmightnotmakesenseforyourapp.ThebestVBsolutionistocanceltheunloadinthefbrm,sQucryUnloadevent.However,thisallowsuserstodosomethingwrong,forwhichyouthenhavetohandleandscoldthem.Ifyoudonothing,itlooksasiftheformhasabugandwon,tcancel.AddthisroutinetoastandardBASmodule:PrivateDeclareFunctionGetSystemMenu1.ib"user32"_(ByVaIhWndAs1.ong,ByVaIbRevertAs1.ong)As1.ongPrivateDeclareFunctionRemoveMenu1.ib"user32"_(ByVaIhMenuAs1.ong,ByVaInPositionAs1.ong,_ByVaIwFlagsAs1.ong)As1.ongPrivateConstMF_BYPOSITION=&H400&PublicSubRemoveCancelMenultem(frmAsForm)DimhSysMenuAs1.ong,getthesystemmenuforthisformhSysMenu=GetSyStemMenU(frm.hWnd,O)'removethecloseitemCallRemOVeMenU(hSysMenu,6,MF-BYPOSITION)'removetheseparatorthatwasoverthecloseitemCallRemoveMenu(hSysMenu,5,MF_BYPOSITION)EndSubThencalltheroutinefromanyformasitloads:PrivateSubForm_1.oad()RemoveCanceIMenuItemMeEndSubAfterthiscall,theClosemenuiteminthesystemmenuandtheoptiontocancelXwillbedisabled.Notethatifyou,redoingotherthingswiththesystemmenu,youmighthavetoadjustthepositionnumberintheRemoveMenucall.JoshFrank9Parsippany9NewJersey*辛*余*辛*零*辛*零*辛*余*率*拿*辛*辛*零*率卒*余*辛*辛*拿*率*余辛*拿*卒*辛*小*余辛*VB3,VB416/32,VB5,VB61.evel:BeginningComputeCreditCardCheckDigitsThelastdigitinyourcreditcardnumberisacheckdigitderivedfromtheotherdigitsusingthe1.uhnFormulaasdescribedinISO/IEC7812-1:1993.Itsprimarypurposeistoensureaccurateentriesofthecreditcardnumberduringtransactions.Youcanapplythesametechniquetootherapplicationssuchasemployeenumbersorpatientnumbers.Usingcheckdigitsforthesenumbersalsoensuresmoreaccuratedataentries:PublicFunctionCheckDigit(strNumAsString)AsIntegerDimiAsIntegerDimiEvenAsIntegerDimiddAsIntegerDimiTotalAsIntegerDimStrOneCharAsStringDimiTempAsInteger,Adddigitsinevenordinalpositions'startingfromrightmostFori三1.en(StrNum)-1To2Step-2StrOneChar=Mid$(StrNUm,i,1)IfIsNumeric(StrOneChar)TheniEven=iEven+CInt(StrOneChar)EndIfNexti'Processdigitsinoddordinalpositions,startingfromrightmostFori=1.en(StrNum)To1Step-2StrOneChar=Mid$(StrNUm,i,1)IfIsNumeric(StrOneChar)Then,DoubleitiTemp=CInt(StrOneChar)*2IfiTemp>9Then,Breakthedigits(e.g.,19becomes1+9)idd=idd+(iTemp10)+(iTemp-10)Elseidd=idd+iTempEndIfEndIfNexti,AddevenandoddiTotal=iEven+idd,Returnthe10'scomplementCheckDigit=10-(iTotalMod10)EndFunctionTotest,passyourcreditcardnumber,excludingthelastdigit,asastringparameter.Theresultshouldbethelastdigitofyourcreditcardnumber.ArnelJ.Domingo,HongKong*率*弥*京京*拿*VB432,VB5,VB61.evel:AdvancedUseThisHigher-ResolutionSTOPWATCHUsethiscodetocreateaclasscalledHiResTimer:'ThenumberiscodifiedasHighPart*232+1.owPartPrivateType1.ARGEJNTEGER1.owPartAs1.ongHighPartAs1.ongEndTypePrivateDeclareFunctionQueryPerformanceCounter1.ib_"kernel32"(IpPerformanceCountAs1.ARGEJNTEGER)_As1.ongPrivateDeclareFunctionQueryPerformanceFrequency1.ib_,kernel32"(IpFrequencyAs1.ARGEJNTEGER)As1.ongPrivatemTicksPerSecondAsDoublePrivatem_1.IOAs1.ARGE_INTEGERPrivatem_1.llAs1.ARGEJNTEGERFriendSubClass_lnitialize()Dim1.IAs1.ARGEJNTEGERIfQueryPerformanceFrequency(1.I)<>0Thenm-TicksPerSecond=1.I2Double(1.I)Elsem-TicksPerSecond=-1EndIfEndSubFriendPropertyGetResolution()AsDoubleResolution=1#/m_TicksPerSecondEndPropertyFriendSubEnterBIockOQueryPerformanceCounterm_1.I0EndSubFriendSubE×itBlock()QueryPerformanceCounterm_1.llEndSubFriendPropertyGetEIapsedTimeOAsDoubleDimEnterTimeAsDouble,ExitTimeAsDoubleEnterTime=1.I2Double(m-1.I0)/m_TicksPerSecondExitTime=1.I2Double(m_1.ll)/m_TicksPerSecondEIapsedTime=ExitTime-EnterTimeEndPropertyFriendFunction1.I2Double(1.IAs1.ARGEJNTEGER)AsDoubleDim1.owAsDoubleConstTWO_32=4#*1024#*1024#*1024#1.ow=1.1.1.owPartIf1.ow<OThen1.ow=1.ow+TWO_32'Now1.owisint