Duoas 1,025 Postaholic Featured Poster

Look, I haven't meant to make you feel stupid.

1. Look at posts #4 and #10, where I gave you an event handler and which you correctly modified to use the TListView.
2. Now look at post #16 where I gave you a function that prints x lines from a TListView's item list.
3. Put them both in your code. Change the word "save250" from post #10 to "saveNLines".


I know you are new to programming. That is why I have asked you to read about procedures and about types. All your errors are due as a direct consequence of your failure to do that.

You are being defensive and angry. And you presume too much to say I am unwilling or that I misunderstand. I understand better than you think, and I have stated repeatedly I am willing to help, if you are willing to follow the advice given you. I have no interest in wasting my time to lead you in circles.

Please consider that I know what it is to learn how to program and how much information overload it is to find simple answers. The truth is that there are no simple answers when it comes to programming, and you are going to have to wrap your mind around a few things --none of which come easily-- to get it right. Until you do, even a gift horse looks like a mule.

Duoas 1,025 Postaholic Featured Poster

Perhaps you meant to post in the C forum? (This is C++.)

Think about what the program is supposed to do, and write down a sort of "how to" to get it done:

1. get an integer from the user
2. get another integer from the user
3. get yet another integer from the user
4. figure out which integer is the smallest and print it
5. figure out which is neither smallest nor largest and print it
6. figure out which is the largest and print it

Looking that over, you might want to add "ask the user for three integers" before step 1.

Once broken down into smaller steps like this, you can deal with one step at a time. Since you need to keep track of three integers, that suggests three variables: int a, b, c; Use scanf() to get input from the user: scanf( "%d", &a ); // get the first integer from user Refer to your class notes and textbook for more help.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

There's no need for the angry attitude or to get all defensive. I have far more experience than you and, whether you believe it or not, a greater understanding of your problem than you do.

At no point have I given you incorrect code --all the code I supplied works fine. The problem lies in your understanding.

May I ask how it is that you have written so much code that it would take an enormous amount of time to switch to a TListBox (which, you will note, I have not required you to do), without understanding the basic concepts central to programming? At no point have I written anything in any post of mine which does not directly apply to your efforts. Don't just skip over stuff you don't understand because you think it has no bearing.

You are perfectly capable of working with what I have given you. It is neither over your head nor is it smarter than you. You must, if you intend to continue working with Delphi, learn how to lookup information about the VCL with the Delphi help system, and you must understand how to create and use procedures and functions, and you must understand how the type of a thing affects the code used to manipulate it. Failing these things you will remain stuck.

It is time now to put a little effort into learning something about these things instead of demanding that I or anyone else simply give …

Duoas 1,025 Postaholic Featured Poster

I'd like to help more but at this point you aren't paying attention. I've given you all the code you need --which is much more than I usually do. You have to use your brain now and use the code I've given you correctly.

Duoas 1,025 Postaholic Featured Poster

Alright. Here's a SaveNLines that takes a TListItems.

procedure saveNLines(
  filename:  string;
  var items: tListItems;
  startAt:   integer;
  numLines:  integer
  );
  var
    sl:   tStringList;
    b, e: integer;
  begin
  // Our temporary string list
  sl := tStringList.create;
  // indices of lines to copy, inclusive
  b  := startAt;
  e  := startAt + numLines -1;
  if e >= items.count then e := items.count -1;
  // copy the indexed lines into our temporary string list
  for b := b to e do
    sl.append( items.item[ b ].caption );
  // save the lines to file
  sl.saveToFile( filename );
  // cleanup
  sl.free
  end;

Notice that nothing other than each item's caption is saved to file.

Sorry for the confusion. P.S. I haven't tested this code. It might need a tweak here or there.

squidd commented: a great help to me +1
Duoas 1,025 Postaholic Featured Poster

Don't bang your head too hard... you don't want to break it.

Unsatisfied forward or external declaration
You can declare a thing and you can define a thing:

unit fooey;
interface
// Everything in this section is a DECLARATION
function hum( bark: string ): string;

implementation
// Everything this section is a DEFINITION
function hum( bark: string ): string;
  begin
  result := 'Baz says "' + bark + '"'
  end;

end.

