Quantcast
Channel: Planet Object Pascal
Viewing all 1725 articles
Browse latest View live

twm’s blog: Delphi7Help4Bds

$
0
0

Back when Delphi 2005 was released everybody and his brother complained about the new help system. While up to Delphi 7 it used WinHelp the new version used the Microsoft Document Explorer. The new system was not only slow and buggy, the content also wasn’t up to par with that from Delphi 7. The content issue has been resolved in recent versions, but it is still very slow and at least in some of the Delphi versions the DExplorer task tends to hang after the window is closed preventing Windows from shutting down.

But I digress… I got so annoyed by the new help system, that I wrote an expert for the IDE that opened the old Delphi 7 help when pressing Shift+F1. Later on, I added more options like opening any WinHelp or HtmlHelp file and also open a web browser with the results of various search engines. I also made experts for all Delphi versions from Delphi 2005 to XE3. The latest addition was inspired by the superb Delphi Praxis Help Booster: The expert no longer opens a browser window in a separate task but uses the Delphi welcome page instead.

The project is now on SourceForge. To compile your own expert, use (Tortoise)Svn to download the sources, open the package for your Delphi version and just hit compile and install. A new entry in the Help menu will let you configure what to do on Shift+F1, Ctrl+F1, Alt+F1 and Ctrl+Alt+F1.


Leonardo's blog: FreeBsd resize VirtualBox disk

$
0
0
I have a FreeBsd 9.1 VirtualBox guest machine I've created with a 10G disk. After installing my usual programs, I've got the not-so-friendly "disk full" message.

What to do:

Resize the virtual disk:

VBoxManage \
modifyhd "FULL_PATH_TO_VDI" \
--resize SIZE_IN_MBS
For example:
VBoxManage modifyhd "/home/leonardo/VMS/FreeBsd91/disk.vdi" --resize 20480
This will resize the disk up to 20Gb

Let the system know you have resized the disk:


Boot in single user mode and follow these steps:
# gpart show
=> 34 21942973 md0 GPT (CORRUPTED)
34 256 1 freebsd-boot (64k)
290 21943129 2 freebsd-ufs (10G)
The first thing to note is the "CORRUPTED" label. To fix it just do:
# gpart recover ada0
Now, it's time to grow the 10G partition to fill the whole 20G disk:
# gpart resize -i 2 ada0
gpart: Device busy
If you get the "Device busy" message:
# sysctl kern.geom.debugflags=16
kern.geom.debugflags: 0 -> 16
# gpart resize -i 2 ada0
gpart resized
Ok, now the partition was resized. The last step is to resize de filesystem on it:
# growfs /dev/ada0p2
Done!, now reboot and enjoy your big disk!.

EDIT: Today I've received a comment on Google Plus by Edward Tomasz Napierała about improvements on FreeBsd 10. Here's the comment:
Note that in 10-CURRENT it's possible to do all this without going single-user.
The 'debugflags' step is also not required.
In 9-STABLE it's possible to resize the filesystem mounted read-write,
but it's not possible to resize the partition.

Lazarus Team Anouncements: Lazarus 1.0.6 release available for download

Dr.Bob's Delphi Notes: XE3 Update #2 - Help Update 3 (or 2)...

$
0
0
A few days ago, Update #2 for Delphi and C++Builder XE3 was released, which will also update your Help to Update 2 (or 3, if you update now).

Tim Anderson's ITWriting: Embarcadero acquires AnyDAC data access libraries for Delphi, C++ Builder

$
0
0

Embarcadero has acquired the AnyDAC data access libraries from DA-SOFT, including its main author Dmitry Arefiev. These libraries support Delphi and C++ Builder and support connections to a wide range of database servers, including SQL Server, DB2, Oracle, PostgreSQL, SQLite, Interbase, Firebird, Microsoft Access, and any ODBC connection.

AnyDAC is well liked by Delphi devlopers

...continue readingEmbarcadero acquires AnyDAC data access libraries for Delphi, C++ Builder

The Wiert Corner - irregular stream of stuff: jpluimers

$
0
0

One of the really nice contributions on StackOverflow by Allen Bauer is almost 3 years ago.

It is about these three Delphi VCL methods introduced by TWinControl to make control development easier:

