Left - dialog of Win7 of modern apps
Right - dialog of Win7 of my Delphi7 app
How to make my dlg modern? (How to patch Delphi7)
The offending part for the new dialog to be shown, for Windows 7 and later, is the callback. Here's a quote from "Font Dialog Box":
If you enable a hook procedure without creating a custom template, the
default ChooseFont template for earlier Windows versions will be
loaded.
You can eliminate the hook procedure by modifying a copy of "dialogs.pas" and putting it in your source folder for the current project.
function TFontDialog.Execute: Boolean;
...
// Flags := Devices[FDevice] or (CF_INITTOLOGFONTSTRUCT or CF_ENABLEHOOK);
Flags := Devices[FDevice] or CF_INITTOLOGFONTSTRUCT;
...
// hWndOwner := Application.Handle;
hWndOwner := GetActiveWindow;
...
The latter modification is for displaying the dialog in a reasonable place. Once the hook procedure is disabled, the VCL will not be able to center the dialog. You will also lose "Apply" button functionality and other events (OnShow/Close).
Related
Create a new VCL Forms application
On the main form add a Tbutton and a TSaveDialog
Set "ofOverwritePrompt" to True in properties for the SaveDialog1
Use:
procedure TForm1.Button1Click(Sender: TObject);
begin
SaveDialog1.Execute();
end;
Run the app. Press the button to execute the save dialog. Try to save to a file that already exists.
A message box appears if you want to replace the file. Press cancel. All fine so far. Close the app.
Go to Project/Options/Application/Appearance and select a Custom style (e.g. Amakrits). Set Amakrits as the default style.
Run the app as in #5 above. Only a small bit of the message box will be shown. You will have to press Enter to be able to continue.
(Using a TFileSaveDialog will give the same result)
If I compile and run the app using Delphi XE8 it will be ok since the save dialog window seems to use the default windows style even if another style is chosen.
Edit:
I have Windows 10 pro. Source compiled as win32 with Delphi 10.1 Berlin.
The replace message box is partly hidden. Only a small top left part is shown, see figure.
And here it is compiled with XE8 win32:
Ps. I am using the default 100% scale factor.
Compiling with win64 (Delphi 10.1 Berlin) seems to be ok:
So, compiling to win32 does not work for me, but 64-bit will. Any clues?
Edit: Trying with "GetSaveFileName(OFN)" will also not work for me in win32 (win 64 is ok):
You can avoid this issue using the dialog styling code of the VCL Styles Utils project.
Just Add these units to your project.
uses
Vcl.Styles.Utils.Menus, //Popup and Shell Menus (class #32768)
Vcl.Styles.Utils.Forms, //dialogs box (class #32770)
Vcl.Styles.Utils.StdCtrls, //buttons, static, and so on
Vcl.Styles.Utils.ComCtrls, //SysTreeView32, SysListView32
Vcl.Styles.Utils.ScreenTips, //tooltips_class32 class
Vcl.Styles.Utils.SysControls,
Vcl.Styles.Utils.SysStyleHook;
{$R *.dfm}
procedure TForm26.Button1Click(Sender: TObject);
begin
UseLatestCommonDialogs := false;
SaveDialog1.Execute();
end;
I cannot confirm the problem, and all looks well here, (32 bit executalbe, themed with Amakrits, compiled with 10.1 Berlin, on Windows 7, 100% scaling) but you could try this:
uses ... Winapi.CommDlg;
...
var
OFN: TOpenFileName;
begin
FillChar(OFN, SizeOf(OFN), 0);
OFN.lStructSize := SizeOf(OFN);
OFN.nMaxFile := MAX_PATH;
OFN.Flags := OFN_OVERWRITEPROMPT or OFN_HIDEREADONLY or OFN_ENABLESIZING or OFN_EXPLORER;
GetSaveFileName(OFN);
end;
The result is an Amakrits-themed, new Explorer-like save dialog, which works fine (for me). Only the two round, blue "back" and "forth" (<- and ->) buttons at the top left of the dialog look a little weird.
But I did not try this with custom scaling settings (e.g. Medium 125% in the Control Panel -> Display panel, etc.). I think this could influence such things.
Update
I just tried to use SaveDialog1 (commenting out the OFN code above) with custom Display scaling (125%). All looked fine, so that is not it. Also when I use the OFN code, all looks fine (actually, better, i.e. no XP style dialog, but a real Explorer-like dialog instead).
If I set "Enable High-DPI" to true in Project/Options/Application it will work (replace box properly displayed). Disabling it will cause the problem (both in win32 and win64).
For the record, I had exactly the same problem (Delphi 10.1 Berlin, compiling on Windows 10 64 bit, 100% screen settings, compiled for 32 bit target). Enabling or disabling High-DPMI awareness didn't help.
A workaround is to disable styles for dialog boxes before executing the TSaveDialog (or TOpenDialog) like this:
TStyleManager.SystemHooks := TStyleManager.SystemHooks - [shDialogs];
The file dialog itself will still be themed. You will get standard Windows-style message boxes in case an overwrite prompt (or create prompt) pops up, but they will be large enough for the user to read and click them. After the file dialog has finished, you can enable styled dialogs again by re-adding shDialogs to SystemHooks if needed.
Create a new VCL Forms application
On the main form add a Tbutton and a TSaveDialog
Set "ofOverwritePrompt" to True in properties for the SaveDialog1
Use:
procedure TForm1.Button1Click(Sender: TObject);
begin
SaveDialog1.Execute();
end;
Run the app. Press the button to execute the save dialog. Try to save to a file that already exists.
A message box appears if you want to replace the file. Press cancel. All fine so far. Close the app.
Go to Project/Options/Application/Appearance and select a Custom style (e.g. Amakrits). Set Amakrits as the default style.
Run the app as in #5 above. Only a small bit of the message box will be shown. You will have to press Enter to be able to continue.
(Using a TFileSaveDialog will give the same result)
If I compile and run the app using Delphi XE8 it will be ok since the save dialog window seems to use the default windows style even if another style is chosen.
Edit:
I have Windows 10 pro. Source compiled as win32 with Delphi 10.1 Berlin.
The replace message box is partly hidden. Only a small top left part is shown, see figure.
And here it is compiled with XE8 win32:
Ps. I am using the default 100% scale factor.
Compiling with win64 (Delphi 10.1 Berlin) seems to be ok:
So, compiling to win32 does not work for me, but 64-bit will. Any clues?
Edit: Trying with "GetSaveFileName(OFN)" will also not work for me in win32 (win 64 is ok):
You can avoid this issue using the dialog styling code of the VCL Styles Utils project.
Just Add these units to your project.
uses
Vcl.Styles.Utils.Menus, //Popup and Shell Menus (class #32768)
Vcl.Styles.Utils.Forms, //dialogs box (class #32770)
Vcl.Styles.Utils.StdCtrls, //buttons, static, and so on
Vcl.Styles.Utils.ComCtrls, //SysTreeView32, SysListView32
Vcl.Styles.Utils.ScreenTips, //tooltips_class32 class
Vcl.Styles.Utils.SysControls,
Vcl.Styles.Utils.SysStyleHook;
{$R *.dfm}
procedure TForm26.Button1Click(Sender: TObject);
begin
UseLatestCommonDialogs := false;
SaveDialog1.Execute();
end;
I cannot confirm the problem, and all looks well here, (32 bit executalbe, themed with Amakrits, compiled with 10.1 Berlin, on Windows 7, 100% scaling) but you could try this:
uses ... Winapi.CommDlg;
...
var
OFN: TOpenFileName;
begin
FillChar(OFN, SizeOf(OFN), 0);
OFN.lStructSize := SizeOf(OFN);
OFN.nMaxFile := MAX_PATH;
OFN.Flags := OFN_OVERWRITEPROMPT or OFN_HIDEREADONLY or OFN_ENABLESIZING or OFN_EXPLORER;
GetSaveFileName(OFN);
end;
The result is an Amakrits-themed, new Explorer-like save dialog, which works fine (for me). Only the two round, blue "back" and "forth" (<- and ->) buttons at the top left of the dialog look a little weird.
But I did not try this with custom scaling settings (e.g. Medium 125% in the Control Panel -> Display panel, etc.). I think this could influence such things.
Update
I just tried to use SaveDialog1 (commenting out the OFN code above) with custom Display scaling (125%). All looked fine, so that is not it. Also when I use the OFN code, all looks fine (actually, better, i.e. no XP style dialog, but a real Explorer-like dialog instead).
If I set "Enable High-DPI" to true in Project/Options/Application it will work (replace box properly displayed). Disabling it will cause the problem (both in win32 and win64).
For the record, I had exactly the same problem (Delphi 10.1 Berlin, compiling on Windows 10 64 bit, 100% screen settings, compiled for 32 bit target). Enabling or disabling High-DPMI awareness didn't help.
A workaround is to disable styles for dialog boxes before executing the TSaveDialog (or TOpenDialog) like this:
TStyleManager.SystemHooks := TStyleManager.SystemHooks - [shDialogs];
The file dialog itself will still be themed. You will get standard Windows-style message boxes in case an overwrite prompt (or create prompt) pops up, but they will be large enough for the user to read and click them. After the file dialog has finished, you can enable styled dialogs again by re-adding shDialogs to SystemHooks if needed.
I study preparing a dictionary programme with delphi. So far I have solved my problems about Word documents but I've got some problem about PDF documents.
I imported and installed the AcroPdf component with Delphi 7 and I want to get the word (or text) which was selected by dblclicking by user from pdf document which was viewed by the ACROPDF component in Delphi. If I can get it I'll send it the dictionary database directly.
If you help me I'll be glad. Thank you...
Remzi MAKAK
The following shows one way to get the selected text from a Pdf document which is
open in Adobe Acrobat Professional (v.8, English version).
Update The original version of this answer neglected to check the Boolean result of calling MenuItemExecute and specified the wrong argument to it. Both these points are fixed in the updated version of this answer. It turned out that the reason the call to MenuItemExecute was failing was that it is essential to call BringToFront on the Acrobat document before trying to copy the text selected in to to the clipboard.
Create a new Delphi VCL project.
In D7's IDE go to Projects | Import Type Library, and in the Import Type Library pop-up, scroll down until you see something like "Acrobat (Version 1.0) in the list of files, and
"TAcroApp, TAcroAVDoc..." in the Class names box. That is the one you need to import. Click the Create unit button/
In the project's main form file
a. Make sure it USES the Acrobat_Tlb.Pas unit from step 2. You may need to add the path to wherever you saved Acrobat_Tlb.Pas to the SearchPath of your project.
b. Drop a TButton on the form, name it btnGetSel. Drop a TEdit on the form and name it edSelection
Edit the source code of your main form unit as shown below.
Set a debugger breakpoint on Acrobat.MenuItemExecute('File->Copy'); Do not set a breakpoint within the GetSelection procedure as this is likely to defeat the call to BringToFront in it.
Close any running instance of Adobe Acrobat. Check in Task Manager that there are no hidden instances of it running. The reason for these step is to make sure that when you run your app, it "talks" to the instance of Acrobat that it starts, not another one.
Compile and run your app. Once the app and Acrobat are open, switch to Acrobat, select some text, switch back to your app and click the btnGetSel button.
Code:
uses ... Acrobat_Tlb, ClipBrd;
TDefaultForm = class(TForm)
[...]
private
FFileName: String;
procedure GetSelection;
public
Acrobat : CAcroApp;
PDDoc : CAcroPDDoc;
AVDoc : CAcroAVDoc;
end;
[...]
procedure TDefaultForm.FormCreate(Sender: TObject);
begin
// Adjust the following path to suit your system. My application is
// in a folder on drive D:
FFileName := ExtractfilePath(Application.ExeName) + 'Printed.Pdf';
Acrobat := CoAcroApp.Create;
Acrobat.Show;
AVDoc := CoAcroAVDoc.Create;
AVDoc.Open(FileName, FileName); // := Acrobat.GetAVDoc(0) as CAcroAVDoc; //
PDDoc := AVDoc.GetPDDoc as CAcroPDDoc;
end;
procedure TDefaultForm.btnGetSelClick(Sender: TObject);
begin
GetSelection;
end;
procedure TDefaultForm.GetSelection;
begin
// call this once some text is selected in Acrobat
edSelection.Text := '';
if AVDoc.BringToFront then // NB: This call to BringToFront is essential for the call to MenuItemExecute('Copy') to succeed
Caption := 'BringToFront ok'
else
Caption := 'BringToFront failed';
if Acrobat.MenuItemExecute('Copy') then
Caption := 'Copy ok'
else
Caption := 'BringToFront failed';
Sleep(100); // Normally I would avoid ever calling Sleep in a Delphi
// App's main thread. In this case, it is to allow Acrobat time to transfer the selected
// text to the clipboard before we attempt to read it.
try
edSelection.Text := Clipboard.AsText;
except
end;
end;
I use FileCtrl.SelectDirectory to show a 'open folder' dialog. However, I am unhappy with it because it doesn't allow the user to enter a path from where to start the browsing.
For example, if the user already has the path in clipboard it should be able to enter it into my dialog instead of wasting 12 seconds to navigate (open) lots of folders until it gets there.
I have found this code which seems to do EXACTLY what FileCtrl.SelectDirectory does. i hopped it will allow me to configure the dialog more. It doesn't.
So, how do I show a editbox in the SelectDirectory where the user can enter the path?
The solution that I have now, is my own dialog box. It is build from zero using TDirectory and TListBox. Very handy. BUT it looks so obsole because it uses Embarcadero's file management controls (TDirectory, TListBox) and we all know how dull they look like.
To make it clear: I would like something like FileCtrl.SelectDirectory but with an extact TEdit or a crumbar where the user can enter its path (if he has any).
Example:
Passing sdShowEdit to FileCtrl.SelectDirectory adds an edit box that you can paste a directory into.
FileCtrl.SelectDirectory('Caption', 'C:\', Dir, [sdNewUI, sdShowEdit]);
If you use the overloaded version of SelectDirectory() that has a Root parameter, it calls SHBrowseForFolder() internally (the other overload displays a custom VCL Win3.1-style dialog instead). If you assign an initial value to the variable that you pass to the Directory parameter, it gets passed to SHBrowseForFolder() as the initial selected folder. You can also specify the sdShowEdit flag in the Options parameter. However, the edit box is not meant for entering full paths. But, if you call SHBrowseForFolder() directly, you can provide your own callback function for it, so when the dialog sends you a BFFM_VALIDATEFAILED event for instance, you can grab the text from the dialog's edit box and send the dialog window a BFFM_SETSELECTION message to navigate to the correct path.
What you are really asking for is the customization provided by the Vista+ IFileDialog dialog instead. You can use the IFileDialogCustomize interface to add custom controls to the dialog, such as edit boxes and buttons, and then implement the IFileDialogControlEvents interface to know when various actions occur on those controls, like button clicks. You can use that to check your custom edit box, or the clipboard, for a valid path and if detected then tell the dialog to navigate to that path via the IFileDialog.SetFolder() method.
TJvDirectoryEdit from Jedi VCS does that. Look it up.
Here are some pictures of it:
If I understand correctly I think this could be your solution.
procedure TForm1.Button1Click(Sender: TObject);
var
opendialog : Topendialog;
begin
openDialog := TOpenDialog.Create(self);
openDialog.InitialDir := GetCurrentDir; {This can also be what is on the clipboard}
openDialog.Options := [ofFileMustExist];
openDialog.Filter := 'Text Document |*.txt'; {This is the type of file the user must open}
openDialog.FilterIndex := 1;
opendialog.execute;
end;
This code creates and shows a simple open dialog.
The path the user then selected is:
opendialog.filename
#davea's answer is ok but it only shows the old (WinXP) dialog style.
So, this is the code I use now. On Win Vista and up it shows the new style dialog and the old style on Win XP:
{$WARN SYMBOL_PLATFORM OFF}
{$IFDEF MSWindows}
function SelectAFolder(VAR Folder: string; CONST Options: TFileDialogOptions= [fdoPickFolders, fdoForceFileSystem, fdoPathMustExist, fdoDefaultNoMiniMode]): Boolean; { Keywords: FolderDialog, BrowseForFolder} { Works with UNC paths }
VAR Dlg: TFileOpenDialog;
begin
{ Win Vista and up }
if OS_IsWindowsVistaUp then
begin
Dlg:= TFileOpenDialog.Create(NIL); { Class for Vista and newer Windows operating systems style file open dialogs }
TRY
Dlg.Options := Options;
Dlg.DefaultFolder := Folder;
Dlg.FileName := Folder;
Result := Dlg.Execute;
if Result
then Folder:= Dlg.FileName;
FINALLY
FreeAndNil(Dlg);
END;
end
else
{ Win XP or down }
Result:= vcl.FileCtrl.SelectDirectory('', ExtractFileDrive(Folder), Folder, [sdNewUI, sdShowEdit, sdNewFolder], nil);
if Result
then Folder:= Trail(Folder);
end;
{$ENDIF}
{$WARN SYMBOL_PLATFORM On}
{ Keywords: FolderDialog, BrowseForFolder}
I want to be able to open files in Delphi with a Windows GUI where you can scroll through the folders etc. I have already done this with Matlab with a single function that (after selecting the file) returns a string of the path. You could event specify which extension the be shown. Is this kind of function available in delphi and how should I use it.
you can use the TOpenDialog component which is part of the Dialogs unit. you can create in runtime or drop this component from the Dialogs palette.
if you drop the component to your form you can use in this way
OpenDialog1.Filter := 'Only Text files (*.txt)|*.txt';
if OpenDialog1.Execute then
//do you stuff here
or if you create the component in runtime
Var
OpenDialog1 : TOpenDialog;
begin
OpenDialog1:=TOpenDialog.Create(nil);
try
OpenDialog1.Filter := 'Only Text files (*.txt)|*.txt';
if OpenDialog1.Execute then
ShowMessage('Selected File '+OpenDialog1.FileName);
finally
OpenDialog1.Free;
end;
end;
That's available via TOpenDialog which encapsulates the relevant Windows functionality.
Drop a TOpenDialog component on your form. Then you can call OpenDialog1.Execute to show the Windows dialog.