How to disable TAction.Shortcut or TMenuItem.Shortcut? - delphi

I'm developing a Word addin, and somehow the shortcuts defined in TAction.ShortCut are always trigged more than one time, and this is tricky to me and hard to solve, so I resort to TForm.OnKeyDown event and cleared all TAction.ShortCut properties, this approach works well, except that the shortcuts are not shown on the corresponding menu items, but I want them to be displayed on those menu items.
So I come up this idea: Set values for TMenuItem.Shortcut so that the program can show the shortcut hint to the end user, and does not allow VCL to handle these shortcuts, instead, handle them in TForm.OnKeyDown. So my question is how to disable TAction.Shortcut or TMenuItem.Shortcut? Thank you in advance.

For a start, you have an Enabled property on both TAction and TMenuItem. Just set it to False.
Next, one of the possible causes of your event being triggered more than once is that you may be using Application.ProcessMessages; or at least a badly written component that you're using is doing so. One should be very wary of using that Delphi feature because it can cause 're-entrant' code (unintentional recursion).

The root cause of your problem is the events being triggered more than one time. You could try to workaround this problem offcourse but I would suggest to:
Place a breakpoint in your eventhandler.
Copy the Call Stack's content [CTRL+ALT+S] to whatever editor you like for every time you hit the breakpoint.
Start brainstorming as to why the calls lead to hitting the event multiple times.
Fix your code if it is your code to fix.

Hacker way (usually not recommended):
copy unit that contain TAction in separate folder, modify source of TAction that makes ShortCut method do nothing. Put this folder to search path as first item.
rebuild your app.
I use this technique to fix bugs in VCL, but after installing Delphi patches you should not forget to update 'hacked' version of modified units.

Related

How can I make the 'Showmessage' dialog wider so it fits the text?

I'm showing where a file has been saved by using 'Showmessage' (in Win 7).
When the file path is long it gets truncated and elipsis get inserted.
eg
the path
C:\Users\Admin\Documents\SubFolderOne\AnotherSubFolder\MyFile.csv
gets displayed as
C:\Users\Admin\Documents\SubFolderOne\Ano...\MyFile.csv
Is there a way to make the message box wider and show all of the filename and path?
I have read this
http://zarko-gajic.iz.hr/displaying-long-non-breakable-text-file-path-in-messagedlg-truncationellipsis-issues/
which explains some of the reasoning and gives a rather unsatisfactory method for a TTaskDialog and I also I realise I could make my own form to act in the same way as Showmessage but I am wondering if there is a simpler solution using just Showmessage.
Is a simpler solution using just ShowMessage?
No there is not.
I can think of three obvious approaches, although doubtless there are more.
Create your own dialog
There's nothing particularly magical about a dialog. You can perfectly well create them yourself, and so have complete control over their appearance. The downside of course is that it can be hard to match the native platform appearance. Especially when you consider all the different Windows versions that you are typically expected to support.
Use CreateMessageDialog and customise this Delphi form
You can call the RTL function CreateMessageDialog to obtain a Delphi form that can be used to display your message dialog. You then have the opportunity to customize this dialog in any way you please.
Use the task dialog API
The task dialog API, introduced in Vista, affords control of the dialog width. Call TaskDialogIndirect, and specify a non-zero value for cxWidth.
Before ShowMessage put:
UseLatestCommonDialogs:= false;
I use Delphi 10.2 and it works.

Tab order in a console app with a single VCL form

I have a Windows console app created with Embarcadero XE 6 (in fact converted from a Borland C++Builder5 project). It has a single form with a few buttons and edit controls. All these controls have set TabStop=True and appropriate TabOrder's. However, pressing Tab in runtime when the form is shown does not do anything (it just produces a sound when a cursor/focus is in an Edit control and does nothing when a button is focused).
I have read in docs that Tab order would not work unless the Parent of the form is set. However, this is the only VCL form (the other windows are the console and the GLUT window), so there is no VCL parent AFAIK. I tried to set
Parent=Application->MainForm;
in the Form's constructor, but the Application->MainForm is also NULL. Any ideas?
Your problem is that you don't have a message loop. This is because console applications are not expected to have windows and do not come with message loops by default.
You can run a message loop by calling:
Application->Run();
However this will probably stop the console part of your application from working properly. How can your main thread service the console synchronously and the asynchronous GUI message loop at the same time?
I suspect you will need to have a more serious re-think of your application design.
Regarding your update, it seems that you do have a message loop, but it is the message loop for the GLUT framework. The VCL framework requires its message loop to handle dialog messages like TAB key presses.
It's plausible that running the VCL message loop in place of the GLUT message loop would give better results. But it's quite likely that would just break the GLUT part of the app.
Trying to run two incompatible GUI frameworks out of a single message loop is hard to get right. There's probably no quick fix here. You'll need to dig deeper. Perhaps it would be best to give up on the VCL and stick to the one GUI framework.

TObjectList.Clear access violation

I'm running into a very weird problem with a large application. I make heavy use of TObjectList storing a custom object on them. On large lists im experiencing weird crashes with "Access violation at address.. read of address.. " "privileged instruction" and others, when I use the CLEAR method. I've tracked this to happen exactly when attempting to delete the last item in the list. I've checked this by logging the contained objects deletion from their destroy proc, and also trying to deleting them on my own (for a := olist.count-1 downto 0 do.. debugmsg('deleting '+inttostr(a)).. olist.delete(a) ), both ways I get the access violation right when deleting the LAST remaining item in the list.
This doesnt happen always, cause I use clear in other areas, and also a few different (smaller) lists, but at a very specific point in my app this happens.
I've no clue what might be wrong, there's nothing trying to access the list during the clear, and the cointained objects do not have access to their parent objectlist, there has to be something screwing up in the TObjectList.delete/clear methods when it comes to clearing the last item.
Any suggestions? Using Delphi XE.
That sounds to me like you're freeing objects that have already been freed. To track this down, download the full version of FastMM, add FullDebugMode to the Conditional Defines line under Project Options->Delphi Compiler and the Map File option under Linking set to Detailed, and rebuild. (Build, not Compile.) Then copy the FullDebugMode DLL to the same folder as your EXE and run it. It'll watch your memory as you allocate and free and when you try to free the same object for a second time, it'll catch that and give you some very detailed debug data as to where the problem is coming from.
Are you sure the last object is valid and not already deleted? It could be in the list twice e.g. due to other bugs.

