-
Content Count
116 -
Joined
-
Last visited
Community Reputation
37 ExcellentRecent Profile Visitors
-
If you want more control, I really recommend going with owner-draw / custom-draw menus instead of relying on workarounds like Screen.MenuFont. With TMainMenu you can enable OwnerDraw and then handle the OnDrawItem and OnMeasureItem events. That way you can set your own font size, text alignment, and also calculate the correct item width so that no text gets cut off. This approach avoids the side effects you’re seeing and gives you full flexibility to style your menus exactly how you want.
-
udp discovery Delphi Super Fast LAN tethering in IPv4 network using Indy UDP AutoDiscovery IP
bravesofts replied to bravesofts's topic in I made this
thanks & huge respect to you Mr Remy. -
udp discovery Delphi Super Fast LAN tethering in IPv4 network using Indy UDP AutoDiscovery IP
bravesofts replied to bravesofts's topic in I made this
i really appreciate your reply with remarks & ideas & improvements (IPv6, subnet broadcast, reply-to-sender-port support, multiple NIC handling). etc ... ---------- my goal is : Super Fast LAN tethering in IPv4 network Automatic Discovery but i have a View & a Design Philosophy here: My view: Optimize for speed, simplicity, and control in one specific business scenario. Extra UDP server on client side = intentional handshake/security measure. “It works everywhere I tested, so good enough.” Your view: Optimize for protocol correctness, portability, and edge cases. Avoid assumptions about broadcast, NAT, routers, IPv4-only, etc. Make the protocol generic and reusable in any network environment. My Design Philosophy: - Server Side: - Creates a UDP listener on a fixed port (3434 by default). - Waits for broadcast requests with a specific keyword ("Discovery|Hello..."). - Responds to the client only if that client has a UDP server listening on another pre-defined port (our “secret port”). - The reply goes to that listening port, not back to the sender’s ephemeral port. - Client Side (VCL / FMX): - Uses a UDP server to listen for ServerApp replies on our pre-defined “secret port”. - Uses a UDP client socket to broadcast a discovery request Help. - The server is forced to reply on our pre-defined “secret port”, and will only reply if the client has a listening UDP server on the agreed-upon port → this is our security + filtering mechanism here. - After receiving the reply, the client knows the TCP server IP/port and can connect quickly. Why it feels “super fast”: - You don’t waste time scanning subnets. - You don’t query all adapters manually. You just blast 255.255.255.255:3434 and whoever is alive responds. - The “secret UDP server port” acts as handshake validation, so random broadcasts don’t get replies. - No retries, no handshakes, no multi-round protocols, no user help at all → just one broadcast, one reply. ✅ Conclusion: My approach is fast, pragmatic, secure, and business-oriented. Remy’s advice is about protocol correctness, portability, and avoiding future bugs. -
udp discovery Delphi Super Fast LAN tethering in IPv4 network using Indy UDP AutoDiscovery IP
bravesofts posted a topic in I made this
A simple, cross-platform demo (VCL + FMX) showing how to Super Fast LAN tethering in IPv4 network Automatically discover a server on the same LAN using UDP Broadcast with Indy components. 📌 Overview This project demonstrates a lightweight, zero-configuration **auto-discovery mechanism**: - The **Server** listens on a known UDP port (`3434`) for broadcast packets. - A **Client** (VCL or FMX/Android) sends a broadcast message (`Discovery|Hello...`) on port `3434`. - The **Server replies** directly to the client (on port `22049`) with its LAN IP address. - The **Client receives the reply**, extracts the server’s IP, and can then connect via TCP or continue communication. This makes it possible to build applications that can **find each other on the same LAN instantly** without manual IP setup. 🏗 Components Used - Indy UDP Components - TIdUDPServer. - TIdUDPClient. 2. - Cross-platform IP detection - Windows: `GetAdaptersAddresses` API - Android: `Java.Net.NetworkInterface` enumeration 3. - Thread-safe logging via `TThread.Queue`. 4. - Timer to control discovery message sending Loop All details has been added in my Github Repo here. Mit Licence: Please feel free to fork and improve & use it on your projects... Any remarks or suggestions are very wellcome here. -- thank you All. -
promise Introducing My Delphi TFuture PPL For Thread Safe UI
bravesofts replied to bravesofts's topic in I made this
Thank you very much my friends.. especially my dear Dalija -
promise Introducing My Delphi TFuture PPL For Thread Safe UI
bravesofts replied to bravesofts's topic in I made this
💬 Is Future an accurate name? From a theoretical computer science and functional programming perspective, yes — the term Future (or Promise) has a well-established meaning: A Future<T> represents a value that will be available at some point in the future. But in my critique is fair in the Delphi-specific context, because Delphi’s TFuture<T> is not particularly “intelligent” in how it informs you when the value is ready. Instead, it expects you to pull (.Value) or manually monitor its .Status. Delphi’s TFuture<T> is more like a deferred computation container than a true reactive future like in JavaScript (Promise), Java (CompletableFuture) 🧠 Final Thought If Delphi’s TFuture<T> had a callback or allowed chaining with .OnComplete(...), then the name “Future” would feel more earned. As it stands: 🔹 It’s a Future — but you must chase it. 🔸 It holds a value — but it won’t tell you when. The Accurate name for it in my opinion is this "HalfPromise" Fits Perfectly. It promises a result... eventually. But it doesn't promise to tell you when it's ready. No OnComplete, no Then, no observer pattern — you're left guessing or blocking. So it's not a full Promise, just... half of one. what you think friends ? -
promise Introducing My Delphi TFuture PPL For Thread Safe UI
bravesofts replied to bravesofts's topic in I made this
but how "my some code" that is between knows exactlly how to continue while future still not ready, inorder to avoid app touching in bad time the LFuture.Value // use future value there is no callback in tfuture to use unless monitoring her status with while loop which also freeze the app -
promise Introducing My Delphi TFuture PPL For Thread Safe UI
bravesofts replied to bravesofts's topic in I made this
could you please introduce real work scenario where Future blocking call is usefull. -
promise Introducing My Delphi TFuture PPL For Thread Safe UI
bravesofts posted a topic in I made this
Delphi Async Helpers with TFuture<T>: This demo project provides a clean and safe way to perform background operations in Delphi using TTask and TFuture<T>, with a focus on keeping the UI responsive and preventing memory leaks. 📦 What's Inside API.Helpers.pas: A generic async helper unit Main.View.pas: A VCL form demonstrating good and bad usage of futures and background tasks. 🔧 Helper Static Class: TSimpleFuture<T> A simple abstraction over TTask.Future<T> and TTask.Run to make async coding easier. type TConstProc<T> = reference to procedure (const Arg1: T); TSimpleFuture<T> = class class procedure Run(const aQuery: TFunc<T>; const aReply: TConstProc<T>); static; class procedure RunFuture(const aQuery: TFunc<T>; const aReply: TConstProc<T>); static; end; 🖼 Demo Form: `Main.View.pas` The form includes buttons that demonstrate the following patterns: ✅ Correct Usage (Non-Blocking): `💪 BtnStartWithHelper`: TSimpleFuture<string>.RunFuture(function: string begin Sleep(2000); Result := TimeToStr(Now) + ' ✅ تم التنفيذ'; end, LogReply); > ✅ Background-safe > ✅ Memory-safe > ✅ Beginner-friendly ⚠️ Incorrect Usage (`BtnWrongUse`): var LFuture := TTask.Future<string>(...); LogReply(LFuture.Value); // ❌ Blocks the main thread! > ❌ This freezes the UI and defeats the purpose of async programming. ✅ Safe Manual Usage(`BtnWaitOutsideMainThread`): LFuture := TTask.Future<Integer>(...); TTask.Run( procedure begin var LValue := LFuture.Value; // Block or wait inside background thread. TThread.Queue(nil, procedure begin LogReply('Result: ' + LValue.ToString); // update UI on main thread LFuture := nil; // release `IFuture<T>` reference to avoid Memory Leak (TCompleteEventWrapper etc of internal thread pool that service the TTask). end); end); > ✅ Keeps UI free. > ✅ Releases `LFuture` to prevent leaks. 🧪 Simulating `IFuture<T>` with `ITask`(`BtnSimulateIFuture`): var LResult: string; LFuture := TTask.Run(...); TTask.Run(procedure begin LFuture.Wait; // Call wait inside background thread like IFuture<T>.Value does .. TThread.Queue(nil, procedure begin LogReply(LResult); LFuture := nil; // release `IFuture<T>` reference to avoid Memory Leak (TCompleteEventWrapper etc of internal thread pool that service the TTask). end); end); > 🧠 A useful trick for simulating `Future.Value` behavior without using `TFuture<T>`. 🔁 Future Monitoring Pattern(`BtnMonitorSolution`): A more advanced way to ensure task completion: var LFuture := TTask.Future<string>(...); TTask.Run(procedure begin while not (LFuture.Status in [TTaskStatus.Completed, TTaskStatus.Canceled, TTaskStatus.Exception]) do TThread.Sleep(100); // Reduce CPU Usage ..(Check every 100 Millisec). TThread.Queue(nil, procedure begin if LFuture.Status = TTaskStatus.Completed then LogReply(LFuture.Value) else LogReply('Future Failled or Canceled !!'); LFuture := nil; // release `IFuture<T>` reference to avoid Memory Leak (TCompleteEventWrapper etc of internal thread pool that service the TTask). end); end); 🧼 Best Practices (in my opinion now): ✅ Do : - Use `TThread.Queue` to update UI - Use `TFuture.Value` **only from background threads** - Set `LFuture := nil` to release memory ❌ Don’t : - Call `.Value` on the main thread. - Forget to release `IFuture<T>` reference to avoid Memory Leak (TCompleteEventWrapper etc of internal thread pool that service the TTask). - Update UI directly from background threads. 🧰 Requirements: - Delphi XE7+ - VCL application (not mandatory, but my Demo is VCL) - `System.Threading` unit. 📜 License Free to use and modify in any personal or commercial project. 🧠 Design Philosophy: What Future Really Means In general software design, a Future is an abstraction that represents a promise of a result to be available in the future. It is not intended to be synchronously accessed using .Value, especially not from the main thread. ❌ Misconception: Using .Value Is Asynchronous The Future is not designed for synchronous use — instead, it should be part of a fully asynchronous programming style, ideally involving a callback mechanism. Calling .Value is essentially a blocking call, which defeats the purpose of using Future in the first place. ✅ The Core Idea Behind Future The essence of the Future abstraction is: 🔹 A promise for a future result without blocking the current thread, preferably using a callback to handle the result when it’s ready. So using .Value is almost equivalent to Task.Wait — not a true asynchronous pattern ⚠️ Using .Value on the Main Thread Is Misleading! One of the most common pitfalls developers face with IFuture<T> in Delphi is the assumption that it is meant to be accessed using .Value. In reality, this goes against the very design philosophy of Future in most programming languages. In Delphi, calling .Value internally does something like this: function TFuture<T>.GetValue: T; begin Wait; // ⛔ This blocks the current thread! Result := FResult; end; So, it's not just about when the computation starts — it’s about how you consume the result in a way that doesn't harm the user experience. 🔄 Summary .Value = Blocking = like Wait Future's goal = Non-blocking promise, best used with callbacks Using .Value in UI = ❌ Breaks the async model, risks freezing UI Best practice = Use background thread + TThread.Queue for result delivery ## 🙌 Contributions Feel free to open an issue or PR if you want to extend this helper for things like: - Cancellation - Progress reporting - `Future.ContinueWith(...)` chaining. 🔧 if you find any Remarks or Suggestions , please Notify me bellow. Thank you for your Time my Friends. My Ready to use Github Repo here. -
future day TDateTime Extension for Day Name Lookup with Offset and Locale
bravesofts posted a topic in I made this
unit API.DateUtils; interface uses System.SysUtils, System.DateUtils; type TDateTimeHelper = record helper for TDateTime // Get the future day or the past day in same-function.. function DayOfWeek(const aDaysCount: Integer; aLocaleName: string = ''): string; end; implementation function TDateTimeHelper.DayOfWeek(const aDaysCount: Integer; aLocaleName: string): string; //const // cDaysSysUtils : array[1..7] of string =( // 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' // ); // cDaysDateUtils : array[1..7] of string =( // 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' // ); var LDisplayFormat: TFormatSettings; LTargetDate: TDateTime; begin if aLocaleName <> '' then LDisplayFormat := TFormatSettings.Create(aLocaleName) else LDisplayFormat := TFormatSettings.Create; // default OS locale LTargetDate := IncDay(Self, aDaysCount); // Result := cDaysSysUtils[System.SysUtils.DayOfWeek(LTargetDate)]; // Result := cDaysDateUtils[System.DateUtils.DayOfTheWeek(LTargetDate)]; Result := FormatDateTime('dddd', LTargetDate, LDisplayFormat); end; end. then use it like this: procedure TMainView.BtnTestClick(Sender: TObject); begin ShowMessage('In 200 days, it will be: ' + Today.DayOfWeek(200, 'ar-DZ')); ShowMessage('200 days ago, it was: ' + Today.DayOfWeek(-200, 'ar-DZ')); end; Helper for TDateTime to get the name of the day (e.g., Monday, Tuesday) based on a given day offset. It supports both future and past dates by adding or subtracting a number of days. The helper function returns the localized name of the day of the week for the current date, adjusted by aDaysCount. If aLocaleName is provided, it uses that locale; otherwise, the default operating system locale is used. -
tmainmenu identify whether a TMenuItem is a top-level menu bar item
bravesofts replied to bravesofts's topic in VCL
Thanks, but I actually did try that earlier — checking if TMenuItem.Parent = nil. Unfortunately, in my specific case, it didn’t give the expected result. Even top-level menu items were affected, possibly due to the way OwnerDraw, when my MainMenu is hosted by TToolbar. I also checked the documentation, and while Parent should be nil for main menu items, it didn’t behave consistently in my setup. That’s why I started exploring alternatives like checking the Windows hSubMenu via MENUITEMINFO. Appreciate the suggestion though — it’s good in theory, just didn’t work reliably in my case.- 12 replies
-
tmainmenu identify whether a TMenuItem is a top-level menu bar item
bravesofts replied to bravesofts's topic in VCL
Thanks, that worked correctly! However, I'm still not knowing the native way to distinguish between true menu bar items (top-level items in the TMainMenu) and internal submenu items !- 12 replies
-
tmainmenu identify whether a TMenuItem is a top-level menu bar item
bravesofts replied to bravesofts's topic in VCL
procedure TdmUI.FixMenuCaptions(aMenu: TMainMenu); var I, K: Integer; procedure FixItem(aItem: TMenuItem); var J: Integer; begin if (Pos('&', aItem.Caption) = 0) and (not aItem.IsLine) then // and // (not IsMenuBarItem(aMenu, aItem)) then //or (aItem.Count > 0) or (aItem.Tag <> 2) aItem.Caption := '&' + aItem.Caption; // Add & if missing for J := 0 to aItem.Count - 1 do FixItem(aItem.Items[J]); end; begin for I := 0 to aMenu.Items.Count - 1 do for k := 0 to aMenu.items[I].Count -1 do FixItem(aMenu.Items[I]); end; I tried that approach, but it still adds the & to top-level menu bar items as well — so the issue remains. Even with separate loops or skipping directly in the main loop, the FixItem() call still affects them unless I explicitly check whether the item is a menu bar item.- 12 replies
-
tmainmenu identify whether a TMenuItem is a top-level menu bar item
bravesofts replied to bravesofts's topic in VCL
I know about using the Tag property, but I'm aiming to write a clean, universal solution or design pattern that works reliably with any dropped TMainMenu, without relying on manual tagging or special-case logic. I want something that auto-detects whether a TMenuItem is a menu bar item based purely on its structure, so it can be reused across different forms and menus with minimal setup.- 12 replies
-
tmainmenu identify whether a TMenuItem is a top-level menu bar item
bravesofts posted a topic in VCL
In Delphi VCL, I'm trying to identify whether a TMenuItem is a top-level menu bar item (a MenuBarItem) as opposed to a regular submenu item. I'm currently using this check: if aItem.Count > 0 then But this returns True for both top-level menu items (e.g., "File", "Edit" in the main menu bar) and submenu items that have their own children (like "Recent Files" under "File"). Is there a more reliable way—perhaps using TMenuItem properties or GetMenuItemInfo from the Windows API—to distinguish true menu bar items from submenu items with children? i'm using this: function IsMenuBarItem(aMenu: TMainMenu; aItem: TMenuItem): Boolean; var LInfo: MENUITEMINFOW; LHMenu: HMenu; I: Integer; begin Result := False; LHMenu := aMenu.Handle; ZeroMemory(@LInfo, SizeOf(LInfo)); LInfo.cbSize := SizeOf(LInfo); LInfo.fMask := MIIM_SUBMENU; for I := 0 to GetMenuItemCount(LHMenu) - 1 do begin if GetMenuItemInfoW(LHMenu, I, True, LInfo) then begin if LInfo.hSubMenu = aItem.Handle then begin Result := True; Exit; end; end; end; end; is possible to avoid iterating all items in the main menu if i trying to determine whether a given TMenuItem is a menu bar item, using only information from the TMenuItem itself ! --- 🧩 Context: The reason I'm doing this is to work around the automatic access key (Alt + key) assignment that Windows applies when menu items don't have an & in their caption. Even after setting: TMainMenu.AutoHotkeys := maManual; the issue persisted. I'm working in a Right-to-Left (BiDiMode) environment with OwnerDraw := True, and the system still assigns hotkeys unless the & is explicitly added to the menu captions. 👉Hint: the TMainMenu is hosted by TToolBar and not the Form ! -- 🛠️ MySolution: Add "&" to Non-MenuBar Items Here's the utility I use to ensure all non-menu bar items have an & prefix: procedure TdmUI.FixMenuCaptions(aMenu: TMainMenu); var I: Integer; procedure FixItem(aItem: TMenuItem); var J: Integer; begin if (Pos('&', aItem.Caption) = 0) and (not aItem.IsLine) and (not IsMenuBarItem(aMenu, aItem)) then //or (aItem.Count > 0) or (aItem.Tag <> 2) aItem.Caption := '&' + aItem.Caption; // Add & if missing for J := 0 to aItem.Count - 1 do FixItem(aItem.Items[J]); end; begin for I := 0 to aMenu.Items.Count - 1 do FixItem(aMenu.Items[I]); end; This approach above ensures that only submenu items get the &, preserving the expected behavior on the menu bar, especially in right-to-left and owner-drawn setups.- 12 replies