The really cool thing is that this API has been stable since 1995, and still allows you to subclass windows controls or create your own controls in a very simple way.

Note that Allen does not cover DestroyWnd or DestroyWindowHandle, but those are just counterparts of CreateWnd and CreateWindowHandle.

In normal Delphi application code, you have less Destroy overrides than Create overrides, and the same holds for control development.

–jeroen

via: delphi – What’s the difference between CreateWnd and CreateWindowHandle? – Stack Overflow.


Filed under: Delphi, Delphi 1, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 3, Delphi 4, Delphi 5, Delphi 6, Delphi 7, Delphi 8, Delphi x64, Delphi XE, Delphi XE2, Delphi XE3, Software Development

Firebird News: My First Firebird and Python application

$
0
0
Ido Kanner (ik_5) wrote on his blog about his First Firebird and Python application : It’s that time of the year again – I’m required to learn new technology due to a project requirement. The requirement is to write something using django, but I do not know django or Python. So I’ve started my first [...]

Žarko Gajić: TProgressBar Not Updating Fast Enough?

$
0
0

progressbar-slow-update
Do users of your Delphi application actually see the progress bar moving?

The TProgressBar control provides visual feedback about the progress of some actions within your application. The Position, Max and Min properties determine the current position of the progress bar within its minimum and maximum values.

In most processing situations of some kind, where the progress bar is used, I have code that looks like:

ProgressBar1.Max := NUMBER_OF_ELEMENTS;
try
  for i  := 1 to NUMBER_OF_ELEMENTS do
  begin
    begin
     // do some operation
    end;

    //update progress bar
    ProgressBar1.StepIt; //if Step = 1
    //OR
    ProgressBar1.Position := i;
  end;
finally
  ProgressBar1.Position := 0;
end;

I guess the above way of using a progress bar is also what you have in your application. Set the Max value, run some loop, update the progress bar position to notify the user of the progress of the loop.

Note that after the operation is finished the progress bar position is set to zero, to make it ready for the next operation requiring visual feedback where the same progress bar control is used. In fact, I have a single progress bar positioned in the status bar of the main form of my application – this single progress bar is used for all progress-type actions.

Now, would you expect, using the above code, to actually see the progress bar progressing?

The answer to that questions depends on two other questions: how fast will the loop finish and on what version of Windows (themed or not) the application is being run!

The TProgressBar as implemented in Delphi (as the case is with most other controls) is a direct implementation of the Windows common control – and therefore Windows (the operating system) is responsible for painting it.

Progress Animation on Vista, Windows 7, 8 ….

If your application is run under Windows Vista or Windows 7 (and later) with Aero enabled, the operating system draws the progress bar in a way that it smoothly scrolls from the previous position to the new position. Since this painting takes time, it can take more time then needed in your code to step to the next position.

As a result, and depending on the time needed to process your loop, you might notice that the progress bar is sometimes not painted at all, sometimes it will go to 30%, sometimes to 80% (whatever number or position).

Here’s a real code example you can use to see this (should be running on Windows 7, 8 or Vista with Aero):

procedure TProgressForm.Button1Click(Sender: TObject);
var
  dirFiles : TStringDynArray;
  aFile : string;
begin
  dirFiles := TDirectory.GetFiles('c:\SomeFolderWithPasFiles');

  ProgressBar1.Max := Length(dirFiles);
  ProgressBar1.Position := 0;

  for aFile in dirFiles do
  begin
    if TPath.MatchesPattern(ExtractFileName(aFile),'*.pas',false) then
    begin
      //do something with .PAS files that could take time
    end;

    ListBox1.Items.Add(aFile);

    ProgressBar1.Position := 1 + ProgressBar1.Position;
  end;

  ProgressBar1.Position := 0;
end;

The code loops through all the files in a specified folder and places their names in a list box, a progress bar is used for the visual feedback. If a file is a .PAS file some additional action will be done (whatever). Depending on the number of files and the number of .PAS files (and what you would do to them) it might appear that the progress bar is not being painted at all or it will reach some random position before being reset to position zero (initial position).

Similarly, if the progress bar is at 0% and you set it to 75% then 100% (very fast) – the progress bar does not “jump” to that position – it “slowly” and smoothly fills in its area – possibly too slow for the purpose!.