Is there a way to disable the hint for a TOpenDialog in delphi?

I have a TOpenDialog component I am creating on runtime and I want to disable the hint that pops up over files when it is used. I have not written any exrta code for this than creating the object, executing the object and extracting the filename,, then freeing the instance.
Can I do what I want to do? If so, how do I do this?
I googled for "opendialog crash tooltip" and the first hit gave me this. The solution for their problem (and probably yours) is this:
[...]
You only need to add this modification to the first form of your application:
uses ActiveX;
initialization
OleInitialize(nil);
finalization
OleUninitialize
end.
Since this is a Windows common dialog, you may have to jump in and hook into the dialogproc and manually try and process the tooltip messages. You can look here for a start about how to customize the common dialogs; http://msdn.microsoft.com/en-us/library/ms646951.aspx. You can also look at creating your own TOpenDialog descendant and override the WndProc protected method to get access to the dialog messages and notifications. I suspect you'd also need to do some deeper hooking and start getting into dealing with the explorer shell. The file list in that dialog is actually an instance of parts of the Windows Explorer shell.
Another question is what is it you're trying to accomplish by hiding this information from the user? Maybe there is some other solution to what you're trying to do rather than disabling some intrinsic functionality?

How do I make a TLinkLabel work in Delphi?

I put a TLinkLabel on my form, filled it in with a caption including a valid HTML link, and got some nice blue underlined text. When I ran the program, I expected it to invoke Firefox (my default browser) and open the link automatically. Apparently that's not the case.
The helpfile says I have to code this in an OnLinkClick event handler. It doesn't say anything about how to do that, though. It'll pass in a string value called "Link". How do I say "invoke the default browser and have it open Link"?
You can call ShellExecute.
I wrote this method for generic calls, and should works in your case.
procedure ShellOpen(const Url: string; const Params: string = '');
begin
ShellAPI.ShellExecute(0, 'Open', PChar(Url), PChar(Params), nil, SW_SHOWNORMAL);
end;
In your code you should call this
procedure TForm1.LinkLabelClick(Sender: TObject);
begin
ShellOpen(LinkLabel.Caption);
end;
I have all sorts of problems with TLinkLabel that ships with delphi 2010.
a) The control does not render as a hyperlink but as a simple label text on the form. b) the cursor does not change to point out this is a link even though I set the Cursor property. c) the OnLinkClick event does not fire at all.
I am working on windows 7.
So, as far as I am concerned, TLinkLabel does nothing as it should and is useless. ShellExecute is the only solution and must be placed in the OnClick event.
TLinkLabel provides a label that looks like a link. It's your job as the programmer to make it act like a link because only you can know what links are supposed to act like in your program. You wanted the label to automatically open the user's default Web browser using the URL in the label, but that's not the only thing links do. For example:
Internet Explorer is not my default browser, but when I click a link in Internet Explorer, I do not expect the linked page to open in Firefox.
When I click a link in the help program, I expect the linked topic to appear in the help program, not in any Web browser at all.
The preference pages in Eclipse are very complicated. Settings on one page are sometimes related to settings on another page. There are links on those pages that take the user directly to the related page. There is no URL and no HTML involved in this case, and yet they're still labels with underlined text.
Some programs try to offer a choice between opening links in new windows versus re-using old windows. You can't implement that feature without knowing which browser is in use. Your program might offer the user a choice to ignore the default browser setting and always use a specific one. To do that, your UI control can't make too many assumptions about what the program is supposed to do.
I'm guessing you're referring to a TLinkLabel control that comes with Delphi. (My versions don't have such a component.) I imagine that the Delphi control is meant to mimic the one in the .Net class library. It can hold multiple links, and each link can do something different.
If you want a control that always does the shell's default action for URLs, then consider using a different TLinkLabel; the one by Alexander Bach does exactly what you expected. It's from Delphi 3, but it should work unmodified in all later versions as well, including Delphi 2009. If you look at the code, you'll see how it works. It simply calls ShellExecute, as Cesar's answer demonstrates.
LOL, it's funny. So instead of setting crHandPoint as cursor, colored and underlined font and filling the OnClick event to standard TLabel we have component that knows link tag and which at all I need to supply with same On(Link)Click event :))
Only thing it is good for is that it makes easier to embed link into some text and that it is using system style of link...
p.s.: really you have to put Some text with link into the Caption and setup OnLinkClick to that ShellExecute...
I use a control called TInternetLabel instead. It does exactly what you want: on click it opens the browser so you don't have to put code in the OnClick event.
I tried this solution but it still gave problems in Delphi XE4, probably becasue ShellOpen does not understand the HTML-code in the Caption.
What worked for me was a combination of Cesar Romero (the basic code), Adam Feistner (The HTML-code in the Caption) and an older solution:
Put the URL in the HINT field.
Change the line: ShellOpen(LinkLabel.Caption);
to
ShellOpen(LinkLabel.Hint);
This worked for me.

Resources