All the help I have received in here has been wonderful and I am very glad that there are good people in here to help us newbies. I know I sure need it!

So these last few things would be nice to get some help with and then I will be done with this list modifier I have been working on for too long now. haha

1: Trying to sort a list from Z to A. I have A to Z done. I will post code if requested.

2: Sort a list numerically without it being sorted lexicographically. (thanks for that term Duoas)

3: Capitalize the first letter in a list of names... and/or capitalize all first letters on each word.
~I had some help from Duoas on that but I dont seem to be able to get it right. I cant seem to implement this on a button click. I have been trying all afternoon to do this and other things in this list i am writing up. -- s[ 1 ] := UpCase( s[ 1 ] );

4: Take each line in a loaded list and put it in reverse order. (i.e. 12345 will be 54321)

Thats about it. If this is too much for one post or I am not allowed to do this sort of thing, I will close this thread or a moderator can. I don't want to put silly questions in here at all.

Thanks for any help. BTW, this is all being done in a ListView.

Recommended Answers

All 15 Replies

Yes , please post the code first.

Code is as follows:

1: This is what I posted for the alphabetical and somenumerical values in the list that is loaded.

procedure TMainForm.SortListButtonClick(Sender: TObject);
begin
  ListView1.SortType := stBoth;
  CurrentStatusLabel.caption := 'List Sorted';
end;

I would like to also sort it from z - a... that is the problem atm...

2: Sort a list numerically... tried stdata..

ListView1.SortType := stData;

this does not truly sort numerically...

3: Capitalize the first letter in a list or all first letters in a list... no idea. Not much luck on reading up on it. Most code I saw was applied to other edit boxes and not tlistview.

4: Reversing the order of a line in listview.. Cant get that to work either and looking it up hasn't afforded much help either. I was given this to start off with.

s[ 1 ] := UpCase( s[ 1 ] );

so there you have it. :( im new

Thanks for any help...

Code is as follows:

1: This is what I posted for the alphabetical and somenumerical values in the list that is loaded.

procedure TMainForm.SortListButtonClick(Sender: TObject);
begin
  ListView1.SortType := stBoth;
  CurrentStatusLabel.caption := 'List Sorted';
end;

I would like to also sort it from z - a... that is the problem atm...

2: Sort a list numerically... tried stdata..

ListView1.SortType := stData;

this does not truly sort numerically...

3: Capitalize the first letter in a list or all first letters in a list... no idea. Not much luck on reading up on it. Most code I saw was applied to other edit boxes and not tlistview.

4: Reversing the order of a line in listview.. Cant get that to work either and looking it up hasn't afforded much help either. I was given this to start off with.

s[ 1 ] := UpCase( s[ 1 ] );

so there you have it. :( im new

Thanks for any help...

Squidd, whenever you look up Delphi help - e.g. for SortType - also make sure that you check out the entries under See Also.

In this instance what you need is to checkout the OnCompare. event. You can use this event to alter the way the sort is being done. Here is some, untested, code that should do your reverse sort

procedure TMaster.WhenLVCompare(Sender:TObject;Item1,Item2:TListItem;Data:Integer;var Compare:Integer);
begin
    Compare:=CompareText(Item2.Caption,Item1.Caption);
end;

As to the problem with capitalization - remember that you will need to update the corrected entry in the listview. Thus if you have the code

procedure TMaster.InCapLV;
var i:Integer;
     s:String;
     AList:TListItems;
begin
   AList:=lvOne.Items;
   with AList do
   for i:=0 to Count - 1 do
   begin
       s:=Item[i].Caption;
       s[1]:=UpCase(s[1]);
       Item[1].Caption:=s;
   end;
end;

you should get the result you desire.

As I have discussed before this is not really the right way to deliver speed nor to write good code. However, I guess that is the learning process you are currently going through.

p.s. - I guess I should have commented on the OnCompare event and the CompareText method

a. By default some Delphi controls, such as ListView, and controls, such as TStringList, know how to do a sort.
b. If you don't like the default sort order the offer - typically A -> Z - you can alter that by writing the OnCompare event.
c. CompareText is a unit in SysUtils - spend some time looking at the routines available in SysUtils. Could save you a lot of time. Here is what Delphi help says regarding CompareText

CompareText compares S1 and S2 and returns 0 if they are equal. If S1 is greater than S2, CompareText returns an integer greater than 0. If S1 is less than S2, CompareText returns an integer less than 0. CompareText is not case sensitive and is not affected by the current locale.

I think you will be able to figure out the rest.

Working on it now.. Actually have been working on it for the last 2 hours.

I implemented your sample code for Capitalizing the first letter, but instead of doing all of them in the list, it caps the last line and moves that line up to and writes over the second line in a loaded list.

Looking into that right now. Thanks you for your help. And I am still using ListView1 for the name as that is the only LV i have in this program. I am not disregarding your advice, but the name ListView1 for this program is comfortable for my purposes. Thank you for your help on this.

The other questions you ahev answered will be addressed after I correct this one. One thing at a time. :)

I found the problem with the capitalization of the first letter.

the line:

Item[1].Caption := s;

should be

Item.Caption := s;

now it works perfectly. :)