ProgressBar.ProperlyPaint!

Now, enough with the intro to the problem. The thing is that the way to solve the painting problem is rather simple and involves a trick.

When you set the progress position backwards the (slow) animation does not take place, rather the progress bar jumps quickly to that position.

Having this in mind, I have a simple procedure “ProgressBarStepItOne” implemented as:

procedure TProgressForm.ProgressBarStepItOne;
begin
  ProgressBar1.StepBy(1);
  ProgressBar1.StepBy(-1);
  ProgressBar1.StepBy(1);

  //same as
  (*
    ProgressBar1.Position := 1 + ProgressBar1.Position;
    ProgressBar1.Position := -1 + ProgressBar1.Position;
    ProgressBar1.Position := 1 + ProgressBar1.Position;
  *)
end;

And my code looking as below, ensures the visibility of the progress bar actually moving even when the time to process something is less than it would be needed for Windows to paint (animate) the progress bar moving from 0 to 100!

procedure TProgressForm.Button1Click(Sender: TObject);
var
  dirFiles : TStringDynArray;
  aFile : string;
begin
  dirFiles := TDirectory.GetFiles('C:\SomeFolderWithPasFiles');

  ProgressBar1.Max := Length(dirFiles);
  ProgressBar1.Position := 0;

  for aFile in dirFiles do
  begin
    if TPath.MatchesPattern(ExtractFileName(aFile),'*.pas',false) then
    begin
      //do something with .PAS files that could take time
    end;

    ListBox1.Items.Add(aFile);

    ProgressBarStepItOne;
  end;

  ProgressBar1.Position := 0;
end;

If you use the TProgressBar’s StepIt procedure to advance the Position property with the current value of M by some value > 1, let’s say N , make sure you then set it to M+N-1 and back to M+N.

Now, is that a trick you would never think of or?


Žarko Gajić: The (Open) Case Of Dangling Pointers (Invalid Object References) In Delphi

$
0
0

dangling-pointer-delphiI guess you might not know what the term “dangling pointer” means, but if you have ever done some more complex programming in Delphi (where you do not only put controls on a form and handle a few events – rather you create and use objects at run-time) you might have experienced weird Access Violations when you tried accessing properties of an object you though is “Assigned” (or not nil).

The term dangling pointer refers to a pointer that is not nil, but does not point to valid data (i.e. points to an invalid memory address).

Still confused? You’re not alone!

Take a look at the following piece of code:

TMyClass = class (TObject);
…
var
  mc_1 : TMyClass;
begin
  mc_1 := TMyClass.Create;
  mc_1.Free;
  // is Assigned(mc_1)  = TRUE?
end;

You might expect that Assigned(mc_1) would return false, but this is not the case.

When you create an instance of a class, an object, the memory required is allocated on the heap. Calling mc_1.Free will free the memory occupied for the object referenced by mc_1. The variable mc_1 is not cleared out, it is not nil (i.e. is still Assigned) but the memory it points to is no longer valid.

The Assigned function tests if the pointer to the memory (the variable reference) is nil. In case of variable references, Assigned(mc_1) is equal to “mc_1

nil”. mc_1 after the call to mc_1.Free is a dangling pointer.
Certainly, since the above is “your” code, you know you can no longer operate on mc_1 after you called Free on it. In case you want to be sure Assigned(mc_1) would return false, you would also need to do mc_1 := nil, or call FreeAndNil(mc_1). Case closed.

How about the next example:

var
  mc_1, mc_2 : TMyClass;
….
begin
  mc_1 := TMyClass.Create;
  mc_2 := mc_1;
  mc_1.Free;
  mc_1 := nil;
  //mc_2  usable ?
end;

Now, what is the state (i.e. can you use it) of the variable mc_2 after we have freed mc_1?

What if at some stage in the life of your application you need to do something with mc_2? Would you expect that Assigned(mc_2) would return false? Should mc_2 = nil be true?

The truth is that a call to “Assigned(mc_2)” as well as “mc_2

