📄 189.htm
字号:
------------------------------------------------------------------------ <br>
Section 8. Tools for Delphi <br>
8.1. Is there YACC and LEX for Delphi? <br>
<br>
There is a YACC and LEX written by Albert Graef (ag@muwiinfa.geschichte.uni-mai <br>
nz.de) for Turbo Pascal that works with Delphi. This can be found on many share <br>
ware sites (search for Pascal and YACC). <br>
<br>
One location is /msdos/turbopas/tply30a1.zip and /msdos/turbopas/tply30a2.zip in <br>
the Simtel archives. <br>
<br>
<br>
<br>
8.2. How can I write code to display JPEG files? <br>
<br>
nomssi@physik.tu-chemnitz.de has a Pascal library based of the Independent JPEG <br>
Group's free JPEG library. It is available from the following locations: <br>
<br>
ftp://druckfix.physik.tu-chemnitz.de/pub/nv/ <br>
http://www.tu-chemnitz.de/~nomssi/pub/pasjpeg.zip <br>
<br>
------------------------------------------------------------------------ <br>
Section 9. Basic Programming Techniques <br>
9.1. How do I create a dynamic array of objects? <br>
<br>
The easiest way to create an array of objects is to use a TList control. I ofte <br>
n find it helpful to create specialized classes that derive from TList. The foll <br>
owing class shows how to create a list for a specific type of object that has a <br>
little better error reporting than the basic TList. For you own list you may ne <br>
ed to implement more methods. <br>
<br>
TListOfMyObject = class (TList) <br>
Private <br>
Function GetItems (Index : Ordinal) : TmyObject ; <br>
public <br>
public <br>
Property Items [Index : Ordinal] : TmyObject Read GetItems ; <br>
Procedure Add (AObject : TmyObject) ; <br>
End ; <br>
<br>
Function TListOfMyObject.GetItems (Index : Ordinal) : TmyObject ; <br>
Begin <br>
If Index >= Count Then <br>
raise Exception.CreateFmt ('Index (%d) outside range 1..%d', [Index, Count - <br>
1 ]) ; <br>
Result := Inherited Items [Index] ; <br>
End ; <br>
<br>
Procedure TListOfMyObject.Add (AObject : TmyObject) ; <br>
Begin <br>
Inherited Add (AObject) ; <br>
End ; <br>
<br>
9.2. Where is the Wincrt unit in Delphi 2.0? <br>
<br>
There is no WinCrt unit in Delphi 2.0. It has been replaced by a project options <br>
setting. On the linker page there is an option to create a console application <br>
. Check this rather than use the WinCrt unit. <br>
<br>
9.3. What should the base class be for my component? <br>
<br>
If you are deriving from an existing component then the class of the component y <br>
ou wish to derive from should be the base class. Several of the registered VCL <br>
component classes are immediate ancestors of corresponding custom classes (e.g. <br>
TMemo descends from TCustomMemo). These custom classes implement most of the fu <br>
nctionality of the control but they do not publish many of the properties that t <br>
hey define. In most cases you are probably better off deriving your component <br>
from the custom class rather than the well known registered class. <br>
<br>
If you are creating a component from scratch then TCustomControl is most likely <br>
your best choice. This is used for visual, windowed controls. <br>
<br>
Other less likely alternatives are: <br>
<br>
TGraphicControl - For visual controls that have no associated window. These can <br>
not receive input focus. <br>
<br>
TComponent - Non-visual component. <br>
<br>
TWinControl - To create a control that derives from an existing control that was <br>
hat derives from an existing control that was <br>
not created specifically for Delphi. <br>
<br>
9.4. What is the difference between the Free and Destroy methods ? <br>
<br>
From Xavier Van Dessel <br>
<br>
Free is a static method on TObject and Destroy is a virtual/dynamic method. <br>
This means that any call to Free will compile to a straight call into <br>
TObject.Free. The implementation of TObject.Free is very simple: <br>
<br>
Procedure TObject.Free; <br>
Begin <br>
If Self<>Nil Then <br>
TObject.Destroy; <br>
End; <br>
<br>
As you can see, the only thing Free does, is check whether the object that is <br>
being freed, really exists. If it exists (the pointer Self points to <br>
something), then the Destroy method is called. The reason for this complex way <br>
of releasing storage is that Destroy is a virtual/dynamic method, and thus <br>
should only be called when it is possible to determine the class the object <br>
belongs <br>
class the object <br>
belongs to. But this can only be done if an object really exists, otherwise you <br>
belongs to. But this can only be done if an object really exists, otherwise you <br>
<br>
would get GPF's and exceptions. <br>
An example will clarify this: <br>
<br>
Class AnObject(Object) <br>
FObject1, <br>
FObject2 : TObject; <br>
Constructor Create; Override; <br>
Destructor Destroy; Override; <br>
End; <br>
<br>
Constructor AnObject.Create; <br>
Begin <br>
FObject1:=TObject.Create; <br>
Raise Exception('Dummy Exception'); <br>
FObject2:=TObject.Create; <br>
End; <br>
<br>
Destructor AnObject.Destroy; <br>
Begin <br>
FObject1.Free; <br>
FObject2.Free; <br>
Inherited Destroy; <br>
End; <br>
<br>
This Object creates 2 sub-objects, but for some reason there occurs an <br>
exception between the 2 creations. As the exception occurs in the Create of <br>
AnObject, the Destroy Destructor will be executed automatically. FObject1 <br>
exists, and therefore it will be freed (by calling its Destroy Destructor <br>
method). But FObject2 is still Nil. So Free will find out that in fact FObject2 <br>
<br>
does not exist anywhere, and the Destroy method will NOT be called. Note that <br>
all attributes of AnObject get initialised (before the Create) into binary <br>
zeroes, which causes all sub-objects to be Nil pointers. <br>
<br>
You should NEVER override Free, but you should always override the Destroy <br>
Destructor method. Don't forget to code the 'Override' keyword in the <br>
declaration in the class, otherwise you code should not get executed. <br>
In the implementation of Destroy, you should ALWAYS call Inherited Destroy, <br>
preferably as last statement (as in the example above). <br>
<br>
------------------------------------------------------------------------ <br>
<br>
Section 10. Advanced Programming Techniques <br>
mming Techniques <br>
10.1. Is there a Delphi equivalent to C++'s I/O Stream classes? <br>
<br>
Yes and no. Delphi allows you to create your own "Text-File Device Driver" whic <br>
h allows you to use standard Delphi I/O procedures for non-standard I/O streams <br>
such as Unix <LF> files or network connections. These are not as powerful as C+ <br>
+ I/O Streams but it is possible to get around their limitations. <br>
<br>
The procedure for creating a Text-File Device Driver is reasonably well document <br>
ed in the "Object Pascal Langue Guide" and there is one example in the VCL sourc <br>
e in PRINTER.PAS. <br>
<br>
Delphi also has stream classes for writing objects to a stream. These are not a <br>
s "general purpose" as C++'s I/O streams. <br>
<br>
10.2. How can I get the text equivalent for an enumerated type? <br>
<br>
Use the function GetEnumName located in the module TypInfo. <br>
<br>
Type <br>
TMyType = (Value1, Value2) ; <br>
... <br>
Var <br>
Var <br>
TypeValue : TmyType ; <br>
... <br>
WriteLn (GetEnumName (TypeInfo (TMyType), Ord (TypeValue)) ; <br>
<br>
The module TypInfo has many other functions for obtaining information about type <br>
s. <br>
<br>
The book "Secrets of Delphi 2.0" has a lot of information on how to us the TypIn <br>
fo module. <br>
<br>
------------------------------------------------------------------------ <br>
Section 11. Component Virtual Methods <br>
11.1. How can I find out when my component has had its window handle created? <br>
<br>
A control's window handle is created by the CreateWnd method. If you have proce <br>
ssing that needs to be performed after the window handle is created then you can <br>
override CreateWnd and do <br>
<br>
Procedure TMyClass.CreateWnd ; <br>
Begin <br>
Inherited CreateWnd ; { Don't forget or you'll never get a window handle. } <br>
<br>
<br>
{ Your processing goes here. } <br>
End ; <br>
<br>
11.2. How can I tell when all the components on my form have been loaded? <br>
<br>
The Loaded method is called for each component on a form after all controls on t <br>
he form have been loaded from the stream. <br>
<br>
Procedure TMyClass.Loaded ; <br>
Begin <br>
Inherited Loaded ; { Clears the csLoading in ComponentState } <br>
<br>
{ Your processing goes here. } <br>
End ; <br>
<br>
11.3. Where is the best place to draw my control? <br>
<br>
You could intercept the WM_PAINT message and set up your control's canvas howeve <br>
r will VCL do all this work for you if you simply override the Paint method in y <br>
our control. <br>
<br>
Procedure TMyClass.Paint ; <br>
Begin <br>
{ You only need to call inherited Paint if your class inherits <br>
directly from TCustomControl or TGraphicControl. You may need <br>
to call this if your control inherits from an existing control. } <br>
<br>
Inherited Paint ; <br>
<br>
<br>
<br>
{ Your processing goes here. } <br>
End ; <br>
<br>
11.4. How do I change the Window Style for my control. <br>
<br>
The CreateParams method is used to set up the window style and all the other arg <br>
uments that are passed to CreateWindowEx to create the control's window.To chang <br>
e the window style use something like this which creates a window with or withou <br>
t a vertical scroll bar. <br>
<br>
procedure TMyControl.CreateParams(var Params: TCreateParams) ; <br>
Begin <br>
Inherited CreateParams (Params) ; <br>
Inherited CreateParams (Params) ; <br>
IF IWantAScrollBar Then <br>
Params.Style := Params.Style OR WS_VSCROLL <br>
Else <br>
Params.Style := Params.Style AND NOT WS_VSCROLL ; <br>
End ; <br>
<br>
------------------------------------------------------------------------ <br>
Section 12. Windows API Functions <br>
<br>
12.1. I am trying to scroll the contents of my control but I get an ugly flicker <br>
effect. How can I eliminate this? <br>
<br>
The easiest way to scroll the elements of a control is to change all of their co <br>
ordinates then to force a repaint of the control. Unfortunately this produces t <br>
he flicker effect. <br>
<br>
The best way to reduct this flickering is to use the ScrollWindow or ScrollWindo <br>
wEx Windows API function. <br>
<br>
Another source of flickering can be from Windows using two messages to paint: WM <br>
_PAINT and WM_ERASEBKGND. You may want to intercept all of the WM_ERASEBKGND me <br>
ssages and do all of your painting, including the background, in response to WM_ <br>
PAINT messages in the Paint method. <br>
<br>
12.2. How can I restart windows? <br>
<br>
Use the ExitWindowsEx function. <br>
<br>
12.3. How can I batch updates to when changing the appearance of my control? <br>
<br>
Sending the WM_SETREDRAW message to your control can either set or clear the fla <br>
g used to determine if a control is redrawn. <br>
------------------------------------------------------------------------ <br>
<br>
Section 13. Control Borders <br>
13.1. How come my control does not have a 3D border even when I have CTL3D set t <br>
o True? <br>
<br>
CTL3D has no effect unless csFramed is set in ComponentStyle. Try something like <br>
this inside your constructor: <br>
<br>
ComponentStyle := ComponentStyle + [csFramed] ; <br>
<br>
13.2 How do I implement a BorderStyle property? <br>
13.2 How do I implement a BorderStyle property? <br>
<br>
The trick to having a control border is that the border must be created when the <br>
control's Window handle is created. <br>
<br>
FBorderStyle : TBorderStyle ; <br>
Procedure SetBorderStyle (Style : TBorderStyle) ; <br>
Property BorderStyle : TBorderStyle Read FBorderStyle write SetBorderStyle ; <br>
procedure CreateParams(var Params: TCreateParams) ; Override ; <br>
<br>
procedure TMyControl.CreateParams(var Params: TCreateParams) ; <br>
Begin <br>
Inherited CreateParams (Params) ; <br>
If FBorderStyle = bsSingle Then <br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -