Sunday, May 13, 2012

Plan Ahead When It Comes To FireMonkey & iOS

I don't intend to move to XE2 or XE(next) anytime soon, I have my hands full just porting over my old applications from D5 to D2010. However, I would like to take advantage of FireMonkey and the iOS market when the time is right so I'm planning ahead and so can you.

I am currently working on adding Inifile support to my application to keep track of window sizes and position. I asked on StackOverflow if FireMonkey has anything similar to GetSystemMetrics. Whiler posted a snice snippet of code that uses FX.Platform. (Merci Beaucoup Whiler)

My first thought was it's too bad I can't use this piece of code today. Then I had one of those aha moments. I thought to myself,
"Why not add this as a comment in your Delphi code."
So that's what I did.

Begin Code Snippet
{
----------------------------------------------------------------
FireMonkey Consideration:
----------------------------------------------------------------
Question asked on stackoverflow:
http://stackoverflow.com/questions/10564505
I'm rewriting an old application using Delphi 2010 and I'd like
to put placeholders in my code for when I port it over to XE2.
Just curious if FireMonkey has an equivilent to GetSystemMetrics.
I'm specifically interested in:

GetSystemMetrics(SM_CXSCREEN)
GetSystemMetrics(SM_CYSCREEN)
----------------------------------------------------------------
If you just need the main monitor size, and not the desktop size
(n monitors sum), you can use this:

uses ..., FMX.Platform;

var   p: TPointF;
begin
  p := Platform.GetScreenSize;
  ShowMessage(Format('X: %f' + LineFeed + 'Y: %f', [p.X, p.Y]));

From: Whiler
http://blogs.wittwer.fr/whiler/
----------------------------------------------------------------
}
unit IniFileStuff;

interface

uses
  Windows, SysUtils, Forms, IniFiles;

type
  TScreenType  = (MainScreen, PreviewScreen);

Procedure InitializeIniFile();
Procedure ResetScreenSection(ScreenType:TScreenType);
Function WindowStateToInt(WSType:TWindowState):integer;
Function IntToWindowState(WSInt:integer):TWindowState;
...
End Code Snippet

So, even though I'm not using FireMonkey today, I've documented my code so when I do go to use FireMonkey I'll have a decent head start.

Don't keep it - Pass it on.
Semper Fi - Gunny Mike

Wednesday, May 9, 2012

Keeping Screen Resolution in Mind

I'm redoing an old Delph 5 app that forced a screen resolution of 640 x 480 on the users. At the time this application was deveopled that screen resolution was acceptable but not anymore. Todays endless arrays of screen resolutions brings on new challenges. One of the things I plan on doing at application start is interrogate the current screen resolution and set my application screen size to a ratio of 80%.

I'm amazed at how much information is available. Here is a nice graph that shows the top 10 screen resolutions in use from 2008 through 2012.





Source: http://gs.statcounter.com/#resolution-ww-monthly-201201-201301-bar


Add MultiMon to the uses clause The button click event lets you move the program between two monitors to get the screen resolution.
procedure TScreenResolution.Button1Click(Sender: TObject);
var
  MonInfo: TMonitorInfo;
  ScreenW, ScreenH : integer;
begin
  MonInfo.cbSize := SizeOf(MonInfo);
  GetMonitorInfo(MonitorFromWindow(Handle, MONITOR_DEFAULTTONEAREST), @MonInfo);
  ScreenW :=  MonInfo.rcMonitor.Right  - MonInfo.rcMonitor.Left;
  ScreenH :=  MonInfo.rcMonitor.Bottom - MonInfo.rcMonitor.Top;
  Label2.Caption := IntToStr(ScreenW);
  Label4.Caption := IntToStr(ScreenH);
end;
Semper Fi - Gunny Mike

FireMonkey Update - 05/13/2012:

I'd like to thank Whiler from StackOverflow for a FireMonkey example using FX.Platform:



Sunday, May 6, 2012

Print to File Options Supported by ReportBuilder