nil” will return true. :(

The problem here is that freeing mc_1 marks the memory block used by mc_1 as available – but all the mc_1 data is still there. Since mc_2 points to the same memory location where mc_1 used to be, the data is still there, Assigned(mc_2) returns true.

Therefore, mc_2 is a dangling pointer. But this one is a more complex one to handle! There is no way for you to check if mc_2 is usable!

The way how Delphi memory manager works, after freeing an object, is to mark the memory space occupied by the object as available – not clear it out in any way.

As you create new instances of your objects (various types), memory manager will reuse blocks of memory from the heap. Your dangling pointer points to the same address but this time, quite possibly, to a different object (different class instantiated at the same memory block).

What’s worst, if the new object is of the same type you could end up with this dangling pointer working perfectly! Consider where a newly instantiated mc_3 gets the memory space where mc_1 used to be. Using mc_2 you are not aware that mc_1 is dead, mc_2 works normally but operates on the mc_3 instance. Catastrophe.

Of course, it is more likely that some other object (of some other type) will reuse the memory space of mc_1 and you could start experiencing weird Access Violations when using mc_2. And still, Assigned(mc_2) returns true.

While there’s a lot discussion on this problem on the Internet, and while there are some posted solutions to check if a pointer points to a valid object instance, I am strong in my belief that there’s no way to check this with 100% certainty (am not considering third-party memory managers).

Is there a solution? No :( Or, yes: be careful when you have such code constructs.

Rewrite the usage of mc_2 in a way that you somehow signal to mc_2 when mc_1 is freed (no longer really available).

In one of my programs I have the next setup (I guess common): an object has a property that is a list of objects of the same type. Something like:

//PSEUDO CODE:
TMyClass = class
public
  property Relatives : TObjectList<TMyClass>;
end;

Now consider the following:

procedure TDanglingPointersForm.FormCreate(Sender: TObject);
var
  mc : TMyClass;
begin
  mc1 := TMyClass.Create;
  mc2 := TMyClass.Create;
  mc3 := TMyClass.Create;

  mc1.Relatives.Add(mc2);
  mc1.Relatives.Add(mc3);

  for mc in mc1.Relatives do
  begin
    //there are 2 that are ok (mc2 and mc3)
  end;

  FreeAndNil(mc2);

  for mc in mc1.Relatives do
  begin
    //mc that is mc2 will not be usable here !!
    //how to remove it from mc1.Relatives when mc2.Free ?
  end;
end;

Of course, in a real world application all the code is not contained in one procedure!

My solution was to signal (using events) to the list when an object is freed – so that the list can remove it from itself.

Here’s the full source:

TMyClass = class;

TMyClassList = class(TObjectList<TMyClass>)
  procedure Destroyed(sender : TObject);
  function Add(myObject : TMyClass): Integer;
end;

TMyClass = class
private
  fRelatives : TMyClassList;
  fOnDestroyed: TNotifyEvent;
  function GetRelatives: TMyClassList;
public
  destructor Destroy; override;

  property OnDestroyed : TNotifyEvent read fOnDestroyed write fOnDestroyed;

  property Relatives : TMyClassList read GetRelatives;
end;

The TMyClass has a lazy-instantiated property “Relatives” which is actually a list of (other) TMyClass instances. Relatives does not own the instances added, they will be freed by other means.

Here’s the implementation part:

{ TMyClass }

function TMyClass.GetRelatives: TMyClassList;
begin
  if fRelatives = nil then fRelatives := TMyClassList.Create(false);
  result:= fRelatives;
end;

destructor TMyClass.Destroy;
begin
  if Assigned(fOnDestroyed) then OnDestroyed(self);

  fRelatives.Free;

  inherited;
end;

{ TMyClassList }

function TMyClassList.Add(myObject: TMyClass): Integer;
begin
  myObject.OnDestroyed := Destroyed;
  result := inherited Add(myObject);
end;

procedure TMyClassList.Destroyed(sender: TObject);
begin
  if self.Contains(TMyClass(Sender)) then self.Remove(TMyClass(Sender));
end;

This time:

procedure TDanglingPointersForm.FormCreate(Sender: TObject);
var
  mc : TMyClass;
begin
  mc1 := TMyClass.Create;
  mc2 := TMyClass.Create;
  mc3 := TMyClass.Create;

  mc1.Relatives.Add(mc2);
  mc1.Relatives.Add(mc3);

  for mc in mc1.Relatives do
  begin
    //there are 2 that are ok (mc2 and mc3)
  end;

  FreeAndNil(mc2);

  for mc in mc1.Relatives do
  begin
    //only mc3 is here, as expected !
  end;
end;

Am eager to hear your ideas and solutions to this problem…

See Different: לזרוס, חדשות תקופתיות

$
0
0

הרבה זמן שלא היה לי זמן לכתוב את הפינה שלי של חדשות לזרוס, ובנתיים עברו להן מספר גרסאות חדשות (מאז גרסה 1.0).

הנה חלק קטן מהדברים אשר הוכרזו בשלושה חודשים האחרונים בנושא:

ביום שני האחרון (4/02/2013) שוחררהגרסה 1.0.6 של לזרוס אשר מכילה תיקוני באגים בלבד.

בינואר שוחרר הסברכיצד ניתן לפתח עבור Raspberry Pi באמצעות לזרוס.

שוחררו רכיביםעבור לזרוס לפיתוח טוב ואיכותי יותר עבור iOS. זה כולל הרבה סרטוניווידאו המסייעים להדריך כיצד לעשות זאת.

מנוע המשחק Castle שיחרר גרסה 4 שלו. המנוע מאפשר לספק API גבוהה לפיתוח משחקים, התחברות למודלים (כדוגמת אלו הנבנים עם blender), ועוד.

אנשים בקהילת הלזרוס של סין (תתפלאו אבל יש כזו קהילה), שיחררו את pascal4androidבסוף שנה שעברה.

מערכת בשם Formboxשהיא חצי קוד סגור המספקת מערכות לניהול ווירטואליזציה על בסיס SmartOSהשתמשה ב FPC לפתח את כל תשתית הניהול שלה בצד השרת. יש להם רצון לפתוח את המוצר גם כקוד פתוח בנוסף, והם מחפשים לגייס כסף בנושא להמשיך בפיתוח.

אחרון חביב לפוסט זה, הוא Community של FPC/Lazarusב Google+‎ שאתם מוזמנים גם להצטרף לשם כמובן.


Filed under: android, FPC, Lazarus, Object Pascal, חומרה, טכנולוגיה, פיתוח, קוד פתוח, תוכנה Tagged: lazarus

Žarko Gajić: Signing Back On. Hello World (Again)!

$
0
0

zarko-gajic_2012Well, a few weeks ago I decided (never mind the reasons) that “the time has come for me to move to new endeavors”. This comes from my last post as the “Delphi Programming Guide for About.com”.

As I’ve promised at the end of the “signing off”, I’m back!

I’ll simply repeat what I’ve said there: I am and will be using Delphi every day, there’s always something to be implemented, some problem to be solved, some new feature to be included – any why not share the knowledge gained with others.

That’s it, as simple as always in life it is.

Sign off there, sign on here and continue doing what’s your best.

procedure TMainForm.Create(Sender: TObject);
begin
  TZarkoGajic.OnDelphiProgramming.Go(infinite);
end;

Firebird News: IBX for Lazarus (Firebird Express) Release 1.0.3 is now available for Download with minor changes

$
0
0
Here is the IBX Change Log for version 1.0.3: 1. Conditional compilation used to limit registration of TIntegerField to Lazarus versions less than 1.1 2. When a database connection is created, character set is now by default set to UTF8 (Unix) or to the current Windows code page (Windows) if in the range 1250 to [...]

TPersistent: I Spy…

$
0
0

Whenever I take on a new maintenance project I find that sometimes form names do not adhere to a standard naming convention, or it takes a while to get accustomed to the one used.  For that reason, if you encounter a bug, or behaviour that is not desired when running an application outside of the IDE, it is often difficult to figure out what form is active when the error occurs.

An old school way to answer this question is to use Spy++ to get the window class name, which for Delphi forms is the Delphi class name.  Since Spy++ is a Microsoft VC++ application and tool, it doesn’t come with Delphi so I always have to get it from another source.  I recently found this location with multiple versions.  Guess I’m not the only one who still uses this tool!

TPersistent: AnyDAC Acquisition

$
0
0

While the information available regarding the AnyDAC acquisition is pretty sparse, I find it worrysome.  Perhaps I’m alone on this, but why does a company acquire a competing technology?  I can think of a couple of reasons: 1) the technology is better than what they currently have, or 2) the company that owns the technology is more progressive and so acquiring them early enough prevents having to compete with, and quite possibly lose to them later.  Otherwise, licensing it is a viable option depending on its intended usage.

