730 likes | 1.24k Views
Delphi Tips & Techniques. Brian Long (brian@falafel.com) Master Consultant Falafel Software. Before We Begin. Hours: 8:00 – 12:00 Break Time: 10:00 – 10:30 Please ask questions as we go along Let’s keep this informal. Agenda. The IDE The language The RTL The debugger Windows .NET.
E N D
Delphi Tips & Techniques Brian Long (brian@falafel.com) Master Consultant Falafel Software
Before We Begin • Hours: 8:00 – 12:00 • Break Time: 10:00 – 10:30 • Please ask questions as we go along • Let’s keep this informal
Agenda • The IDE • The language • The RTL • The debugger • Windows • .NET
The IDE • Toolbars • The Editor • The Form Designers • The Object Inspector • Miscellaneous • Enhancing from within • Undocumented registry entries
Toolbars • Save mouse-clicks with the File | Open toolbutton’s drop down menu • Less need to switch to the Project Manager with the Run | Run tool button’s drop down button • Avoid unneeded debugging with Run | No Debug • Restore corrupted toolbars • Move toolbars between systems
Code Insight et al Code Folding Refactoring Help Insight Error Insight Editor bookmarks Keyboard macros Case switching Buffer list Block marking Block indent / unindent Block operations Bracket matching Various selection / deletion operations Incremental search Drag & drop The Editor
The Editor • An overwhelming number of keyboard shortcuts available • In Delphi 7 help under “shortcuts” • In Delphi 8/“Diamondback” help via Reference | Keyboard Mappings • Many based on the ancient WordStar word processor keyboard shortcuts • Many were present in Turbo Pascal & Borland Pascal • Ctrl+Q+? is a Quick operation • Ctrl+K+? is a blocK operation • Ctrl+O+? is an Other operation • More recent additions just fill in any available gaps
The Editor • Code Insight – Code Completion • Manually invoked by Ctrl+Space • Supports being alpha-sorted • Supports being resized • Supports automatically adding units into the uses clause:HKCU\...\7.0\Code Insight\ExtraUnits(feature removed in Delphi 8, replaced in Delphi “Diamondback” with new option:Refactor | Find Unit)
The Editor • Code Insight – Code Parameters • Manually invoked with Ctrl+Shift+Space • Code Insight – Code Templates • Manually invoked with Ctrl+J • Stored in the text file delphi32.dci / bds.dci
The Editor • Code browsing • Ctrl+click on an identifier • context menu, Find declaration • Navigation buttons: Alt+← & Alt+→ • Module navigation • Ctrl+Shift+↓ or Ctrl+Shift+↑ • Class completion • Ctrl+Shift+C • Good property implementation
The Editor • Code Folding • Ctrl+Shift+K+G Fold interface and implementation • Ctrl+Shift+K+EFold | Nearest • Ctrl+Shift+K+N Fold | Namespace (Unit) • Ctrl+Shift+K+C Fold | Types • Ctrl+Shift+K+M Fold | Methods • Ctrl+Shift+K+R Fold | Regions • Ctrl+Shift+K+P Fold | Nested Methods • Ctrl+Shift+K+U Unfold | Nearest • Ctrl+Shift+K+A Unfold | All • Ctrl+Shift+K+O Toggle code folding
The Editor • Refactoring • Ctrl+Shift+V Declare Variable • Ctrl+Shift+D Declare Field • Ctrl+Shift+M Extract Method • Ctrl+Shift+L Extract Resource String • Ctrl+Shift+A Find Unit • Ctrl+Shift+E Rename • Ctrl+Shift+J Sync Edit
The Editor • Help Insight • Enabled by default • Ctrl+Shift+H • Works with Code Completion window • Error Insight • Enabled by default • Symbol existence verification
The Editor • Bookmarks • Toggle: Ctrl+Shift+n or Ctrl+K+n • Go to: Ctrl+n or Ctrl+Q+n (n = 0, 1, 2, ..., 9) • Not persisted in project desktops • Alternative is to use disabled breakpoints, which are persisted • Use the Breakpoints window to navigate (View | Debug Windows | Breakpoints)
The Editor • Keyboard macros: • Start/stop recording: Ctrl+Shift+R • Playback: Ctrl+Shift+P • Limited to editor keystrokes only • Macro toolbar (added officially in Delphi 8, unofficially in Delphi 7)
The Editor • Case-switching: • Upper case: Ctrl+K+N • Lower case: Ctrl+K+O • Toggle case: Ctrl+O+U • Buffer list: • Ctrl+B • Implemented in Win32 DclSmpEdit70.dpk ToolsAPI package demo
The Editor • Block marking • Shift+navigation keys • Non-inclusive: Ctrl+O+K (default) • Inclusive: Ctrl+O+I • Line: Ctrl+O+L • Column: Ctrl+O+C • Alt+Shift+navigation keys or Alt+mouse • Column block marking
The Editor • Block indent • Ctrl+Shift+I • Ctrl+K+I • Block unindent • Ctrl+Shift+U • Ctrl+K+U
The Editor • Block operations • Toggle comment: Ctrl+/ • Write to text file: Ctrl+K+W • Read from text file: Ctrl+K+R • Print: Ctrl+K+P
The Editor • Bracket matching (almost obsolete in Delphi 8+) • Alt+[ • Alt+] • Ctrl+Q+[ • Ctrl+Q+] • Matches {,} and (,) • Does not match begin,end
The Editor • Selecting the current word • Ctrl+K+T • Deleting to the next word • Ctrl+T • Deleting to the end of the line • Ctrl+Shift+Y, Ctrl+Q+Y • Deleting the current line • Ctrl+Y
The Editor • Selecting the current line • Ctrl+K+L • Selecting lines • Home, Shift+↑ or Shift+↓ • Incremental search • Ctrl+Shift+S (or Ctrl+E in Classic)
The Editor • Drag & drop • Dragging text moves it • Ctrl+dragging text copies it • Same functionality as Microsoft Word • Preserves clipboard content
The Form Designers • Selecting a component’s parent • Escape • Selecting the form • VCL: Select a component, then Shift+click it • WinForms: Click form caption bar • Lassoing on a container • VCL: Ctrl+drag mouse • WinForms: drag the mouse
The Form Designers • Moving & sizing components:
The Object Inspector • Property editor keyboard access • Ctrl+Enter • Incremental property search • Tab • Instance list • Ctrl+↓ • Following linked components (VCL-only) • Ctrl+double-click
Miscellaneous • Drag & drop RAD now works (kinda)! • MPD keyboard shortcuts • Ctrl+Tab and Shift+Ctrl+Tab • IDE memory consumption • IDE command line switches –hm and -hv • Preventing docking • Hold down Ctrl • Use the environment option
Enhancing from within • Implement a Win32 package • In Register procedure use e.g.: • Application • Application.MainForm • Application.FindComponent • Modify aspects of IDE as you choose • Tidy up in the finalization section • Use ToolsAPI for official route
Undocumented registry • All relative to HKCU\Software\Borland\ • Removing Ctrl+Alt shortcuts Delphi\7.0\Editor\Options\NoCtrlAltKeys="1“ Tools | Options | Editor Options | Key Mappings | Use Ctrl+Alt keys • Delphi 7 Macro toolbar (as in later versions) Delphi\7.0\Extras\ShowRecordMacro="1" • Delphi for .NET Reflection IL Disassembly BDS\3.0\Globals\ShowILDisassembly="1" • Designer Insight (WinForms) BDS\3.0\DesignerInsight\Visible="1"
The IDE • End of section
The language • Iterations • Logical assignments • Logical array indices • Typed constants • Sets & cases • Accessing protected members • Accessing private members • Characters • Concise object creation
The language • Iterations - extension to for loop syntax
The language • Iterations - extension to for loop syntax
The language • Iterations - extension to for loop syntax
The language Logical assignments
The language • Logical array indices • Arrays need not be indexed by numbers • A typical array is specified using a subrange, e.g.:MyArray[ 1..10 ] of Byte; • Subranges can be made from any ordinal type, e.g.:MyArray[ Boolean ] of String;
The language • Typed constants • Very useful for initialising constant arrays & records • Currently defaults to actually being constant • Toggling the option allows them to be used like C static variables: • {$WRITEABLECONST ON} • {$J+}
The language • Typed constants • procedure TForm1.UpdateUI; • begin • if Length( Trim( edtTextEntry.Text ) ) = 0 then • Bar.SimpleText := 'No text to add' • else • Bar.SimpleText := 'You can add the text' • end; • ↓ • procedure TForm1.UpdateUI; • const • Desc: array[ Boolean ] of String = • ( 'No text to add', 'You can add the text' ); • begin • Bar.SimpleText := • Desc[ Length( Trim( edtTextEntry.Text ) ) <> 0 ]; • end;
The language • Sets & cases • Conditionals easily become cumbersome (develop a surfeit of brackets) • Conditionals that compare a variable against a number of values can be simplified using sets or case statements • If the values have an ordinal value less than 256 a set can be used • Otherwise you can employ a case statement
The language • Sets & cases • procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); • begin • if (Key = VK_UP) or (Key = VK_DOWN) or • (Key = VK_LEFT) or (Key = VK_RIGHT) then • begin • Bar.SimpleText := 'Cursor key'; • Key := 0; • end • else • if (Key = VK_PRIOR) or (Key = VK_NEXT) then • begin • Bar.SimpleText := 'Page movement key'; • Key := 0; • end • else • Bar.SimpleText := 'Miscellaneous key' • end;
The language • Sets & cases • procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); • begin • if Key in [ VK_LEFT..VK_DOWN ] then • begin • Bar.SimpleText := 'Cursor key'; • Key := 0; • end • else • if Key in [ VK_PRIOR, VK_NEXT ] then • begin • Bar.SimpleText := 'Page movement key'; • Key := 0; • end • else • Bar.SimpleText := 'Miscellaneous key' • end;
The language • Sets & cases • procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); • begin • case Key of • VK_LEFT..VK_DOWN: • begin • Bar.SimpleText := 'Cursor key'; • Key := 0; • end; • VK_PRIOR, VK_NEXT: • begin • Bar.SimpleText := 'Page movement key'; • Key := 0; • end • else • Bar.SimpleText := 'Miscellaneous key' • end • end;
The language • Concise object creation (who needs a variable?) • procedure TForm1.Button1Click(Sender: TObject); • const • RegPath = 'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced'; • RegEntry = 'HideFileExt'; • begin • with TRegistry.Create do • try • if OpenKey( RegPath, False ) then • WriteInteger( RegEntry, 0 ) • finally • Free • end • end;
The language • Accessing protected members • Delphi’s definition of protected is not the same as in C++ • It’s more like C++’s protected with friend classes • Rather like C#’s protected internal • Akin to .NET CLR’s family or asembly • Protected members are accessible to: • any derived classes • any code in the target class’s unit
The language • Accessing protected members • A common trick is to implement so called “access” classes or “hack” classes to gain access to protected members • An access class is a shallow descendant defined in the unit where access is required: type TWCAccess = class( TWinControl ); • Used several times in the VCL source • Search VCL / VCL for .NET source for: Access = class(T
The language • Accessing protected members • Another trick uses “interposer” classes • These are defined in the unit requiring access • Distinguishing feature is the name is the same as the original, thereby removing the need for a typecast: type TDBGrid = class( DBGrids.TDBGrid );
The language • Accessing private members • No easy answer to this except hacking • Relies on you knowing: • how many data fields precede the target private data field • Which class the field was added in • how many bytes they take up • Add to this the ancestor class’s instance size • You now have the offset from the start of the instance data
The language • Accessing private members • function GetPrivateField(Obj: TObject; Cls: TClass; DataOffset: Cardinal): Pointer; • var • ParentInstanceSize: Cardinal; • begin • //Get parent instance data size • //and add on the VMT pointer • ParentInstanceSize := Cls.ClassParent.InstanceSize + 4; • Result := Pointer( Cardinal( Obj ) + ParentInstanceSize + DataOffset ) • end; • var • FocusedCtl: TWinControl; • ... • FocusedCtl := TWinControl( • GetPrivateField( Self, TCustomForm, 4 )^ );
The language • Characters • Characters don’t need concatenation • They can be effectively embedded in the string as long as there is no white spaceCaption := 'Copyright '#169' 2004, Me';
The language • End of section