Jump to content

Incus J

Members
  • Content Count

    83
  • Joined

  • Last visited

Everything posted by Incus J

  1. I’ve added a folder of sample images to an FMX application. They appear listed in the Deployment manager. When the app is deployed on macOS, these images are included inside the application bundle in Contents/Resources/Startup/ How can I obtain a normal directory path to this internal folder, for internal use by the application? For example is there something like TPath.GetInternalResourcesFolder; ? I’m looking for the path to the folder only, rather than a full path to one single image file, so my app can load up all sample images in that folder when it starts up, without me having to reference each image filename individually in code.
  2. Incus J

    How to obtain a path to a folder inside the app bundle?

    That's very useful - thank you!
  3. Incus J

    How to obtain a path to a folder inside the app bundle?

    I've found a post from April 2019 by Dave Nottage that looks like it might be adapted to do the trick: // Bit of a "hack" to get the exact paths of the pdf files deployed to /Contents/Resources/Startup LSourceName := TPath.GetDirectoryName(ParamStr(0)); LSourceName := TPath.Combine(StringReplace(LSourceName, '/MacOS', '', []), 'Resources/Startup/' + AFileName); ...seems to work OK 🙂. Would make a nice addition to the built in TPath class: class function TPath.GetAppResourcesPath:string; var appPath:string; begin appPath:=TPath.GetDirectoryName(ParamStr(0)); result:=TPath.Combine(StringReplace(appPath,'/MacOS','',[]),'Resources/Startup/'); end; ...though it would need adapting further to produce a sane result on all supported platforms.
  4. I'd like to search for, and then highlight a line or phrase of text in a TMemo. I can get the Caret to move to the start of the correct location via SelStart, but when I set SelLength the selection does not expand visibly. The text highlight does not appear. Here's my approach : s := 'section'; i := MyMemo.Lines.Text.IndexOf('['+s+']'); if i>-1 then begin MyMemo.SetFocus; MyMemo.SelStart := i+1; MyMemo.SelLength := s.Length; MyMemo.Repaint; //MyMemo.ScrollTo(MyMemo.Caret.Pos.Y,0); I suspect the selection is actually being made successfully, internally behind the scenes, but the control is failing to highlight its current selection. If I start typing, the not-visibly-selected text is replaced with what I type. I added Repaint to see whether that would give the control a gentle kick to persuade it to display its selection highlight, but no joy so far. I can highlight text with the mouse OK, and the control is set to display its highlight whether focussed or not (HideSelectionOnExit is false). The memo is not currently ReadOnly. I've also tried toggling the control type between Platform and Styled, but the behaviour remains the same. (You can also spot that I'd eventually like to scroll the selected line into view, and I'd also like this to happen on a ReadOnly memo without giving the memo focus - but one step at a time.)
  5. I've just tried your suggestion, and it works perfectly. I don't think I would ever have thought to look under .Model for a SelectText method. It even scrolls the line into view, and it works when the memo is ReadOnly too. Thank you Lajos!
  6. Incus J

    Calculate the width of a Popup Menu?

    I'd like to calculate the width of a Popup Menu before it is displayed, so that I can position and align it accurately when I call its .Popup(x,y) method. function CalcPopupMenuWidth(popup : TPopupMenu) : single; var i : integer; w : single; item : TMenuItem; begin result := 0; for i := 0 to popup.ItemsCount-1 do begin item := popup.Items[i]; w := popup.Items[i].Width; if w > result then result := w; end; end; The above approach iterates over the individual menu items, to determine the widest item. It almost works, in that it calculates the width correctly, but only after the Popup Menu has been displayed once. If the Popup Menu has never been displayed (yet) then this code always returns a value of 50. I'm guessing maybe that's a default width for a TMenuItem, which gets updated with the actual width shortly before it is displayed. How can I calculate the dimensions of a Popup Menu before displaying it?
  7. I've created a TPopupMenu, and assigned it to the PopupMenu property of a TButton. When the button is left clicked I'd like the assigned PopupMenu to appear just below the button. The documentation suggests : "Use PopupMenu to set the context menu of the current control. The pop-up window is displayed when ShowContextMenu is called." In the button OnClick handler, I've added : procedure TmyForm.myButtonClick(Sender: TObject); begin myButton.ShowContextMenu; end; This doesn't compile : [dccosx64 Error] myForm.pas(73): E2362 Cannot access protected symbol TControl.ShowContextMenu The procedure ShowContextMenu seems to be Protected. Perhaps it is not meant to be called directly, but I haven't spotted an auto-popup option yet. ShowContextMenu takes coordinates, but I'd like FMX to decide the best place to display the PopupMenu for me, rather than me having to specify coordinates, because the form can be resized or maximised, and the width of the PopupMenu may vary depending on the length of the menu items, so the ideal position is likely to be variable. How do I get a button to show its assigned popup menu (in a sensible position) when left clicked?
  8. Incus J

    TButton : How to display the assigned Popup Menu?

    I'll go with the above code for now, until I find a better way to do it. I'm just trying to figure out how to calculate the width of the Popup Menu before it appears, so I can align it centrally or right-aligned. At the moment it displays left aligned (to the left edge of the button) - right aligned to the right edge of the button would be particularly useful as the button is positioned at the very right hand side of the form. I could do with a property like : PopupMenu.Width; //no such property TMenuItem has CalcSize and CalcRenderSize so perhaps I could iterate over the Items to determine a value for the widest Menu Item.
  9. Incus J

    TButton : How to display the assigned Popup Menu?

    TButton.DropDownMenu looks to be the right thing to use for a VCL application. The FMX TButton doesn't have that property though, so perhaps FMX lacks this capability.
  10. Incus J

    TButton : How to display the assigned Popup Menu?

    Yes, I'm probably trying to use it for something other than intended (this happens to me quite a lot). Still, click a button for a menu to appear, must be a fairly common requirement. I'll see whether FMX offers another control better suited for this. Ah - I've just seen your last reply, thank you - I will take a look.
  11. Incus J

    TButton : How to display the assigned Popup Menu?

    Hi Virgo - Yes, it pops up OK on right click (but the menu tends to overlap the button, obscuring it). I've come up with this for left click : procedure TmyForm.myButtonClick(Sender: TObject); var h:single; pt:TPointF; begin h:=myButton.Height; pt:=myButton.LocalToAbsolute(PointF(0,h)); pt:=Self.ClientToScreen(pt); myButton.PopupMenu.Popup(pt.x,pt.y); end; ...though it seems a bit convoluted, and I'm not sure how robust it is.
  12. I’m creating a record helper for string. It seemed like a good idea at first, until I realised string already has a helper, and I can’t inherit from it (?) So I think I need to duplicate those existing default string helper functions in my new string helper, and call into the original. Something like this : function TStringHelper.ToInteger: integer; begin result := System.SysUtils.TStringHelper.ToInteger(Self); end; [dccosx64 Error] My.Str.Helper.pas(36): E2018 Record, object or class type required Don’t laugh, am I anywhere close…?
  13. Thanks Uwe, I've had a look in the Object Inspector, and in the documentation, but there doesn't seem to be a HideSelection property on TMemo. However there is HideSelectionOnExit. I have that set that to false at the moment, but no joy - when I make a selection in code via SelStart and SelLength, no highlight is displayed.
  14. That's unfortunate, I did like the concept of helpers. Really I just wanted to add a couple of extras, to make my coding a little less verbose with fewer brackets e.g. mystring := mystring.Trim.Capitalise; vs mystring := TMyStringUtils.Capitalise(Trim(mystring)); ...the flow and readability of the first version has some appeal. I find it easier and quicker to parse. I think adding the ability to inherit from an existing helper would make helpers more practical. Better would be types supporting multiple helpers simultaneously. Hey, I can dream 🙂 Thank you for the heads up!
  15. I have a two column TStringGrid on my main form. I set the column widths in the form designer at design time. I think this used to work, but at runtime most designer column widths are now ignored - all columns default to the width of the first column. Is it possible to get the app to apply the other column widths set at design time? I can set a column width in code : MyGrid.Columns[1].Width:=200; but that involves a bit of trial and error, so I'd prefer to set it visually. Incidentally while playing around with this, I found : MyGrid.Columns[1].Align:=TAlignLayout.Client; autosizes the last column to fill remaining space, which is useful. However this TStringColumn Align property does not appear in the Object Inspector - it is not a Published property, so this can only be set in code.
  16. Incus J

    TListView OnChange Event Doesn't Fire

    I have an FMX project with a TListView control. I need to detect when the user selects an item in the list. There's no OnItemSelected event, but previously I used the control's OnChange event for this. Since upgrading from 10.4 to 10.4.1 this no longer works and I'm seeing odd behaviour : Click on any item in the listview - OnChange event does not trigger 😞 Select an item using the Up/Down arrow keys on the keyboard - OnChange event triggers OK 🙂 Click and hold down on an item for a couple of seconds until the blue selection rectangle updates - OnChange event then triggers on release 😕 It's as though if the user releases their mouse button before the selection rectangle moves to the new item (which takes a second or so) then the item is still selected visually as expected, but the accompanying OnChange event fails to fire. The documentation says FMX.ListView.TListViewBase.OnChange "Occurs when the ItemIndex property changes as a result of a user selecting a different item. Write an OnChange event handler to respond to changes of the ItemIndex property. OnChange allows a response once the list has been successfully changed." I've tried using the similar OnChangeRepainted event instead, but get the same result. Has anyone else encountered an issue with TListView OnChange? (In case it is significant I'm using a laptop, so trackpad rather than a mouse)
  17. Incus J

    TListView OnChange Event Doesn't Fire

    Oh, I never thought of that. At the moment the following seems to work but requires two event handlers : procedure TMainForm.MyListViewChange(Sender: TObject); begin MyController.ShowMatch(MyListView.ItemIndex); //Pass the new index to my code for processing. end; procedure TMainForm.MyListViewItemClick(const Sender: TObject; const AItem: TListViewItem); begin MyListView.ItemIndex:=AItem.Index; //Set the item index manually. MyListView.OnChange(Sender); //Call the OnChange handler. end; So OnChange is the same as before (fired for arrow keys, and also click-and-hold) OnItemClick fires for a normal mouse click, sets the ItemIndex itself, then simulates an OnChange call. That combination seems to catch all the various ways an item can be selected. However it's likely OnChange will get called multiple times per selection in some cases (i.e. when Click and Change both fire). There's also a workaround posted in the bug report comments, which looks to achieve the same kind of thing in reverse.
  18. Incus J

    TListView OnChange Event Doesn't Fire

    OK, I've voted! (and added a comment) Now I have to figure out a workaround. OnClick seems to fire, but unfortunately it fires before the new selection comes into effect. So ItemIndex still points to the previous item. I wonder if there is a way to retrieve the new upcoming index value from within the OnClick event handler? Or by the time OnMouseUp fires, ItemIndex might have updated by then? Or maybe in OnClick I could call Application.ProcessMessages followed by a call to the OnChange event handler manually. Could get messy.
  19. I'm trying to compile an FMX project with ICS 8.64 (installed in Delphi 10.4 via the GetIt Package manager) and getting the following error: [dccosx64 Error] Ics.Posix.Messages.pas(57): E1030 Invalid compiler directive: 'MESSAGES' at the following line: {$IFNDEF MSWINDOWS } {$MESSAGES Fatal 'This unit should not be included in a Windows project. Make sure you use Winapi.Messages instead'} {$ENDIF} The program is for macOS and uses ICS HTTP and SSL components. It used to compile and run OK. However it was last compiled some time ago, for macOS 32-bit. I'm now recompiling it for macOS 64-bit, since 32-bit programs no longer run on macOS. I'm wondering if the line above should read {$IFDEF MSWINDOWS} instead of {$IFNDEF MSWINDOWS} - but thought I'd ask before I tinker with it.
  20. Thanks Lars. I had no luck switching thread, but found the routine mentioned in the call stack manually. It is useful that the code gives the thread a label in Debug mode. I've set a Breakpoint prior to the hang so I can step through the code and see what parameters are being passed in. Unfortunately Breakpoints don't seem to be working in this unit. Breakpoints look to be set OK at design time, but become unavailable (X) at runtime, so the program runs past.
  21. I've had a go at stepping through code from my app. It's a bit tricky because the units such as Ics.Fmx.OverbyteIcsWndControl contain no actual code, just an include {$I OverbyteIcsWndControl.pas}, which the Debugger isn't pulling in, so I don't get to see the lines of code I Trace Into or Step Over in the IDE. It is stepping though, because the call stack changes when I press F7, and I occasionally step into the System unit. Shortly before the hang, the call stack looks like this : Ics.Fmx.Overbyteicshttpprot.THttpCli.SetTerminated(bool)(0x0000000203a33170,false) Ics.Fmx.Overbyteicswndcontrol.TIcsWndControl.TIcsWndControl(System.Classes.TComponent*)(0x0000000203a33170,false,0x000000020bd3b640) Ics.Fmx.Overbyteicshttpprot.THttpCli.THttpCli(System.Classes.TComponent*)(0x0000000203a33170,true,0x000000020bd3b640) And the hang occurs after/when the System unit executes : constructor TObject.Create; begin end; Oh, here we go - this looks more useful : :00007FFF6E68AE36 semaphore_wait_trap :00007FFF6E4F0AED _dispatch_sema4_wait :00007FFF6E4F0FBF _dispatch_semaphore_wait_slow System.Syncobjs.TEvent.WaitNoReset(unsigned int)(0x0000000205815ff0,4294967295) System.Syncobjs.TEvent.WaitFor(unsigned int)(0x0000000205815ff0,4294967295) Ics.Posix.Messages.TMultiReadExclusiveWriteSynchronizer.WaitForWriteSignal()(0x0000000105809620) Ics.Posix.Messages.TMultiReadExclusiveWriteSynchronizer.BeginWrite()(0x0000000105809620) Ics.Posix.Messages.TIcsMessagePump.AfterConstruction()(0x000000020beeb1b0) System._AfterConstruction(System.TObject*)(0x000000010bed9a40) System.TObject.TObject()(0x000000010bed9a40,true) Ics.Fmx.Overbyteicswndcontrol.TIcsWndControl.AllocateHWnd()(0x0000000203a33170) Ics.Fmx.Overbyteicshttpprot.THttpCli.THttpCli(System.Classes.TComponent*)(0x0000000203a33170,true,0x000000020bd3b640) So the app hangs at semaphore_wait_trap. Not sure what that is yet, but there is a Thread #7 labelled : TIcsAsyncSocketThread (7) with the following Call Stack kevent Ics.Fmx.Overbyteicswsocket.TIcsEventQueue.HandleEvents() Ics.Fmx.Overbyteicswsocket.TIcsAsyncSocketThread.Execute() System.Classes.ThreadProc(System.Classes.TThread*) System.ThreadWrapper(void*) _pthread_start thread_start Could Thread #1 be waiting for Thread #7 to complete or sync? Other threads do exist (4, 10, 14, 19) but are all unlabelled.
  22. Thank you Lars - I wasn't sure as Trace to Next Source Line just hangs again - so it must never reach a Delphi Source Line to stop at. Which makes sense if it is stuck in an infinite loop somewhere - I guess that means it's getting stuck in the system somewhere outside of Delphi code.
  23. The latest overnight zip looks good. I can get both IcsHttpsTst and also my own app to Build successfully for macOS 64-bit (but not run successfully at present). IcsHttpsTst hangs when it starts up (the main form is never displayed). My own app runs OK, and is functional until it tries to use ICS - at which point it hangs too. Both apps are actually still running, but seem stuck in an infinite loop. If I select Program Pause from the IDE, a CPU tab appears filled with assembly language, showing the current execution point in Thread #1. I can perform commands such as Run Until Return. Thread #1 -> 00007FFF6E68AE36 C3 ret 00007FFF6E68AE37 90 nop 00007FFF6E68AE38 4989CA mov r10, rcx 00007FFF6E68AE3B B825000001 mov eax, 0x1000025 00007FFF6E68AE40 0F05 syscall 00007FFF6E68AE42 C3 ret 00007FFF6E68AE43 90 nop 00007FFF6E68AE44 4989CA mov r10, rcx 00007FFF6E68AE47 B826000001 mov eax, 0x1000026 00007FFF6E68AE4C 0F05 syscall Is there a 'Run Until Inside A Delphi Unit' command somewhere?
  24. I think FMX renders its UI to a surface/canvas, rather than having the OS render the controls (?) - so yes, it could be different. This is where the IcsHttpsTst seems to get stuck at startup: Line 1962 of Ics.Posix.Messages function TMultiReadExclusiveWriteSynchronizer.BeginWrite: Boolean; var Thread: PThreadInfo; HasReadLock: Boolean; ThreadID: Cardinal; Test: Integer; OldRevisionLevel: Cardinal; begin ... ThreadID := GetCurrentThreadID; The top of the call stack looks like this : :000000010001D0F0 System::_DbgExcNotify(int, void*, System::SmallString<(unsigned char)255>*, void*, void*) :000000010001D12E System::NotifyReRaise(System::TObject*, void*) :000000010001D1CA System::_RaiseAtExcept(System::TObject*, void*) :0000000100056AB8 System::Sysutils::ErrorHandler(unsigned char, void*) :0000000100015F30 System::ErrorAt(unsigned char, void*) :000000010001B252 System::_BoundErr() Ics.Posix.Messages.TMultiReadExclusiveWriteSynchronizer.BeginWrite()(0x0000000102521120) Ics.Posix.Messages.TIcsMessagePump.AfterConstruction()(0x000000020245bd80) :0000000100016B45 System::_AfterConstruction(System::TObject*) :0000000100011443 System::TObject::TObject() Ics.Fmx.Overbyteicswndcontrol.TIcsWndControl.AllocateHWnd()(0x0000000203080ff0) Ics.Fmx.Overbyteicshttpprot.THttpCli.THttpCli(System.Classes.TComponent*)(0x0000000203080ff0,true,0x000000020801e5f0) ... Maybe that contains useful information. On Posix, the System unit defines: TThreadID = NativeUInt; But local var ThreadID is Cardinal. Maybe Cardinal and NativeUInt are not compatible. If I redefine ThreadID as a NativeUInt too, then the ERangeError disappears, and the app is "[Running]" - but the UI does not appear. I think Thread #1 might be waiting for something.
×