Marco in his announcement stated that AnyDAC is “considered the best data access library for Delphi”, and “its [dbExpress] features set remained very stable since it was introduced, and the transition to dbExpress IV started in Delphi 2009, was never fully completed.”  I interpret this last statement as an indication that dbExpress has not continued to evolve, and was never completed in over 4 years.  That is a little disturbing since EMBT sells their additional drivers as part of the Enterprise SKU which commands a large price tag.  It’s also scarey in that Delphi’s popularity was largely due to it’s ability to produce first class client/server applications, and then later distributed database applications.  If EMBT fell behind in such core functionality, to the point where they had to buy a third party product to keep pace, what does that say about their direction?  It’s also concerning that the AnyDAC acquisition might very well mean a change to the EULA in the next release due to the additional cost, and the deprecation of DBX.  I’m sure other EMBT partners such as DevArt are thrilled!

Add to that, the acquiring company is apparently suffering financially, raising it’s prices in the new year, laying off staff, etc, and it really makes you wonder why in January they were negotiating a deal with DA-Soft to purchase DA-Soft’s primary product.  The last time this happened they acquired a flaming ape.

I suppose time will tell what this means to the Delphi community.  I personally don’t see it as a positive.  If I wanted to use AnyDAC, all I had to do was buy it.  Now I will very likely be paying for it (Kind of like the “free” HTML Builder 5 you get with Delphi), whether I want it or not, and there is no telling what the customer service, and development direction of Any DAC will be like in the future.  As part of EMBT, it will become EMBT’s.