Also, I am going to try and capitalize any first letter in my list now. Thanks again for your help... You too Duoas!

I have the list capitalizing as it should now.. the code is probably poor, but it works...

I will now work on reversing the items in my listview.. but that will wait until tomorrow, I have spent a lot of time going back and undoing error correction the didnt work.

Thanks again! :)

How do I get a function to work when I click a Button on my form?

function StringReverse(const AString : string): string;

I thought I was to put this up in private declarations. Then add a button to perform a stringreverse procedure.

procedure TMainForm.ReverseOrderButtonClick(Sender:TObject);
  var
    s : string;
    begin
      s := Reversestring(s);
    end;

Obviously, this isnt working for me. I dont know how to get a button click to do a function listed elsewhere. AGH!

Thanks for any help.

What you have written looks right. But just to make sure you got there correctly (which makes all the difference):

1. You added a button to your form and named it "ReverseOrderButton".
2. You either a) double-clicked the button on your form, or b) changed the object inspector to list events and double clicked the "OnClick" item
3. You added your code.

Yes, it does something. However, in the example posted you reverse an uninitialized local string. That is, a string that only exists in the ReverseOrderButtonClick function and which you did not s := "hello"; before reversing, and which you have not displayed before the procedure quits and the string disappears. So, while you have reversed the string '', it never gets displayed and it appears that nothing happens.

Try this to see what it does:

procedure TMainForm.ReverseOrderButtonClick( Sender: TObject );
  begin
  with ReverseOrderButton do
    Caption := StringReverse( Caption )
  end;

The same is true for any Item[ x ].Caption .

Hope this helps.

private

function StringReverse(const AString : string): string;

this wont stop giving me the following error:

E2065 Unsatisfied forward or external declaration: 'TMainForm.StringReverse'

I dont know why its doing that.

ok i did the following:

lined out
//function StringReverse(const AString : string): string;
because of the error

then this:

procedure TMainForm.ReverseOrderButtonClick(Sender:TObject);
  var
    s : string;
    begin
      s := Reversestring(s);
      Caption := ReverseString( caption )
    end;

and it literally reversed the entire line on my form header! LOL

Didnt do the listview, just the header.. Which I thought was funny. Why is it doing the reversal to the form header instead of the list I loaded? Funny, but not what I needed.. lol

Ah.

The difference is whether the function is a method of the TMainForm class or not.

A quick tutorial:

Forward declarations vs. automatic declarations

Normally you might have a program that looks like this:

program foo;

function triple_it( x: real ): real;
  begin
  triple_it := x *3
  end;

var
  number: real;

begin
  write( 'Please enter a number to be tripled> ' );
  readln( r );
  writeln( r, ' tripled is ', triple_it( r ) )
end.

In this little program, we have both declared and defined a function named "triple_it". By declaring, we mean that we have told the compiler that it exists. By defining, we mean that we have told the compiler all the details about it. Typically, as in this example, things are declared at the same time they are defined. That is, by defining a thing we implicitly declare it as well.

In Pascal, a thing must be at least declared before it is used.

Sometimes, however, we need to tell a program that something exists before we actually define it. Hence, we need to use a forward declaration. Here's a simplistic example lifted off of the Wikipedia (and repaired for correctness):

program oddness;

function is_it_even( n: integer ): boolean; forward;

function is_it_odd( n: integer ): boolean;
  begin
  if n = 1
    then is_it_odd := TRUE
    else is_it_odd := is_it_even( n -1 )
  end;

function is_it_even;
  begin
  if n = 1
    then is_it_even := FALSE
    else is_it_even := is_it_odd( n -1 )
  end;

var x: integer;

begin
  write( 'Please enter a whole number greater than zero> ' );
  readln( x );
  writeln( 'The statement "', x, ' is odd" is ', is_it_odd( x ), '.' );
  writeln( 'The statement "', x, ' is even" is ', is_it_even( x ), '.' )
end.

Notice how we used the function "is_it_even" before we defined it? We told the compiler about it beforehand using the forward keyword. That is, we declared it. Thereafter we only needed to define it somewhere in the program.