An Object Pascal unit requires you to first declare your functions, etc. in the interface section. Then you must use the implementation section to define the thing things you declared. If you do not define it, but only declare it, then you are basically telling the compiler that some function exists when it does not.


The type of things matters
Recall that I previously recommended you to use something other than a TListView? (such as a TListBox)? That is because the items property is a TListItems, not a TStrings. The former is weird and hard to handle. The latter is convenient and easy to handle. Unless you are making a spreadsheet or something you should not be using a TListView.

The procedure I gave you takes a TStrings, not a TListItems. If you insist on using a TListView then you will have to convert your items property into a TStrings object before using the function I gave you. If you don't want to do that either then you will have to get every …

Duoas 1,025 Postaholic Featured Poster

You didn't define save250 the way I gave it to you. The one you defined takes a single argument: a TObject. The one I gave you takes entirely different arguments.

The procedure header should look like this: procedure SaveNLines( filename: string; var strs: tStrings; startAt, numLines: integer ); Please notice how I renamed the procedure from save250 to saveNLines.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

No compiler error is user error... not unless the 'user' is the person using the compiler. :$

Check that you spelled everything correctly, that everything is in the proper scope, and if you still can't get it to work post your code here and I'll take a look at it.

Duoas 1,025 Postaholic Featured Poster

Did you define a procedure named save250? It won't work unless you do...

Duoas 1,025 Postaholic Featured Poster

Ah.

Virtual functions are the core of Object Oriented Programming --you can't do it without them. (Otherwise you are just doing "object-based" programming --or playing with structs that have functions attached.)

I think your professor wants you to understand what it is that OOP offers (i.e. what the benefit is from using virtual functions).

Part of the Animal type is an enum indicating what animal it is. If you can't use virtual functions you will have to change your makeAllNoisesInZoo() to use a giant if..else or a giant switch statement to check what kind of animal you have, then call the appropriate animal's makeNoise() function. if (a->getAnimalType() == t_Horse) ((Horse *)a)->makeNoise(); I was thinking of multiple-inheritance when you said "polymorphism". Sorry.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

You are trying to do something that windows is designed against permitting. So it will be a very technical problem.

If you want more information type "setwindowshookex" in the Delphi IDE, place the cursor on the word, and press F1.