DelphiTools.info: Graphics competition, two days left to register!

$
0
0

..and maybe win first prize, which is the tablet of your choice?

SmartContest 2013 Round #1

This is the first competition out of four this year. So this is your chance to win some exciting prices by showing off your Object Pascal skills!

The topic of this round is: graphics programming (eg. demo-scene, fractal art, visualizations etc).

Registration is before the 10th of February, follow the link above for more details!


Firebird News: New IBExpertBenchmark tool: Compare your db server performance on different hardware, OS’s and Firebird server version

$
0
0
Have you ever tried to compare the database speed of your Firebird server with new server hardware? Is a XEON Machine better than an Opteron? What improvements can you expect from fast SAS hard disks, RAID controllers or Enterprise SSDs? Is SuperClassic really better than Superserver? We’ve created a new tool which offers a reproducible [...]

Firebird News: ZeosLib 7.0.3 stable for Delphi/Lazarus is released

$
0
0
Stable version of zeoslib 7 is released. The most important improvement you’ll find in this version is support for the compilers Delphi2009 and newer, with their unicode strings. Other changes in this release are - Some new components for grouping connections (alpha status) - Postgres event alerter component comparable with the existing Interbase/Firebird event alerter [...]

jed-software.com: FireMonkey: Extending TFloatAnimation to support maximum loops

$
0
0

Background

In response to a QC report I wrote early last year I decided to implement a LoopCount property on the TFloatAnimation component.

Report No: 105140 Status: Open
Add a LoopCount property to the TAnimation class
http://qc.embarcadero.com/wc/qcmain.aspx?d=105140

Class Definition

  TJSCustomLoopCountFloatAnimation = class(TFloatAnimation)
  public
    type
      TAnimationLoopEvent = reference to procedure (Sender: TObject; const LoopNumber: Integer; var Cancel: Boolean);
  private
    FLoopCount: Integer;
    FCheckingLooping: Boolean;
    FOnLoop: TAnimationLoopEvent;
  protected
    FLoopsComplete: Integer;
    procedure FirstFrame; override;
    procedure DoLoop(var ACancel: Boolean); virtual;
    procedure ProcessAnimation; override;
  public
    constructor Create(AOwner: TComponent); override;
    property LoopCount: Integer read FLoopCount write FLoopCount default 3;
    property OnLoop: TAnimationLoopEvent read FOnLoop write FOnLoop;
  end;

Nothing that interesting in the new descendant. New property called LoopCount to control the number of loops and a new event that gets triggered each time a loop completes.

