Jump to content

giomach

Members
  • Content Count

    51
  • Joined

  • Last visited

Posts posted by giomach


  1. I hadn't used any $A directives in the project, but I put in {$A4} as you suggested, and magically the number of records is 951.

     

    There are still other errors to fix, but I seem to be able to access the records now.

     

    Thank you very much for your help.


  2. I've just tried all values from off to quad word several times and they are all giving 998.  An hour ago, they were all giving 977 ...  I can't make any sense of it.

     

    If we don't know what alignment D5 does, and can't find out how to make XE do the same, the only solution may be to extend the program with a procedure to export the datafile to a text file, compile and run on D5, then extend the program with a procedure to import from the textfile and run that on XE.


  3. Adding filler: string [2] reduces the reported no of records in XE from 998 to 977, but this does not help, I'm still unable to retrieve them.

     

    I found that changing the XE compiler option "record field alignment" from byte to word also reduces the number to 977.  But also no help.

     

    The option in D5 is a check-box named "aligned record fields", which is checked by default, and this was probably the setting when that file was produced.


  4. Thanks, Holländer, but the program doesn't get as far as that.  After it misreports the number of records, any further reading of data (by 'seek' and 'read') just produces rubbish (out of range, etc).  I think I need to make it get the number of records correct before it can even separate the records, and I think that means some change to my definition of lexrec. 

     

    Thanks Uwe.  951 records is correct, and that is what the program compiled in D5 reports. Compiled in XE, it reports 998 records, before going nuts.  Some of the things I have tried in place of string32, like shortstring or array[1..32] of char, produce other wrong numbers of records.


  5. I took an old program (Delphi 5) and tried to recompile and run it under XE.  There was a data file, created under D5, which I tried to read in the recompiled XE program but it is misread — even the number of records comes out wrong (the correct number in 951).  Here is a minimal example of the program source (the form is empty).  It works perfectly when compiled in D5 under WinXP and run on the same data file. I'm also dropping the data file below.

    unit MorphAll;
    
    interface
    
    uses
      Forms, SysUtils, Dialogs;
    
    type
      TForm1 = class(TForm)
        procedure FormActivate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.DFM}
    
    type
       valid_range = -1..5;
       string32 = string [32];
       supp_rec = record
                     flag: integer;
                     case nform: integer of
                       1: (single: array [1..1] of string32);
                       2: (double: array [1..2] of string32);
                       3: (treble: array [1..3] of string32)
                     end;
       normal = array [1..20] of integer;
       lexrec = record
                    root_part: string32;
                    case speech_part: valid_range of
                      -1: (suppletive_type: supp_rec);
                       0: (nsupp_type: integer);
               1,2,3,4,5: (normal_type: normal)
                      end;
       lexfile = file of lexrec;
    
    var morphlex: lexfile;
        nooflexrecs: integer;
    
    procedure TForm1.FormActivate(Sender: TObject);
    begin
    assignfile (morphlex, 'MorphIr.dat');
    reset (morphlex);
    nooflexrecs := System.FileSize (morphlex);
    ShowMessage ('Data file contains '+inttostr (nooflexrecs)+ ' records');
    end;
    
    end.

    I suspect the trouble is the type declaration string[32].  When the data file was created (D5), this would have been an old-style string, and moreover the encoding would have been Windows 1252.  How can I make XE interpret these strings correctly (if that is what is wrong)?

    MorphIr.dat


  6. Thanks Ioan, that worked great.

     

    My next question to all 🙂  Many of the files I'll be looking for will not exist on the server.  Is there a way to test for the existence of a remote file without actually trying to download it, and importantly would that be quicker than what I'm doing, which is trying to download and checking whether the size is non-zero?  (I will treat a non-existing remote file and an existing file of zero size in the same way, so I don't need to distinguish those two cases.)


  7. Thanks for both suggestions, but in both cases it looks like a steep learning curve would be involved!  Lots of technical jargon to be deciphered!

     

    Actually, I think TMediaPlayer can do all that I need.  I now realise that it can handle WAV as well as MP3, and that it will extract a clip, given start and end times.  It's just a matter of finding out how to do it all.

     

    I intend adding these sound files to a Windows VCL app which I distribute, and I have some decisions to make: store the sounds locally or remotely; store them as WAV or MP3; store them as many separate files or extract them on-the-fly from longer files.  I'll just have to try them all and see what works best.


  8. I'm likely to have further elementary questions about IdHTTP, so if someone can recommend a reference on using it to access REST in the context of Delphi (and preferably a written reference rather than a video), that might save time and bother.

     

    Meanwhile, here's my first simple question.

     

    The Delphi statement

                                s := IdHTTP1.Get (url+filename);

    where s is a string successfully fetches data from a remote server.

    But when the remote file is actually a sound file, having it in a string is not much use to me.

    How can I get it into a sound file on my local machine?

     

    Thanks in advance for your advice.
     

     


  9. Thank you, Remy.  Yes, those two design-time packages were not present on the list of Installed Packages, so I added them, and everything seems to be in order again.

     

    When I was writing the "old" program some years ago, I had to update Indy (from 10.1.1. to 10.6.2) and these packages were on the list then, and I have no idea how they could have been removed in the interim.


  10. Windows 10, Delphi XE

     

    It's some years since I used TIdHTTP in a program.  Now I'm trying to use it again, in  new program.

     

    I don't remember whether in my old program I simply added IdHTTP to the "uses" statement, but when I do that in the new program I get F1026 File not found: 'IdHTTP.dcu', as well as Cannot resolve unit name 'IdHTTP' at line 38

     

    Perhaps in the old program I had placed some control on the form, but now I don't see anything on the Tool Palette that mentions TIdHTTP.

     

    On going back to my old program and trying to open the source (which is unchanged and has "IdHTTP" in its "uses"), Delphi now says Error reading Form1 - Class TIdHTTP not found and the form is not created.

     

    What could be causing IdHTTP to go missing?


  11. Windows 10, Delphi XE

     

    I want to play a short sound file in response to clicking a button (var SoundButton:TBitBtn).  I have two ways which work, but neither is fully satisfactory.

     

    Method 1: with a WAV file — fast, but needs a lot of disk space to store the files

    procedure TFocalForm.SoundButtonClick(Sender: TObject);                         // 2024/03/20     for .WAV
    var ms: TMemoryStream;
    begin
    ms := TMemoryStream.Create;
    try
        ms.LoadFromFile (SoundFileName);
        ms.Position := 0;
        sndPlaySound (ms.Memory, (SND_ASYNC or SND_MEMORY))
      finally
        ms.Free
      end
    end;

    Method 2: with a MP3 file (var SoundPlayer: TMediaPlayer) — saves disk space but there is a delay of several seconds before the sound starts

     

    procedure TFocalForm.SoundButtonClick(Sender: TObject);                         // 2024/03/20     for .MP3
    begin
    SoundPlayer.Close;
    SoundPlayer.Filename := SoundFileName;
    SoundPlayer.Open;
    SoundPlayer.Play;
    end;

    Is there a better way?

     

    And a related question: these sound clips — there could be hundreds of thousands of them eventually — are extracted from a smaller number of larger sound files.  Is there an interface to play such a clip from the larger file, by supplying start and finish times?  And if there is, would it be any advantage at runtime?

     

    Thanks for your suggestions.

     


  12. Using Delphi XE Update 1 (2010)

     

    I'm trying to set the application icon to one I have created, and have this icon appear on a desktop shortcut to the application.

     

    The first screenshot shows the .dpr file. I don't know why both *.res and *.dres are present, they just appear and disappear.

    The second screenshot shows that I have no "additional" icons in the application. The *.dres has disappeared when I removed a previous additional icon.

    The third screenshot shows setting the MAINICON.  I would prefer to choose the 256x256 79KB one, but this gives "out of system resources" — but that's a separate problem.

    So I choose the 48x48 10KB version, and the fourth screenshot shows it loaded.  I now rebuild the application.

    The fifth screenshot shows Resource Hacker confirming that this is the only icon in the application.

    The sixth screenshot shows another utility also confirming it.

    I now create a desktop shortcut to the application. The seventh screenshot shows the result — Delphi XE's default icon on the desktop instead of the one I want.

     

    I know I can tweak the shortcut to get the icon I want, but this is no use.  I need this icon automatically on the shortcut created by the installation of the application on other machines.

     

    Any help welcome.

     

     

    Screenshot (98).png

    Screenshot (99).png

    Screenshot (100).png

    Screenshot (101).png

    Screenshot (102).png

    Screenshot (103).png

    Screenshot (104).png


  13. TDictionary has now solved the problem — but not exactly in the way I expected.

     

    To summarize, I have two programs — a "setup" program which produces data in the form of two stringlists which correspond item-by-item; and a "user" program which reads this data and repeatedly looks up a string in the first list and extracts the corresponding string from the second list.

     

    This works perfectly well, but in raising this thread I sought to improve the speed of TStringList.IndexOf in the user program by sorting the first list in the setup program before exporting it.  To do this, while keeping the two lists aligned, I combined them into a single "name=value" stringlist, which I custom-sorted on the "name" and exported to the user program.

     

    But in the user program, searching the combined stringlist, IndexOfName still used the slow linear search.  Next, in the user program, it would have been logical to re-separate the combined list into two stringlists, but instead I chose to skip that avenue, and to read the combined list into TDictionary.  Access from there works and is very fast.

     

    I had considered using TDictionary in the setup program, but it has no SaveToFile member.   In fact, a TStringList seems to be one of the few things that can be passed from one program to another via a file.  So  the TDictionary processing has to take place in the user program, and there is no point in having the data sorted in the setup program.  That is, I had to add processing into the user program in order to speed it up!

     

    Thank you all for your contributions to the solution, including those whose suggestions I did not get around to trying.

     


  14. I'm (slowly) working through the suggestions.

     

    1. Use a name=value pair in TStringList

     

    My version of Delphi (XE) doesn't seem to have this. (BTW, where can you find out when a Delphi feature - such as IndexOfName - was first introduced?)
    But anyway there could be no time saving in using IndexOfName to look up a list which has been sorted on the whole string, and I don't see a way to sort on Name only.

     

    2. Use TStringList.AddObject to hold (the index of?) the associated string

     

    This technique seems to be frowned on but I tried it anyway.
    I have also seen mention of a problem if the string exceeds the size of a pointer, so perhaps I must use the integer index rather than the actual string.
    But tests seem to indicate that TStringList.SaveToFile saves only the strings, not the attached objects.  I'd like confirmation of that before moving to the next suggestion.  If it's true, it's not useful for me, as the setting up of the lists and their consultation are in different programs.
     

    3. Use a TPair in TList

     

    This is promising because (in contrast to no 1) both TList.Sort and TList.BinarySearch seem to support a custom comparison (in which I would use only the first element of the pair).

    It is next on my list.

     

    TDictionary, of which I have high hopes, will be next after that.

     

     


  15. 12 minutes ago, Sherlock said:

    But, lets let the TE clarify... @giomach has either been overwhelmed by the answers or is carefully formulating a response right now.

    Right on both counts, Sherlock!

     

    While digesting all those very welcome suggestions, meantime I apologize for not making myself clearer and for confusing Find with IndexOf.

    For clarification, the list I want to sort will have no duplicates.

     

    At present, with no sorting, both lists are built sequentially by ADDing corresponding items, and later I have something like this:
                list1, list2: TStringList;
                s1, s2: string;
                ...
                s2 := list2 [ list1.IndexOf (s1) ]
    which works very well, but is slow.

     

    If I make list1 SORTED, the code above is much faster, but the answers are wrong, because the order of items in list1 has been changed by the sorting whereas list2 is the same as before.  To get the benefit of speeding up, I want to re-order list2 to match the way list1 was reordered by the sorting.

     

    Taking up the idea of an index array (or list), the following might work, and slowness here wouldn't matter so much:
               Copy list1 to list1a
               list1.Sort          // will ensure the collation order is compatible with TStringList.IndexOf
               Construct an index by comparing list1 and list1a
               Copy list2 to list2a
               Clear list2 and rebuild it sequentially using list2a and the index.
               
    But I need to examine the other proposals before doing anything else.

     

    • Haha 1

  16. I'd be grateful for your thoughts on the easiest way to program this.

     

    I have two TStringLists, which correspond item-by-item. I intend to use Find on the first list, and extract the corresponding item from the second list.  So far it works well.

     

    Now I want to speed up the Find by having the first list sorted.  But this will change the order of items on the first list, and the result of the Find will not fetch the right item from the second list.

     

    Is there a component which can hold both lists, and sort them both, using one of them as the sort key, so that they stay in step?

     

    It seems a simple problem, but I haven't found a simple answer.  TStringGrid seems appearance-oriented, with a header row, and sorting is not straightforward.  Or TStringList's AddObject might be possible, but it is difficult to find a relevant example program. Or define my own descendant of TList? (I'd need an example of that). Or adapt a textbook quicksort algorithm to include handling the second list?

     


  17. This is the outcome of my attempt to replace the popup menu at the upper right (as shown in a previous attachment) by a control which will not disappear unless I make it, while preserving as much of the appearance as possible.  This is implemented by means of a number of TSpeedButtons created at runtime and placed on a TPanel which is created at design time.

     

    popup2.thumb.jpg.a270332712d53e2fad4769208defb238.jpg

     

    It's fairly satisfactory, most importantly the accelerator keys work.

     

    If there's anything of interest in this, it is probably the fact that the SpeedButton under the cursor, although it stands out a little, does not change colour here, though it does so in a newly-created VCL project.  After much trouble I tracked this down to my old application having Project/Options/Application/Enable runtime themes not set, whereas it is set by default in a new project.  However setting it in my old project upset my colour scheme and made a TListView malfunction.  So I make do without setting it, and partially compensating by putting Flat = true on the SpeedButtons.

     

    Thanks to all who helped me towards a solution to this problem, which has been rumbling on for years.

     


  18. The sample project is working well now — I needed to put OnExecute handlers on the actions.

     

    I'm pleasantly surprised to find that TSpeedButton shares some of the desired features of TMenuItem, even without further programming by me.  I'll try now to use it in my application, and see how that goes.

     

    Apart from anything else, I have learned about "Actions", and the technique for getting a popup to follow the movement of the main form will certainly be useful.

     

    Thanks again all round.

     


  19. Thank you all for taking the trouble to help.

     

    I'm trying programmerdelphi2k's solution but I'm missing something, as clicking any of the three buttons produces no result (the ShowMessage doesn't appear).

     

    test.thumb.jpg.39f5bcab1f4ab0cebce7c5c5a39f6827.jpg

     

    I also attach my unit3 source and the text of my form3.

     

    I also attach a screenshot of my application at present. The rectangle at the upper right of the form is a dynamically-built TPopUpMenu.

     

    popup.thumb.jpg.7b350f189572af1d73406d0c1874bf3a.jpg

     

    You can see the features of TMenuItem which I am using:  accelerator keys on the bottom three items, a separator item above these three, highlighting of the item under the mouse, enabling and disenabling items according to the context.  These are all provided by TMenuItem.  Not seen is the use in programming of TMenuItem's tag property.  Perhaps these can all be implemented in the suggested solutions by additional programming? — I don't know if that is possible.

    form3.txt

    Unit3.pas


  20. Thanks for your suggestions.  I want to emphasize that I really do want the menu items to look like TMenuItem — I want to have accelerator keys, a tag property, separator items (caption = '-'), highlighting of the item under the mouse, etc.  The aspect of TPopupMenu that I don't want is that it disappears by itself.  I've been down the road of writing handlers for every event that could make the popup menu disappear, but that just leads to more problems.

     

    I may be wrong, but it seems difficult to achieve the visual "simulation of a popup menu" that I have described using other standard controls, such as possibly TButtonGroup, whether placed on a separate form or not.

     

    This leads me to think that the solution must be a new control, a descendant of TMenu using TMenuItem directly, probably mixing code from both TMainMenu and TPopupMenu, but I have no experience of writing controls.  So I asked if such a control already exists, or if not, how I should go about making one.

     

    If I have failed to understand the suggestions already made, please say if you think they can still work for me.


  21. I'm looking for a VCL control to use in Delphi XE.  It should be made up of TMenuItems, but neither TMainMenu or TPopupMenu meets my need.

     

    Unlike TMainMenu, the control should allow placement anywhere on the form, and should allow the items to be displayed vertically  — as TPopupMenu does.  (I don't need submenus.)

     

    Unlike TPopupMenu, it should not disappear when an item is clicked, but should have Hide and Show methods.

     

    Basically I want the appearance of a popup menu but with the behaviour of a normal control.

     

    Does such a control exist?  If I have to create it myself, where should I start?

     

    Thanks for any ideas.


  22. Thanks for your replies.

     

    FocalForm is the only form in my application.  The code snippet occurs in the implementation section of the form, but in a procedure which is not declared as a member of the TFocalForm class.(Perhaps the procedure could/should be so declared, if that would make any difference in this case.)

     

    At present, the statement FocalFormResult := FocalForm.LemmaListBox.ShowModal; produces the error undeclared identifier:'ShowModal'.  I'm guessing that I would have to create a second form/unit just to hold the TListBox before I can use ShowModal on it.

     

    If that's so, I think I prefer my present method which keeps the TListBox integrated with the rest of the form, so that eg. I can control its placement, and I can allow some of the other controls to remain accessible while the TListBox is waiting to be clicked.
     


  23. Thanks, that clarifies things.  Unfortunately the suggested solution would be difficult given the program structure — the code snippet occurs in one branch of an if statement, and the bulk of the rest of the code comes outside that if statement, after the branches re-unite.  Rather than undertake a large-scale program restructure, I think I'll regretfully stick with application.processmessages.

×