You are going to have to learn how to use this stuff for yourself. (Sorry, I can't spare to write it for you.)

If you want help along the way, post back here.

Good luck.

Duoas 1,025 Postaholic Featured Poster

You need to read up on virtual methods.

Currently, Animal.makeNoise() is statically bound. In "zoo.h" you must say: virtual void makeNoise() so that the derived classes can override the method with their own versions.

Next, in your addAnimalToZoo() method, you have a memory leak. Let's trace your code:
1. in main() you allocate a new Horse.
2. in addAnimalToZoo() you allocate a new Animal (and use the default copy constructor).
3. in addAnimalToZoo() you put the newly allocated Animal in your array of animals
4. you forget about the Horse
5. in makeAllNoisesInZoo() you ask the first animal (whose type is Animal, not Horse, due to step 2) to make a noise. Animals are abstract creatures so aren't supposed to actually exist: Horses exist, Snakes exist, Cows exist.

My recommendations are
1. make Animal.makeNoise() a purely virtual function: virtual void makeNoise() = 0; Now an Animal class can't actually be instantiated. The user must instead instantiate a derived class (Horse, Snake, or Cow).

2. use the new-ed Animal object passed into addAnimalToZoo() instead of creating another Animal (which you can't do now anyway after recommendation #1):

void Zoo::addAnimaltoZoo(Animal *a)
{
	if (animalCount < ZOO_SIZE)
	{
		animals[animalCount++] = a;
	}
}

Fix that, give it a compile and run, and see if you can't fix the output error.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Caption is not an AnsiString, it is a __property.

A property is a way of making a member field that looks like a regular variable but which actually uses functions to get and set the value. C++ doesn't have properties in the language, but it is not uncommon to write a little class which does the job.

The __property class overloads all the operators necessary to make it look like an AnsiString, but it is still a different class, so you cannot pass it directly to the function. Since you don't know anything about the string besides what the accessor function gives you, you must use a temporary. This is the achilles heel of properties.

AnsiString temp;
  temp = Button1->Caption;
  AnsiChange( &temp );
  Button1->Caption = temp;

Enjoy.

Duoas 1,025 Postaholic Featured Poster

You are going to have to write a global hook and use SetWindowsHookEx. The procedure that does it will need to be compiled into a DLL (a regular application process is not permitted to use global hooks). Your application can then use the DLL to install the hook and remove it when it terminates.

I'm not sure you can trap CTRL+ALT+DEL, but I don't remember for sure either way.

Good luck.

Duoas 1,025 Postaholic Featured Poster

"A" is a string.
'A' is a char.
code is a char.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Sure it will. Pay attention to what is being made const: ZOO_SIZE is const. After the array is created, it has no other effect (since you can't change the size of an array after creating it anyway). Animal *animals[ ZOO_SIZE ] is not const. You can change elements of the array (for example: animals[ 2 ] = new Horse( 750.0, "George" ); ).

Each animal you create is not const.

When you write a function like: void do_something( const Animal &a ) what you are saying is that a is const. That is, your function gets an animal by reference, but is not allowed to change the animal in any way. When you use the function it does not matter whether the animal you give it is mutable or not.

Likewise, when you have a method like: void MyClass::MyMethod() const what that means is that the method is not allowed to change *this in any way.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

The only possible reason I can think of off the top of my head is that Button1->Caption is not an AnsiString.

Duoas 1,025 Postaholic Featured Poster

Ah, that helps. You need to be more careful about reading the documentation when using various procedures (line writeln).

For what you want to do, the save250 procedure can almost do it. Just add another parameter for the number of lines to save and adjust line 10 to use the correct value.

Then you can save each n lines in a loop.

procedure TForm1.Button12Click( Sender: TObject );
  var
    lines_per_block: integer;
    line_index:      integer;
    file_number:     integer;
    file_extension:  string;
    base_filename:   string;
  begin
  lines_per_block := strToInt( edit6.text );  // number of lines to save per file
  if saveDialog1.execute then
    begin
    // get the file extension and everything except the extension in
    // separate strings so we can inject the 1, 2, 3, ... file number.
    file_extension := extractFileExt( saveDialog1.filename );
    base_filename := copy(
      saveDialog1.filename,
      1,
      length( saveDialog1.filename ) -length( file_extension )
      );
    // save each block of lines
    line_index  := 0;
    file_number := 1;
    while line_index < ListBox.items.count do
      begin
      save250(
        base_filename + intToStr( file_number ) + file_extension,
        ListBox.items,
        line_index,
        lines_per_block
        );
      inc( file_number );
      inc( line_index, lines_per_block )
      end
    end
  end;

I used the name save250 just because that is what I gave you before, but I imagine you will want to rename it. Also, you can make it a private member of the TForm if you like...

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

I haven't looked over all your code, but the addAnimalToZoo() function looks fine to me.

Polymorphism just means that you can derive from more than one class at a time. So, for example, you could make a SnakeHorse.

Duoas 1,025 Postaholic Featured Poster

An AnsiString is a class, just like any other type of data.

To modify it in a function, pass it by reference: void myFunction( AnsiString &s ) Hope this helps.

Duoas 1,025 Postaholic Featured Poster

The choice of TListView is a bit odd to me. You could have just as easily used a TListBox or TRichEdit component, which will give you an items: TStrings or lines: TStrings property, as well as LoadFromFile and SaveToFile methods.

You also need to check to make sure the user did actually choose a filename. The filename returned will always be the full path of the filename --there is no need to add '.txt' to it:

procedure TForm1.Button12Click(Sender: TObject);
  begin
  if savedialog1.Execute() then
    ListBox.items.saveToFile(saveDialog1.fileName)
  end;

If you only want to save, say, 250 lines at a time, you can do something like:

procedure save250( filename: string; var strs: tStrings; startAt: integer );
  var
    sl:   tStringList;
    b, e: integer;
  begin
  // Our temporary string list
  sl := tStringList.create;
  // indices of lines to copy, inclusive
  b  := startAt;
  e  := startAt + 249;
  if e >= strs.count then e := strs.count -1;
  // copy the indexed lines into our temporary string list
  for b := b to e do
    sl.append( strs[ b ] );
  // save the lines to file
  sl.saveToFile( filename );
  // cleanup
  sl.free
  end;

Did you really want the caption saved at the beginning of each line?

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Hmm, you're right. I was thinking of the = operator in sed, which is just a line count...
I'm quite rusty at this stuff... so give me a little bit to find out what I can...

Duoas 1,025 Postaholic Featured Poster

Sed can do it easily. You'll have to get a little familiar with some simple regular expressions.

Here's a page with all kinds of useful information.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

/Me feels stupid

Perhaps I should get some sleep.

@tracethepath
To read a string as a character array then use cin.getline( a, 150 ); G'night all...

Duoas 1,025 Postaholic Featured Poster

That would probably be total overkill, but it would work...
Also, WaltP makes a very good point. Since this is a C++ program, would your professor totally object to using std::strings along with the rest of the STL?

Duoas 1,025 Postaholic Featured Poster

WaltP, I've compiled and tested the code. If count is zero then the spaces are written to the output file, and count is always reset to zero. It has no other effect on the code.

Duoas 1,025 Postaholic Featured Poster

I see... You're going to have to ask your professor for clarification on how he wants you to allocate to the array. There is no reasonably simple way to resize a dynamically allocated array in C++. A linked list would work...

Alas.


He might be looking for something along the lines of char *keys[ 50 ]; Where each key is a dynamically allocated array of char. But there is no way to dynamically allocate only part of the keys array at a time --it's all or nothing.

Duoas 1,025 Postaholic Featured Poster

Your compiler might be choking because you are mixing C and C++ I/O. While this isn't supposed to be bad, it sometimes is --particularly with older compilers.

Change your first few lines to:

string a;
char ch;
cout << "Enter a line of text:" << endl;
getline( cin, a );
ofstream file( "EXAMPLE.txt" );
file << a;
file.close();

In general, when coding C++ use the C++ way of doing file I/O, and don't use the C way of doing file I/O.

Also, every line that has the word count on it needs to be deleted. It is preventing those spaces from disappearing.

Hope that makes better sense.

[EDIT]
WaltP you missed the fil ifstream at the bottom... so he actually should see more output on the screen...

Duoas 1,025 Postaholic Featured Poster

If I understand what you want to do correctly, you want to do something like an associative array or a map where the first array simply indicates what type of thing is in the second array?
So: if (keys[ n ] == "name") cout << "Name = " << values[ n ] << endl; You need to read up on dynamic memory allocation and fix your syntax. Lines 14 and 15 each ask to allocate zero bytes of memory (an array of zero elements is zero elements long...).
Also, your syntax is screwy. Neither line makes any sense.

What errors are you getting from the compiler (the first few ought to be enough).


Frankly, since this is C++, you should be using a map<string, string> instead of an array of array of char.

Does this make sense?

Duoas 1,025 Postaholic Featured Poster

Never mix C and C++ I/O unless you know what you are getting in to. (Yes, the C++ standard says you can mix on the same target stream, but that is still somewhat vague and you mileage may vary with different compilers. Just don't mix unless you are forced to.)

That is the only thing I can see that can be messing you up...

Now, just get rid of every line with count on it and it should work just fine...

Duoas 1,025 Postaholic Featured Poster

Watch your fencepost conditions. j can become negative.

Try tracing your sort using this input:

arr3 = 1 3 7 2 9 0 5
       j
         i
temp = 3

Good luck.

tracethepath commented: thanx...it worked +1
Duoas 1,025 Postaholic Featured Poster

Very good. Just a few thoughts:

In your functions, you keep doing stuff you already have functions for. In the new operator+ method, you create the Distance object first, but you still don't use it until you are ready to return a value. Hint, use: Distance d3( sizeInInches() ); Now use an overloaded operator method you have elsewhere to add d2 to d3. No need to play with the feet and inches, or normalize them, because the other functions you already have will do all that for you. Make sense?

Likewise, in your comparison methods (operator== and operator<) there is no need to find the total number of inches yourself. You already have the sizeInInches() function to do that for you. Also, there is no need to say if (x < y) return true; else return false; The < operator returns a boolean value, so just use it directly: return (x < y); Good luck.

Duoas 1,025 Postaholic Featured Poster

Actually, you have done a very good job.

When you say: d1 = d2 + d3; you are actually doing two operations: d2 + d3 and then d1 = dtemp When you overload operators in-class as you are (that is, where the operator functions themselves are actually class methods instead of friend functions) what happens is that the left-hand operand's operator function is called with the right hand operand as the argument value. Hence: d2 + d3 is really the same thing as: d2.operator+( d3 ) When adding two things, you want to return a new value without modifying either of the addends, which is why I had you change it.


Now, what I'd like you to notice is that you had to repeat yourself to avoid modifying d2: you created two ints and did the same thing that normalize() does, and only then created a new Distance object as the return value.

Why not first create the new Distance object (instead of two ints), set it equal to d2, then add d3 to it with a function you already have, then return the new distance object?

Does that make sense?

Duoas 1,025 Postaholic Featured Poster

OK. Your class stores two pieces of information: feet and inches.
Every foot is 12 inches, so if a distance is 70 inches you can't just store it as feet without rounding it up or down to the nearest foot. If you look at normalize() you'll see that you take those 70 inches, get the 70/12=5 feet out of it and store that in feet, and store the remaining 10 inches in inches.

Likewise, the sizeInInches() works in reverse. The return value is the total number of inches, which is ((feet * 12) + inches), right? By using a local variable you are correct. Create a new int inside your function, do the proper calculations to give it a value, and return it.

int result;  // create a local variable (one we'll forget when the function is done)
result = feet * 12;  // convert feet to inches
result += inches;  // add any remaining inches
return result;  // return the total inches

Notice how I used the mathematical formula exactly?

Making things work is just a matter of not giving up. Eventually you'll make sense of it.

Good luck.

Duoas 1,025 Postaholic Featured Poster

[EDIT] Balla4eva33 posted the last message as I was posting this one, so this should be read as post #4 and balla's post #4 as post #5.[/EDIT]

Don't feel stupid. You are just going through what we all do (or did) when learning this stuff. Just keep thinking about it, and reading about it, and trying stuff. Eventually you'll "get" it.

I've already given you a pretty "dumbed down" answer (yeah... don't feel bad). Try to think it through for a day or so and if you are still completely lost post again and I'll help more. Even if your new tries don't work, post them.

Makes your brain feels like a walnut in a nutcracker, no?

Oh yeah, here's a good hint: don't write the same code over and over again. Notice how the sizeInInches() method (i.e. class function) is private. That means it is only meant to be used by methods of your class, such as the int() operator function and your comparison operators and etc. It is perfectly OK to use it over and over again.

Think about it and post again.:cool:

Duoas 1,025 Postaholic Featured Poster

The int() operator should return sizeInInches(). Also, watch it, your sizeInInches() function is not correct: you return the number of feet in inches but forget any extra inches there may have been in inches before calling the function. Since you don't want to normalize or un-normalize, use a local variable instead of modifying inches.

Your += operator is perfect. However, your + operator is not. Assume: d1 = [b]d2[/b] + d3 (not what you've got written above the function definition). Never modify the objects on either side of the + operator. The user wants a new object (d1). Hint: make a new return value as a copy of d2, then add d3 to it, and then return it.

When doing '+= int' think again what the int stands for: number of inches. Just add the int value to the inches and normalize.

In your comparison operators (== and <), be careful. You want to compare the sizeInInches(). (Also, be careful what it is you divide by 12 --moot point.) Finally, return (x < z) ? true : false; is a bit wordy. The expression x < z itself returns a boolean value, so you really only need to say: return (x < z); That should be enough to get you right. Good luck.

Duoas 1,025 Postaholic Featured Poster

You need to consider the format of your input. I will presume something like

Avery Brown
129 Landis St.
Chapel Hill, NC 01234
555-1234
Emma Green
13 Rabbit Run Rd.
Chapel Hill, NC 01234
555-2933

Every four lines is a different record. So read one whole record at a time (that is, read four lines at a time [as per my example, or however many lines per record you are actually working with]).

So, some pseudo might be:

get phone number from user
do
  get record from file
  if eof then complain and quit
while phone number from file doesn't match phone number from user
print entire record

Also, make sure you get a good reference. There is no such function as is_open(). You can test success directly from the object:

ifstream AB( "AddressBook.txt" );

if (!AB) {
  cerr << "I couldn't open the file 'AddressBook.txt'." << endl;
  return EXIT_FAILURE;
  }

// file is fine, ask user for phone number and do while loop go here

AB.close();

// print record found or tell user that record was not found

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

:icon_lol: Yeah, a lot of beginning-programming teachers are like that.

Glad to be of help. :icon_cheesygrin:

Duoas 1,025 Postaholic Featured Poster

Are you doing this for school or just for your own learning?

You are the one who asked about system("pause"); in your second post. How is it you are writing a command-line application and not know what the command line is or how to access it? Go hit your teacher over the head.

Duoas 1,025 Postaholic Featured Poster

Ehem...

Do one of the following:

1. Tell your IDE that you are compiling a console application --it should be smart enough to wait for you to read the console before the window disappears. If it can't do that:

2. Run your program from the command prompt. Or.

3. Use while (cin.get() != '\n'); instead of system().


[EDIT]
Yoinks...

I just tested your code and it works fine for me.

You might want to put a PrintArray() after you GenerateArray() just to see what the generated array was before printing out information.

Also, don't forget spacing and newlines in your output. For example, in sumArray() you should have: cout << "The sum of the matrix is " << sum << endl; And stick that while loop I gave you before the return statement in main().

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

I'm always just a little taken aback by things like getch(); and system( "pause" ); stuck in people's code. It is non-portable and in the case of getch() and cin.get(), leaves the input in an indeterminate state. Since the standard input is line bufferered, the most robust code would be something like: while (cin.get() != '\n'); ...which would read and discard anything typed until the ENTER key is pressed.

Even so, IMAO you shouldn't need to put such things in your code... The IDE should be able to do it for you or just run it from the command line as it was designed...

/me puts soapbox away

Duoas 1,025 Postaholic Featured Poster

That's just the compiler's obnoxious way of saying that you declared a method named TitledEmployee::setTitle but didn't define it anywhere.

What compiler are you using, BTW?

Duoas 1,025 Postaholic Featured Poster

That's because you've got it buried in the Employees namespace. Use its full name: Employees::TitledEmployee frank; Have fun.

Duki commented: Thanks for the C++ help! +4
Duoas 1,025 Postaholic Featured Poster

Good question! :-/

I do have to hit it fairly hard, and regularly. Sometimes with a good, heavy bludger. ;)

Duoas 1,025 Postaholic Featured Poster

An array is just an ordered list of things. So for the array to be serializable the elements of the array must be serializable. Hence, your conclusions 1 is correct. Conclusion 2 is correct for all elements in an array (not just objects).

However, conclusion 3 needs a little help: Primitive types are serializable by default whether or not they are stored in an array. Therefore it follows that any array made of primitive types is also serializable.

Hope this helps.

Duoas 1,025 Postaholic Featured Poster

Yeah. As far as I am concerned, the computer is there to serve me, not the other way around. ;)

The MS article you linked references only which files may be corrupted for the error to occur. QBasic has always used EDIT.COM or EDIT.EXE to do its editing. Version 1.1 is where the editor was rewritten.

Have you tried just going to the command prompt and typing help qbasic.hlp ? If that works, then it is definitely EDIT... If not, then it is definitely a corruption in one of the listed files...

Let me know what happens.

Duoas 1,025 Postaholic Featured Poster

Ah, yes. That would do it. ;) Glad you caught that.

Duoas 1,025 Postaholic Featured Poster

If it is from any of the DOS 6.x series or Windows 9x then it is QBasic 1.1. However, the editor (EDIT.EXE) changed for Windows 9x. Since DOS 6 is a 16-bit OS and Win 9x is 32-bit, you might want to search the web for the later editor. I'm using the 2.0.026 version of EDIT.EXE, copyrighted by MS in 1995. It doesn't have the WordStar diamond, but takes all the WordStar keys just fine...

Good luck.

Duoas 1,025 Postaholic Featured Poster

I'd be interested to know why application.terminate didn't stop your program. Have you got unusual hooks in there somewhere? Did your code actually call it?

The problem with the timer is that there is a system limit on the number of timers available. It doesn't matter how big your application is.

Duoas 1,025 Postaholic Featured Poster

The best way to terminate an application is to call application.terminate This prevents a lot of problems and can be called anywhere.

Avoid using tTimer as much as possible because it is a "heavy" object --chewing up resources and time.

Hope this helps.