The published component publishes the new property and event but also changes the default values for two existing properties. It makes sense to set Loop to true when the new class is for enhancing the looping ability and if you’re looping, generally AutoReverse will be set to true.

  TJSLoopCountFloatAnimation = class(TJSCustomLoopCountFloatAnimation)
  published
    property AutoReverse default True;
    property Loop default True;
    property LoopCount;
    property OnLoop;
  end;

Implementation

I won’t post all of the code here because you can download from the link provided below, just a couple of snippets.

We need to override the FirstFrame method to initialise a couple of variables we use.

  • Checking to see if the LoopCount property is valid (raise an exception if it isn’t)
  • Initialise the variable to zero that counts the interactions
  • Make sure we are going to be checking the animation process for loops

Most of the work occurs in the overridden ProcessAnimation method.

procedure TJSCustomLoopCountFloatAnimation.ProcessAnimation;
var
  LCtx: TRttiContext;
  LType: TRttiType;
  LField: TRttiField;
  LCancel: Boolean;
begin
  inherited;
  if FCheckingLooping then
  begin
    LType := LCtx.GetType(Self.ClassInfo);
    if Assigned(LType) then
    begin
      LField := LType.GetField('FTime');
      if LField <> nil then
      begin
        if LField.GetValue(Self).AsExtended = 0 then
        begin
          Inc(FLoopsComplete);
          LCancel := False;
          if FLoopsComplete > 1 then
            DoLoop(LCancel);
          // The first time through, FTime is 0 so we need to offset this by
          // adding 1 when checking for completion
          if LCancel or (FLoopsComplete = LoopCount + 1) then
          begin
            LField := LType.GetField('FRunning');
            if LField <> nil then
              LField.SetValue(Self, False);
          end;
        end;
      end;
    end;
  end;
end;

Thanks to extended RTTI we can access a couple of private fields that we need to determine if a loop has been completed. This occurs when the FTime variable is zero. There is one issue with using this value and that is that the first “Loop” should be ignored since the first time ProcessAnimation is called FTime is zero so by the logic used, a loop has completed. This is why the DoLoop method is only called if the FLoopsComplete variable is greater than one.

Naturally it is possible to handle this one-off situation differently using a “First Time Through” variable but under the circumstances, I decided to go with the solution in place.

Once the LoopsComplete value is one greater than the LoopCount (refer to the above two paragraphs if you’ve already forgotten about why) the private field FRunning is set to False. Setting FRunning to false, stops the animation immediately.

Why not just call the public Stop method instead of going to the trouble of setting a private field? The answer to that is found in the ProcessTick method of the animation control (incidently, why isn’t this method virtual?).

  ...
  ProcessAnimation; // <==== We set FRunning to false here
  DoProcess;

  if not FRunning then
  begin
    if Assigned(AniThread) then
      TAniThread(AniThread).FAniList.Remove(Self);
    DoFinish;
  end;
  ...

By setting FRunning to false within our ProcessAnimation override, we are avoiding another frame being processed before the animation is stopped. This is because the Stop method calls ProcessAnimation and DoProcess as well.

Download

You can download the component and a cheesy demo application from the link provided. There is no package for the component to install it into your IDE, this is left as an exercise for the reader :-) .

Loop Animation Demo (short video – 39KB)

Download LoopCount Component and Demo

NOTE: Before downloading the source code you must agree to the license displayed below.

License Start




This space intentionally left blank…



License End

See Different: הדגמה מתקדמת לשימוש ב TFPSMap

$
0
0

בFPC 2.2.0 נוספה ספריה בשם fgl בייחד עם התוספת לשימוש ב Generics.

הספרייה מאפשרת לקבל שני מימושים של מחלקות, האחת עובדת בגישה הרגילה של שימוש במצביעים ו/או TObject לבצע פעולות, והשניה לעבוד עם generics.

לאחרונה ניסיתי לעשות שימוש במחלקה בשם TFPSMap כאשר אני מנסה להשתמש ב key ו value של מחלקות. אבל גיליתי בעיה – הוא מאבד את האיבר ולמעשה הצורה שהשתמשתי בה גרמה לדליפת זיכרון. מצד אחד הזיכרון נכנס לרשימה, אבל מצד שני מעולם לא הצלחתי לתפוס אותו חזרה.