This is how a unit works. They have an interface section, wherein things are declared, and an implementation section, wherein things are defined.
(If anyone here is using Extended Pascal and wants to know how this looks in a module, post here and I'll post with the details.) Here's a unit that provides the two functions:

unit oddstuff;

interface

  function is_it_even( n: integer ): boolean;
  function is_it_odd( n: integer ): boolean;

implementation

  function is_it_odd;
    begin
    if n = 1
      then is_it_odd := TRUE
      else is_it_odd := is_it_even( n -1 )
    end;

  function is_it_even;
    begin
    if n = 1
      then is_it_even := FALSE
      else is_it_even := is_it_odd( n -1 )
    end;

end.

And the program that uses it:

program oddness;
uses oddstuff;
var x: integer;
begin
  write( 'Please enter a whole number greater than zero> ' );
  readln( x );
  writeln( 'The statement "', x, ' is odd" is ', is_it_odd( x ), '.' );
  writeln( 'The statement "', x, ' is even" is ', is_it_even( x ), '.' )
end.

One thing to note is that in the definition of the procedures/functions, you only needed to name it. You did not need to specify all the parameters and the like. Typically Borland IDEs and variations will duplicate the procedure/function header with the definition. Both have to match exactly. But it is not strictly necessary to duplicate the declaration with the definition.

Classes

A class is always described in two parts: a declaration part and a definition part. (This separation is necessary, but I'll not go into details as to why here.) The declaration looks like you are used to seeing:

type
  tMatrix = class
    private
      f_rows, f_cols: integer;
      f_elements: array of array of extended;
    public
      constructor create( rows, cols: integer );
      function get_element( row, col: integer ): extended;
      procedure set_element( row, col: integer; value: extended );
    end;

In the definition, you must fully qualify the name of the methods of the class, otherwise the compiler thinks you are talking about some other procedure named (e.g.) "set_element" --not the method of the class.

So our definitions may be:

constructor tMatrix.create( rows, cols: integer );
  begin
  f_rows := rows;
  f_cols := cols;
  setLength( f_elements, f_rows, f_cols )
  end;

function tMatrix.get_element( row, col: integer ): extended;
  begin
  result := f_elements[ row, col ]
  end;

procedure tMatrix.set_element( row, col: integer; value: extended );
  begin
  f_elements[ row, col ] := value
  end;

In each instance, I had to prefix the name of the class to the name of the method, so that the forward declaration is satisfied. If I had just said:

function get_element( row, col: integer ): extended;
  begin
  result := f_elements[ row, col ]
  end;

The compiler would have complained, saying: I don't have a function named "get_element". (The only thing I've got so far is a class named "tMatrix".) Since the get_element function is a member of tMatrix, we must use its full name.

Well, I hope this explains things better.

Oy, after all that typing you beat me to the punch with another Q.

Second tutorial: scope.

Just as the functions and procedures above all belonged to tMatrix, so do the variables. Remember how you can do something like:

program McGonagalls_notes;
type
  tStudent = record
    name: string;
    grade: integer
    end;

var
  my_student: tStudent;

begin
  with my_student do
    begin
    name := 'Hermione Granger';
    grade := 100
    end
end.

Professor McGonagall remembered that when she is only thinking of one particular student, she doesn't need to remember all the information about where or how the student is referenced --she can just concentrate on that particular student. If she had preferred, she could have just said:

my_student.name := 'Hermione Granger';
my_student.grade := 100;

It is the exact same thing, but written using different scoping rules (by using the with statement).

The scope is what you can see at the moment. In an earlier example I created a unit to return whether a number is odd or even. Now, consider the following:

program oddness;
uses oddstuff;

procedure is_it_odd( n: integer ): boolean;
  begin
  result := FALSE;
  end;

var x: integer;

begin
  write( 'Please enter a whole number greater than zero> ' );
  readln( x );
  writeln( 'The statement "', x, ' is odd" is ', is_it_odd( x ), '.' );
  writeln( 'The statement "', x, ' is even" is ', is_it_even( x ), '.' )
end.

Now, the question is, "Which is_it_odd function gets called? The one in the unit or the one that doesn't work?"

The answer is, "Which one is in the current scope?" The one that doesn't work is. To use the one in the unit instead of the bad one, I'd have to specify the correct scope: writeln( 'The statement "', x, ' is odd"', is [B]oddstuff.is_it_odd[/B]( x ), '.' ); The same thing is happening to your caption. In the example I gave you, I was careful to specify that I wanted a specific buttons's caption. In your example, you left it to the current scope. Since the procedure is a method of the TMainForm, the current scope is that of the main form, so when you say "caption" it finds the one in the current scope --and changes the main form's caption.

[EDIT] As an addendum, you should not that "is_it_even" works fine. That's because the scope inside the "is_it_even" function is inside that "oddstuff" unit. So is_it_even calls the correct is_it_odd function. [/EDIT]

Hope this helps.

commented: very well written and helpful +1

Argh. Missed a key:

[EDIT] As an addendum, you should note that "is_it_even" works fine. That's because the scope inside the "is_it_even" function is inside that "oddstuff" unit. So is_it_even calls the correct is_it_odd function. [/EDIT]

WOW Duoas! Thank you for all the work you did there! I am reading it, then rereading it.. and them some more...

I will post back when I get this down.

Thanks again! :)

ok Duoas, I have read that about 10 times now over thanksgiving and whatnot and have a pretty good understanding of that now. Thanks for the help there!

Very good information Duoas. Very well written and laid out for the beginner to understand.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.