Wow, I'm really impressed with the out of the box, Print to File options that come with ReportBuilder. All you do is set the AllowPrintToFile to True and you are done!

The default Print to File option is PDF. But there are several others. The image formats create one image per page. The HTML option creates an *_htm_images folder for any images that might be on the report.


Image modifed to show all Type options

Print to File accepts the Page Range options as well. I even tried breaking it by printing page 3 of a 2 page report. No errors popped up and no output file was created.

I am extremely pleased with my purchase. ReportBuilder has proven to be everything I expected it to be and more.

Semper Fi - Gunny Mike



A Simple Way to Learn About Methods and Properties

I've decided this time around with Delphi, I'm going to do things as best as I possibly can. A long time ago I met Jeff Duntemann (here's his blog). If you know Jeff, you know he has an astounding vocabulary. I asked him about that once and he responded:
"Michael, the reason for my vocabulary is simple, my parents. When I asked for the definition of a particular word they told me to look it up in the dictionary. And while you are reading about that word, read about every word on both facing pages."
Jeff developed this habit when he was young and he still carrys it with him today. What a simple concept. I have decided to use this idea when I go looking up a the reference to a property or method of a Delph object. Not only am I going to read about the property I was intially interested in, I will read about all the other properties and methods.

Thank you Jeff, I finally figured out how to use your dictionary lookup idea!

Semper Fi - Gunny Mike

How to get the DBDemos Database into ElevatdDB

There are several Delphi tutorials out there that use the DBDemos database that ships with Delphi. I tend to learn much better if I actually perform the tasks outlined in these tutorials rather than just reading or viewing them. However, I'd much rather perform these tasks using ElevateDB, since this is the database I have chosen for all my new applications.

I started looking around to see if someone has done this already. I was looking for a .zip file out there in internet land. I posted to the ElevateDB support group hoping someone had a .zip file I could get my hands on. What I found was much more valuable.

One of the regulars, Roy, said why don't you just use the "built-in BDE migrator" that comes with ElevateDB.
This is one of the coolest things I have done with ElevateDB. I learned so much more going through this process then I would have if I simply downloaded some .zip off the internet.This whole process takes less than 5 minutes from start to finish. It looks very complicated but believe me it's not.

Step 1 - Create a Session Called DBDemos

Make sure you have the ElevateDB Manager up and running. Right-Click on ElevateDB Manager and then choose Create New Session

General Tab

There are two things that need to be done inside the General tab.
  1. Name:  DBDemos
  2. Description:  DBDemos database that ships with Delphi
DO NOT CLICK OK . . Switch to the Local tab

Local Tab

There are two things that need to be done inside the Local tab.
  1. File Folder:  Enter the location for configuration file for this session. Don't worry if this folder doesn't exist, it will get created for you later on.
  2. Large File Support:  Make sure this box is checked.
DO NOT CLICK OK . . Switch to the Login tab



Login Tab


There are three things that need to be done inside the Login tab.
  1. User Name: Administrator
  2. Password: Enter:  EDBDefault

  3. Confirm Password:  EDBDefault
NOW CLICK OK


Click Yes if prompted to create folder.

Step 2 - Create Database Migrators

Now we need to add the database Migrators that come with ElevateDB to the DBMemos session.

  • Expand the ElevateDB Manager by clicking on the + (Plus)
  • You will see the DBDemos session we just created
  • Expand the DBDemos session by clicking on the + (Plus)
  • Right-Click on DBDemos
  • Choose Create Database Migrators


Step 3 - Create an Empty DBDemos database

Now we need to add the database Migrators that come with ElevateDB to the DBMemos session.


  • Expand the ElevateDB Manager by clicking on the + (Plus)
  • Expand the DBDemos session by clicking on the + (Plus)
  • Right-Click on Databases
  • Choose Create New Database...


There are three things that need to be done on the General tab
  1. Name:DBDemos
  2. Description: DBDemos Database that ships with Delphi

  3. Folder: Enter the location where you want the database files to reside. In my example I simply use a DB folder in the same location as the session folder.
CLICK OK WHEN DONE

Click OK when Done

Step 4 - Migrate the DBDemos Database and Into ElevateDB

 We are almost done, this is the final step.

  • Expand ElevateDB Manager by clicking on the + (Plus)
  • Expand DBDemos session by clicking on the + (Plus)
  • Expand Databases by clicking on the + (Plus)
  • Right-Click on DBDemos database
  • Choose Migrate Database...


There are seven things that need to be done on the Migrate Database Source tab.
  1. Migrator: Choose BDE
  2. Ckeckbox: Make sure Include Table Data is checked
  3. Parameters Grid: Click DatabaseName to highlight the grid row
  4. Value: Enter DBDemos
  5. Click Set Paramter Value button
  6. Veify the Parameter Grid shows DBDemos for the DatabaseName
  7.  Click OK
 

Congratulations. You now have an ElevatdDB version of the DBDemos database you can use to follow along with all the Delphi tutorials out there.

Enjoy!

Semper Fi - Gunny Mike

Thursday, May 3, 2012

Rethinking the Use of Stored Procedures

As I mentioned in a previous post, I was absent from Delphi programming for about 7 years. During that time I worked 50-60 hours a week on custom database driven websites using ASP and Microsoft SQL Server. I estimate that this resulted in 200 (plus/minus) websites.

Programming for the web taught me about statelessness, bandwith conservation, and the biggie, SQL Injection. Being the lead programmer I developed standards for the use of stored procedures in everything we did. I learned a lot, made my fair share of mistakes, and developed a deep admiration for stored procedures.

The focus became take a request from a webpage, go to the server, do as much on the server as possible while you are there, and return the results to the webpage. Works great.

So, now I'm back into Delphi and rewriting a desktop application that hasn't been updated since 2004. The jump from D5E to D2010 in itself, has been a challenge. I'm also going from a non-database application to a databse application. The database I have chosen to use is ElevateDB.

One of the reasons I chose ElevateDB was it offers stored procedures. I love stored procedures, they are like black boxes. As long as the interface doesn't change they are good-to-go and offer awesome power.

So, I'm taking all this thinking I developed throughout those web years and applying it straight to Delphi and the application rewrite I'm doing. I know that a stand alone desktop application doesn't have to worry about statelessness, or bandwith conservation, and for the most part SQL injection. But it's hard to re-learn to think... until the rubber meets the road.

The rubber met the road when I decided to build my first report using ReportBuilder. I've never truely had a reporting tool before... even in my web days I built everything from scratch. So, I took the amortization schedule I built as an ElevateDB stored procedure and made that my first report. Everything is going well, the report looks professional, I'm having fun.

Then I start thinking... wow it wouldn't be nice to add a a percentage of payment next to the principal column. Wouldn't it be nice to show the percentage of interest also. And it would be totally awesome to bunch them by the year the payment is due. So, I decide to add two calculated fields to my report, no big deal. PrinPct is simply Payment divided by Principal.

Then I realized...
  • You can't add a calculated value from a stored procedure column
  • You can't do a group by based on the the year of the payment
  • Wow, building a report based on the result set of a stored procedure is not the best approach
"My first thought was, great ReportBuilder doesn't let me do what I want to do. This sucks."
Then I realized...
"It's not ReportBuilder, it's me. My thinking is wrong. Stored procedures are not meant to be reported on... they are meant to do the heavy lifting that makes the data easy to report against"
I'm glad that this happened to me early on in the process. I would have been quite upset had I created a total database with 30-40 stored procedures all built on the assumption that they could be used as datasets for reporting.

Back to the drawing board... another lesson learned.

Semper Fi, Gunny Mike

Wednesday, May 2, 2012

Reporting Tool Survey

Here is an unsophisticated poll to see which Delphi reporting toll is used. Please only vote once.

(Participation in this poll requires a Linkedin account)



Results: Poll closed on May 28, 2012