דיווחתי על כך באג, אבל הסתבר שאני פשוט השתמשתי בספרייה לא נכון. הנההצורה הנכונה לשימוש בTFPSMap:

{$mode objfpc}
uses sysutils, fgl;

type
  TMyKey = class
  public
    Key : String;

    constructor Create;
  end;

  TMyValue = class
  public
    Value : String;

    constructor Create;
  end;

constructor TMyKey.Create;
begin
  Key := 'A Key';
end;

constructor TMyValue.Create;
begin
  Value := 'A Value';
end;

var
  Map    : TFPSMap;
  Key    : TMyKey;
  Value  : TMyValue;
  Value2 : TMyValue;

begin
  Map   := TFPSMap.create(SizeOf(key), SizeOf(Value));
  Key   := TMyKey.create;
  Value := TMyValue.create;

  Value.Value := 'here';
  Map.add(@Key, @Value);

  Value2 := TMyValue(Map.KeyData[@Key]^);
  writeln(format('%P, %P, %S, %S', [Pointer(Value), Pointer(Value2),
                                    Value.Value, Value2.value]));
  Key.free;
  Value.Free;
  Map.free;
end.

בחלקים הראשונים יצרתי סתם מחלקות בשביל ההדגמה, הן לא באמת חשובות להסבר.
בחלק ריצה הרגיל, כבר יש דברים אשר חשובים להסבר.

Map   := TFPSMap.create(SizeOf(key), SizeOf(Value));

דבר ראשון אני מכריח ביצירת המחלקה לקבוע את גודל הזיכרון של מחלקת key ומחלקת value.
מה שאומר שכל דבר בעל גודל זיכרון שונה מכך לא יוכל להיכנס לרשימה הזו !
חשוב לזכור כי פסקל אינה שפה דינאמית, אלא שפה סטטית, למרות שלפעמים קל לחשוב אחרת, וזו הסיבה.

 Map.add(@Key, @Value);

כאן נמצא הקסם בין המקום בו אני נפלתי לדרך שצריך לבצע.
אני הנחתי כי בגלל ש"מחלקה היא מצביע לאובייקט" (הגדרה של פסקל ל class), אז הוא יראה את כתובת הזיכרון של המחלקה.
אבל הוא לא. הוא ראה את התוכן של instance בפועל. כך שהתיקון הוא בעצם להכריח לראות את כתובת הזיכרון של הinstance עצמו ולא את התוכן שלו.
ולכן אני מציג לרשימה את כתובת הזיכרון של ה instance ולא כתובת התוכן שלו.

בשביל לחלץ את המידע, השתמשתי בקוד הבא:

 Value2 := TMyValue(Map.KeyData[@Key]^);

כאן אני מחזיר חזרה את הערך של ה instance מכתובת הזיכרון שלו אל תוך משתנה חדש.
ה casting מתבצע בגלל ה strong type. אני מכריח את הקומפיילר בעצם להבין כיצד להתנג נכון עם התוכן, אחרת הוא ידווח על שגיאה כי מה שסיפקתי ומה שהוא מצפה הם שני טיפוסים שונים.

ובשביל להיות בטוח אני מדפיס על המסך את המידע:

 writeln(format('%P, %P, %S, %S', [Pointer(Value), Pointer(Value2),
                                   Value.Value, Value2.value])); 

בהתחלה אני מדפיס את 2 כתובות הזיכרון של ה instance ומגלה שהן זהות.
אח"כ אני מדפיס גם את תוכן המחרוזת לוודא כי הן זהות.

וזה כל הסיפור


Filed under: FPC, Object Pascal, טכנולוגיה, פיתוח, קוד פתוח, תוכנה, תכנות Tagged: fgl, fpc, generics, key value

Firebird News: SplendidCRM on FirebirdSQL demo page and Database structure

$
0
0
SplendidCRM (version C# of SugarCRM) is ported from MSSQL over to FirebirdSQL 2.5.2 It is in a “testable” debug version on this url http://zeos.tetrasys.eu username : user password : user This changes from the usual will/will It is the “community” version and I would like to have your feedback on their added value in a CRM, [...]
Viewing all 1725 articles
Browse latest View live