Pascal Newsletter #13
The full source code examples of this issue are available for download.
![]() |
![]() |
Pascal Newsletter #13 - 24-DEC-2000 INDEX 1. A FEW WORDS FROM THE EDITOR 2. NON-RECTANGULAR SHAPES - Part I 3. OPENGL APPLICATIONS WITH DELPHI 5.0 - FIRST STEPS 4. OPENING MICROSOFT ACCESS .MDB DATABASES WITH DELPHI - ADO - BDE - BDE + ODBC 5. LISTING THE TABLES AND QUERIES IN A DATABASE 6. LINKS ________________________________________________________________________ 1. A FEW WORDS FROM THE EDITOR In this issue Alirio Gavidia will be showing us with two examples how easy is to make non-rectangular forms. Leopold Minikus, from Minais - Individual Cad Software, submitted us an article presenting their set of OpenGL components to help you build 3D applications with Delphi 5. You can download the MNOgl component collection from for free from the minais web site: http://www.minais.at The download includes sample projects. If you need help or have questions about the articles presentend in this newsletter, you can post them to our forum/mailing list. Your problems and doubts might be the problems and doubts of other members of the forum that will also benefit from reading the questions and answers. In order to subscribe, simply send a blank email to delphi-en-subscribe@yahoogroups.com This a free service provided by http://www.egroups.com and they don't spam, although they include a little ad in each message (of which I don't see a cent, just in case you wonder). If you need more information, please visit: http://www.latiumsoftware.com/en/forums.html Regards, Ernesto De Spirito eds2004 @ latiumsoftware.com ________________________________________________________________________ JfControls Library. Multi-language. Multi-appearance. Skins. Privileges. More than 40 integrated and customizable components. Impressive GUI. Centralized resources administration. Multiple programming problems solved. For Delphi 3-7 and C++ Builder 3-6. http://www.jfactivesoft.com/ ________________________________________________________________________ 2. NON-RECTANGULAR SHAPES - Part I Copyright (c) 2000 Alirio Gavidia <alirio@gavidia.org> To see more of my articles visit: Programación Orientada en Delphi (site in Spanish) http://www.gavidia.org/pod/ Translated by Ernesto De Spirito Introduction. ============= The present essay intends to show the possibilities of use of non- rectangular shapes under Windows. The use is simple, but the possibilities look interesting. Additionally, in particular in this first part, we will make use of two important elements: "Canvas" and "Timer". The first example. ================== In the previous article (see "POST-IT". SIZABLE WINDOWS WITHOUT BORDER OR TITLE in http://www.latiumsoftware.com/en/pascal/0010.php ) I made reference to the possibility of creating an analog round clock like the one of Windows "PowerToys". Making a round form is simple and it is limited to calling a couple of procedures. The clock must also draw the hands (which requires certain mathematic calculation) and update about 60 times per minute (this is what the "TTimer" is for). Note: Analog Clock in opposition to Digital. The term is NOT correct because the clock we create here -even if it has hands- is digital. For the clock to really imitate an actual analog behavior it would have to have a continuos movement. The one we create here moves from second to second and therefore it has finite and defined states and that makes it qualify as digital. It seems a more adequate term is "hands clock". Without title. ============== The clock is based on a simple borderless form, eliminating the title bar, which results in a bother when we have a round form. This generates the additional problem of moving the form. For this reason the drag operation should be attended from the client area of the form. To solve this inconvenience there are various ways. I choose the one applied in the previous article (use of wm_Syscommand $f012): procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin ReleaseCapture; Perform(wm_Syscommand, $f012, 0) end; Another technique is responding to "Wm_NcHitTest" and returning "htCaption" as the result. This is simply telling Windows that the clic was made in the title area. It seems to me that there is at least another technique, but it isn't the objective of this essay. The "timer". ============ In the form we included a "TTimer" control. This control fires an event approximately at intervals (defined by the "interval" property given in milliseconds). Its use is well documented in Delphi, but I must add something: it isn't exact. The event associated with the timer executes three actions: eliminates the hands from the previous position, takes the system time, and puts the hands in a new position. The "Canvas". ============= The "Canvas" provides graphical capacities for graphic controls and forms. I offers possibilities to draw lines, ellipses, polygons, text and others. Its usage is simple and practical. We made use of the following elements of the "Canvas": * "Pen", to set the color and mode of the line draw. * "MoveTo", to set the initial point of a line draw. * "LineTo", to draw a line from the last position to the new one. * "Rectangle", to draw a rectangle according to the given parameters. Particularly we have to note the property "Canvas.Pen.Mode" that allows the use of values like "pmXor" or "pmCopy" (among many others). Note: The use of "Xor" as a logical operator has an interesting property which is that applied twice you get the original value, i.e.: "x xor y" results in "z", and if you apply "xor y" again to "z" it results in "x". This is useful for simple encrypting where we want to apply a key to encrypt and the same key and the same algorithm to decrypt. It is also useful when we want to draw something and then erase it because it is only required to draw it again applying a "xor" between the background and the pixel to draw. The "Paint" event of the form certainly makes use of the Mode and Color properties of the Pen obtaining a curious effect. The result, at least for me, wasn't the expected, however it was nice. All this seems to be the consequence of the way in which a rectangle is created. It is filled and then the upper and left border are drawn, that under the "Xor" operator generate a white color and the resulting image generates a 3D effect. I suggest the reader to comment out the lines "Mode" and "Color" to draw his own conclusions. As an additional comment, "Pen.Color" only affects the border of the rectangle. The filling is defined by the "Brush" property of the "Canvas" which in this case remains with its default value. procedure TForm1.FormPaint(Sender: TObject); Var X1, Y1, i : integer; Angle : double; begin Canvas.Pen.Mode := pmXor; Canvas.Pen.Color := clBtnFace; for i:=1 to 12 do begin Angle := i * 2 * Pi / 12; X1 := trunc(X0 + Len * Sin(Angle)); Y1 := trunc(Y0 - Len * Cos(Angle)); Canvas.Rectangle(X1-4,Y1-4,X1+4,Y1+4) end; Canvas.Pen.Mode := pmCopy; Canvas.Pen.Color := clBlack; end; Arithmetic. =========== The coordinates system has the point zero in the upper-left corner. To determine the position of the hand we need the center and the ending point. The center is the half of the width and the height. For the length of the hands we take a fraction of the minimum between the width and the height. Knowing the center and length of the hand, we only need to know the position of its ending point and for this we determine the angle. Here we end up turning to trigonometry. The angle is determined with the zero in 12 o'clock, 90 degrees at 3 o'clock, 180 degrees at 6 and 360 at 12. The sine of the angle gives us the opening in the "X" coordinate, while the cosine gives us the opening of the "Y" coordinate. As an additional remark, the coordinates system in the "Y" axis is inverted with respect of the usual trigonometric systems. All angles must be expressed in radians to be used with the sine and cosine functions. The procedure "DrawWatchHand" makes the calculations (also in "FormPaint") procedure Tform1.DrawWatchHand; : : // Now draw Second Canvas.MoveTo(X0, Y0); Angle := S * 2 * Pi / 60; X1 := trunc(X0 + 9*Len * Sin(Angle)/10); Y1 := trunc(Y0 - 9*Len * Cos(Angle)/10); Canvas.LineTo(X1, Y1); : : Notice that each hand hand uses a proportion of the Len value. For example the seconds are 9/10 of Len, minutes are 3/4 and hours are 1/2. Round. ====== Until now we have used the "Canvas" to draw, eliminated the title bar and substituted its functionality, we have done some arithmetic and we have made use of a "timer". The central point that gives title to this article is the creation of a non-rectangular shape. Well, this is tremendously easy and is solved with two calls to Windows in the "FormCreate" of the main form: hRegion := CreateEllipticRgnIndirect(R); SetWindowRgn(handle, hRegion, true); "CreateEllipticRgnIndirect" is a version of "CreateEllipticRgn" with the parameters (a rectangle) packed in only one structure. This routine returns a "handle" to an elliptic region circumscribed to the given rectangle. If you want you can define non-circular regions using "CreatePolygonRgn" for polygons, "CreateRectRgn" for rectangles (without sense in our case, but it is possible), "CreateRoundRectRgn" for rectangles with round corners, or "CombineRgn" to combine the results of other regions. "SetWindowRgn" defines the area in which a window is visible. It is interesting that under this concept the rectangular window still exists and we only defined something like a hole from where we can see it. A "Bug", a second example. ========================== My first attempt of a non-rectangular shape was a couple of years ago with Delphi 3. It was a mischief motivated in that I know people who terribly hate cockroaches (and here in the tropic there are spectacular ones). So I created a cockroach that wanders on the Windows desktop. Its form is elliptic and I fundamentally created some images for different angles (four: two verticals and two horizontals). The result is a bit rustic, but I enjoyed creating this "bug". I very well know there are better ways to do this, but it comes to the case because of the subject of this article. The next. ========= Well, this opens interesting possibilities of use (as I mentioned before). I think the most adequate seems to be the one of "Skins" like some applications. For reference you have "Winamp", "NeoPlanet", "Windows Media Player" (new version). The technique that allows non- rectangular shapes is applicable to buttons and other controls. Bibliography: * Delphi Developer's Handbook, Marco Cantù, Tim Gooch, John F. Lam SYBEX ISBN: 0-7821-1987-5 1.998 * La Biblia de Delphi 5 Marco Cantù ANAYA ISBN: 84-415-0994-8 2.000 -------------------------- The source code that accompanies this article can be downloaded from: http://www.latiumsoftware.com/download/p0013.zip ________________________________________________________________________ 3. OPENGL APPLICATIONS WITH DELPHI 5.0 - FIRST STEPS Copyright (c) 2000 Leopold Minikus <info@minais.at> When you use MNOgl component collection from minais you have two different ways to build such applications. First I want to describe the easy way: First of all be sure to install the MNOgl package file mnogl.bpl under Delphi (Component menu - Install packages - Add button - search for MNOgl.bpl and say Open). The result is you have a new component folder called MNOgl within which you will find a lot of handy components to design an OpenGL application. Let us start with a new project. Select a TMNOglControl component and drop it onto the form. Resize the control as you want it or let it align. Then select a TMNOglCanvas component and drop it on the form. Assign the MNOglControl1 to the property named WinControl. Now an OpenGL rendering context will be generated (the MNOglControl changes to black backgroundcolor). Let us now look how we can draw a box in this canvas. Pick a TMNOglScene component from the MNOgl folder and drop it on the form. Assign the MNOglCanvas1 to the property MNOglCanvas. Now let us select a TMNOglBox component and drop it on the form. Assign MNOglScene1 to the property Scene. Now you see the shape already in design mode. Try to change the size of the box by changing the properties Length, Width and Height. If you want to have your shape centered then set the TransformBy property to (-Length/2, -Width/2, -Height/2). Second I want to describe the way when you do not want to install the MNOgl package: Let us start with a new project. Change the uses list and add the units _mnoglcanvas, _mnogltools to your list. e.g. uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, _mnoglcanvas, _mnogltools; Add the following private variables to your form: TForm1 = class(TForm) ... private { Private declarations } MNOglControl1: TMNOglControl; MNOglCanvas1: TMNOglCanvas; MNOglScene1: TMNOglScene; MNOglBox1: TMNOglBox; public { Public declarations } end; Then enter the FormShow method and we will create the components we will need: procedure TForm1.FormShow(Sender: TObject); begin // create the WinControl for the OpenGL render context // herein your shapes will be played MNOglControl1 := TMNOglControl.Create(Self); MNOglControl1.Align := alClient; MNOglControl1.Parent := self; // create the MNOglCanvas MNOglCanvas1 := TMNOglCanvas.Create(Self); // assign the WinControl --> and the render // context will be created MNOglCanvas1.WinControl := MNOglControl1; // create the scene (OpenGL calls it DisplayList) MNOglScene1 := TMNOglScene.Create(Self); // and tell the scene in which Canvas it will be played MNOglScene1.MnOglCanvas := MNOglCanvas1; // create the box MNOglBox1 := TMNOglBox.Create(Self); // ant tell the box to which scene it will belong MNOglBox1.Scene := MNOglScene1; // change properties of the box with MNOglBox1 do begin Length := 4; Width := 3; Height := 2; end; end; If you want the scene to rotate then just add a TMNOglNav (a navigator) to your form and set the property MNOglCanvas to MNOglCanvas1. When you start the program you can then press the left mouse button on the MNOglNav component and move the mouse. With double-click the view will be reseted. ________________________________________________________________________ 4. OPENING MICROSOFT ACCESS .MDB DATABASES WITH DELPHI ADO === If you have Delphi 5 Enterprise or Delphi 5 Professional with ADO Express, then you can use an ADOTable and in the ConnectionString property of the associated ADOConnection you can use the property editor to build the right connection string. For example: Provider=Microsoft.Jet.OLEDB.4.0; User ID=Admin; Data Source=D:\Path\dbname.mdb; Mode=ReadWrite; Extended Properties=""; Persist Security Info=False; Jet OLEDB:System database=""; Jet OLEDB:Registry Path=""; Jet OLEDB:Database Password=""; Jet OLEDB:Engine Type=5; Jet OLEDB:Database Locking Mode=1; Jet OLEDB:Global Partial Bulk Ops=2; Jet OLEDB:Global Bulk Transactions=1; Jet OLEDB:New Database Password=""; Jet OLEDB:Create System Database=False; Jet OLEDB:Encrypt Database=False; Jet OLEDB:Don't Copy Locale on Compact=False; Jet OLEDB:Compact Without Replica Repair=True; Jet OLEDB:SFP=False NOTE: It all goes in the same line. This would open the database D:\Path\dbname.mdb using the ADO driver for Access databases (Microsoft.Jet.OLEDB.4.0). The username would be Admin without password (the default when you create an Access database). If you have set a password for the database, you should provide it in the "Jet OLEDB:Database Password" property. If you have set up security, then you should indicate your workgroups .MDW or .MDA file in the "Jet OLEDB:System database" property. BDE === If like most of us you don't have ADO, you can use the BDE which provides a native driver (MSACCESS). In a Database component, set the following properties: DatabaseName = any_name (or alias_name) DriverName = MSACCESS LoginPrompt = False Params = PATH=d:\path DATABASE NAME=d:\path\filename.mdb TRACE MODE=0 LANGDRIVER=Access General USER NAME=Admin PASSWORD=your_password OPEN/MODE=READ/WRITE SQLPASSTHRU MODE=NOT SHARED Value of the DatabaseName property of a Database object is the one you should use in the DatabaseName property of Table and Query components that represent tables and queries on this database (this is the way to "link" them to the Database object). BDE + ODBC ========== In the case of Access databases, the BDE provides a native driver, but there are many database formats for which there insn't a BDE driver, although maybe you can find an ODBC driver. ODBC offers what I would call "compatibility access" (for applications with bare minimum database requirements, or applications that only need to perform import/export operations), but sometimes it's all we have... Here is an example of how to use an ODBC driver with the BDE to open an Access database: * Create a DSN for your database (using the ODBC Data Sources applet in Windows's Control Panel). 1) Click the "System DSN" or "User DSN" tabs 2) Click "Add..." button 3) Select the "Microsoft Access Driver (*.mdb)" and press ENTER. The "ODBC Microsoft Access Setup" dialog will appear. 4) Provide a name in the Data Source Name textbox (no spaces and no special characters). 5) Click the "Select..." to specify your .MDB database. 6) If you have set up a security scheme you have to select the "Database" radio button in the "System Database" frame and then click the "System database..." button to specify your .MDW or .MDA workgroups file. 7) Click the "Advanced..." button if you want to set a default user name and password. This is for low-security access because anybody with access to your machine can see the DSN properties. If you need higher security, you should provide and username and password when you open the database (see below). 8) Finally click the "OK" button to save your DSN. * In Delphi set the properties of the TDatabase component: 1) Set DatabaseName to the name you gave to the DSN. 2) If you want the user to supply a login name and password, then leave LoginPrompt in True. 3) If you don't like the standard login dialog (or if you want to provide the user name and password by code) you can set LoginPrompt to False and use you own dialog box (or have the user name and password hard-coded in your application) and set the Params property with the login data: USER NAME=your_user_name PASSWORD=your_password * Associate your TTable or TQuery components to the TDatabase component mentioned above by simply providing the same DSN name in their corresponding DatabaseName property. ________________________________________________________________________ 5. LISTING THE TABLES AND QUERIES IN A DATABASE If you need to know the names of all tables and/or queries (views) in a database opened with the BDE, you can use DbiOpenTableList to create a cursor* with the table and query names, and then you can read it calling DbiGetNextRecord as shown in the example below that stores the names in a ListBox, indicating whether they correspond to a table or query. (*) A cursor is a "logical table". For example when we open a table or query, what we get is a cursor, that is, a set of data organized in rows and columns, independently of whether this data comes from a physical table, part of table, many tables or any other data source. To try the example, simply place a ListBox and a button on a form, and generate the button's OnClick event handler: uses db, dbtables, bde; procedure TForm1.Button1Click(Sender: TObject); var db1: TDatabase; hCursor: hDBICur; // Cursor for table and query names ListDesc: TBLBaseDesc; // Record of the cursor begin ListBox1.Clear; db1 := nil; try db1 := TDatabase.Create(nil); // Set the neccessary properties to open your database db1.DatabaseName := 'Access_ODBC_Test'; db1.LoginPrompt := False; db1.Connected := True; // Generates a cursor with all table and query names Check(DbiOpenTableList(db1.Handle, False, False, '*', hCursor)); // Move thru the records of the cursor to get the names while (DbiGetNextRecord(hCursor, dbiNOLOCK, @ListDesc, nil) = dbiErr_None) do if ListDesc.bView then // Is it a query? ListBox1.Items.Add(ListDesc.szName + ' (Query)') else ListBox1.Items.Add(ListDesc.szName + ' (Table)'); // Close the cursor dbiCloseCursor(hCursor); db1.Connected := False; except db1.Free; raise; end; db1.Free; end; Instead of a variable of type TDatabase created for the purpose, you can use a TDatabase control placed on a form, or the Database property of a TTable or TQuery control. ________________________________________________________________________ 6. LINKS * Top 100 Borland - Resources for Borland Developers http://www.top100borland.com ________________________________________________________________________ YOU CAN HELP US We need your help to keep this newsletter going and growing. You can help by referring the newsletter to your colleagues: http://www.latiumsoftware.com/en/pascal/delphi-newsletter.php Or you can help by voting for us in some or all of these rankings to give more visibility to our web site and thus increase the number of subscriptions to this newsletter: http://www.sandbrooksoftware.com/cgi-bin/TopSite2/rankem.cgi?id=latium http://news.optimax.com/delphi/links/links.exe/click?id=70C517ECAE6E http://www.programmingpages.com/?r=latiumsoftwarecomenpascal http://www.top219.org/cgi-bin/vote.cgi?delphi&83 http://top100borland.com/in.php?who=20 http://top200.jazarsoft.com/delphi/rank.php3?id=latium http://213.65.224.200/cgi-bin/toplist.cgi/hits?Id=80 It's just a few seconds for you that REALLY mean a lot to us. ________________________________________________________________________ If you haven't received the full source code examples for this issue, you can get them from http://www.latiumsoftware.com/download/p0013.zip ________________________________________________________________________ This newsletter is provided "AS IS" without warranty of any kind. Its use implies the acceptance of our licensing terms and disclaimer of warranty you can read at http://www.latiumsoftware.com/en/legal.php where you will also find a note about legal trademarks. Articles are copyright of their respective authors and they are reproduced here with their permission. You can redistribute this newsletter as long as you do it in full (including copyright notices), without changes, and gratis. ________________________________________________________________________ Main page: http://www.latiumsoftware.com/en/pascal/delphi-newsletter.php Group home page: http://groups.yahoo.com/group/pascal-newsletter/ Subscribe/join: pascal-newsletter-subscribe@yahoogroups.com Unsubscribe/leave: pascal-newsletter-unsubscribe@yahoogroups.com Problems with your subscription? eds2004 @ latiumsoftware.com ________________________________________________________________________ Latium Software http://www.latiumsoftware.com/en/index.php Copyright (c) 2000 by Ernesto De Spirito. All rights reserved. ________________________________________________________________________ |
The full source code examples of this issue are available for download.
![]() |
Errors? Omissions? Comments? Please contact us!






