Delphi OpenDialog文件名显示问题
Delphi OpenDialog filename display problem
将 OpenDialog 组件放在新窗体上,并将此代码放入 OnCreate
opendialog1.filename:='This is a long filename.txt';
opendialog1.execute;
当应用程序运行时,会出现对话框,文件名显示在打开的对话框中,但文件名会突出显示并向右滚动(即使有足够的空间来显示完整的文件名)。
它只显示已突出显示的“ng filename.txt”。
有什么方法可以“取消突出显示”文件名并让文本向左滚动以显示全名“This is a long filename.txt”?
如果我可以 simulate/push 在显示 OpenDialog 时按 Home 键,问题将得到解决,但是 none 以下选项似乎有效。
keybd_event(VK_HOME, 0, 0, 0);
keybd_event(VK_HOME, 0, KEYEVENTF_KEYUP, 0);
或
input.Itype := INPUT_KEYBOARD;
input.ki.wVk := 47;
input.ki.wScan := 47;
input.ki.dwFlags := 0;
input.ki.time := 0;
input.ki.dwExtraInfo := 0;
SendInput(1, input, sizeof(input));
input.ki.dwFlags := KEYEVENTF_KEYUP;
SendInput(1, input, sizeof(input));
或
PostMessage(GetParent(OpenDialog1.Handle), WM_KEYDOWN, VK_HOME, 0);
PostMessage(GetParent(OpenDialog1.Handle), WM_KEYUP, VK_HOME, 0);
如果我将这些代码片段放在 openDialog1.execute 之前,它似乎可以在我的 PC 上运行,但这是个坏主意,因为对话框尚未打开,因此可能收不到按键消息).
在 opendialog1.execute 调用之后尝试所有这些方法似乎没有任何作用。
建议的解决方案
keybd_event(VK_HOME, 0, 0, 0);
keybd_event(VK_HOME, 0, KEYEVENTF_KEYUP, 0);
不安全,无论您何时执行它。
如果我在应用程序中按 Ctrl+O 并在等待对话框显示时切换到其他应用程序怎么办?
然后这个其他应用程序将收到主页键。那么任何事情都可能发生。另一个应用程序可能正在显示控制患者 IV 药物流速的轨迹条,并且该 HOME 键可能将轨迹条设置为 0 cc/min.
更有可能:您在资源管理器 window 中丢失了 selection(可能包含一千张图像),文档中的插入符号位置(位于非常特殊的位置),select在树视图中编辑节点等。或者您的媒体播放器重新启动当前曲目。
是的,很多人(比如我自己)确实做多任务处理!
这是一个可能的(安全的)解决方案。不过,我并不认为它是最优雅的。
做法如下:
我使用 OnSelectionChange
事件在创建对话框 window 后有机会 运行 一些代码。但是,我必须手动确保在第一次触发此事件时只 运行 我的“文件名修复”。如果(默认)文件名非空,我还确保只 运行 此代码。
第一次触发事件时,我在其中找到了编辑框。我“知道”它是正确的控件,因为 (1) 它是一个编辑框,并且 (2) 它的文本等于(默认)文件名(不为空)。
然后我专门指示此编辑框将其插入符号移动到第一个字符,然后 (re)select 每个字符。
完整代码:
type
TOpenDialogFileNameEditData = class
FileName: string;
Handle: HWND;
end;
function EnumChildProc(h: HWND; lp: LPARAM): BOOL; stdcall;
var
WndClass, WndTxt: array[0..1024] of Char;
begin
Result := True;
FillChar(WndClass, SizeOf(WndClass), 0);
FillChar(WndTxt, SizeOf(WndTxt), 0);
if GetClassName(h, WndClass, Length(WndClass)) <> 0 then
begin
if SameText(WndClass, 'Edit') then
begin
if GetWindowText(h, WndTxt, Length(WndTxt)) <> 0 then
begin
if WndTxt = TOpenDialogFileNameEditData(lp).FileName then
begin
TOpenDialogFileNameEditData(lp).Handle := h;
Exit(False);
end;
end;
end;
end;
end;
procedure TForm1.FODE(Sender: TObject);
begin
if Sender is TOpenDialog then
begin
var OpenDialog := TOpenDialog(Sender);
if OpenDialog.Tag <> 0 then
Exit;
OpenDialog.Tag := 1;
var Data := TOpenDialogFileNameEditData.Create;
try
Data.FileName := ExtractFileName(OpenDialog.FileName);
if Data.FileName.IsEmpty then
Exit;
if OpenDialog.Handle <> 0 then
begin
EnumChildWindows(OpenDialog.Handle, @EnumChildProc, NativeInt(Data));
if Data.Handle <> 0 then
begin
SendMessage(Data.Handle, EM_SETSEL, 0, 0); // set caret at first char
SendMessage(Data.Handle, EM_SETSEL, 0, -1); // (re)select all
end;
end;
finally
Data.Free;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
with TOpenDialog.Create(nil) do
try
FileName := 'This is the story of a horse that met a cat that met a dog the day before.txt';
OnSelectionChange := FODE;
Execute
finally
Free;
end;
end;
之前:
之后:
更新
根据要求,我制作了一个易于重用的单元和函数来应用此修复程序。
这是完整的单元:
unit OpenDialogUpgrader;
interface
uses
Windows, Messages, SysUtils, Types, Dialogs;
procedure FixOpenDialog(AOpenDialog: TOpenDialog);
implementation
type
TOpenDialogFileNameEditData = class
FileName: string;
Handle: HWND;
class procedure DialogSelectionChange(Sender: TObject);
end;
procedure FixOpenDialog(AOpenDialog: TOpenDialog);
begin
AOpenDialog.Tag := 0;
AOpenDialog.OnSelectionChange := TOpenDialogFileNameEditData.DialogSelectionChange;
end;
{ TOpenDialogFileNameEditData }
function EnumChildProc(h: HWND; lp: LPARAM): BOOL; stdcall;
var
WndClass, WndTxt: array[0..1024] of Char;
begin
Result := True;
FillChar(WndClass, SizeOf(WndClass), 0);
FillChar(WndTxt, SizeOf(WndTxt), 0);
if GetClassName(h, WndClass, Length(WndClass)) <> 0 then
begin
if SameText(WndClass, 'Edit') then
begin
if GetWindowText(h, WndTxt, Length(WndTxt)) <> 0 then
begin
if WndTxt = TOpenDialogFileNameEditData(lp).FileName then
begin
TOpenDialogFileNameEditData(lp).Handle := h;
Exit(False);
end;
end;
end;
end;
end;
class procedure TOpenDialogFileNameEditData.DialogSelectionChange(Sender: TObject);
begin
if Sender is TOpenDialog then
begin
var OpenDialog := TOpenDialog(Sender);
if OpenDialog.Tag <> 0 then
Exit;
OpenDialog.Tag := 1;
var Data := TOpenDialogFileNameEditData.Create;
try
Data.FileName := ExtractFileName(OpenDialog.FileName);
if Data.FileName.IsEmpty then
Exit;
if OpenDialog.Handle <> 0 then
begin
EnumChildWindows(OpenDialog.Handle, @EnumChildProc, NativeInt(Data));
if Data.Handle <> 0 then
begin
SendMessage(Data.Handle, EM_SETSEL, 0, 0); // set caret at first char
SendMessage(Data.Handle, EM_SETSEL, 0, -1); // (re)select all
end;
end;
finally
Data.Free;
end;
end;
end;
end.
要在您自己的单元 X
中使用此单元和函数,只需将单元 (OpenDialogUpgrader
) 添加到您的 X
单元的实现部分 uses
子句并更改你的标准
var OpenDialog := TOpenDialog.Create(nil);
try
OpenDialog.FileName := 'This is the story of a horse that met a cat that met a dog the day before.txt';
OpenDialog.Execute;
finally
OpenDialog.Free;
end;
进入
var OpenDialog := TOpenDialog.Create(nil);
try
OpenDialog.FileName := 'This is the story of a horse that met a cat that met a dog the day before.txt';
FixOpenDialog(OpenDialog); // <-- just call this prior to Execute
OpenDialog.Execute;
finally
OpenDialog.Free;
end;
当然,如果您的应用程序在 20 个不同的单元中有 73 个打开的对话框,您只需要这个 OpenDialogUpgrader
单元的一个副本,但您需要将其添加到实现部分 uses
在你的 20 个单元中的每个单元中。你需要在每个 TOpenDialog.Execute
.
之前调用 FixOpenDialog
将 OpenDialog 组件放在新窗体上,并将此代码放入 OnCreate
opendialog1.filename:='This is a long filename.txt';
opendialog1.execute;
当应用程序运行时,会出现对话框,文件名显示在打开的对话框中,但文件名会突出显示并向右滚动(即使有足够的空间来显示完整的文件名)。
它只显示已突出显示的“ng filename.txt”。
有什么方法可以“取消突出显示”文件名并让文本向左滚动以显示全名“This is a long filename.txt”?
如果我可以 simulate/push 在显示 OpenDialog 时按 Home 键,问题将得到解决,但是 none 以下选项似乎有效。
keybd_event(VK_HOME, 0, 0, 0);
keybd_event(VK_HOME, 0, KEYEVENTF_KEYUP, 0);
或
input.Itype := INPUT_KEYBOARD;
input.ki.wVk := 47;
input.ki.wScan := 47;
input.ki.dwFlags := 0;
input.ki.time := 0;
input.ki.dwExtraInfo := 0;
SendInput(1, input, sizeof(input));
input.ki.dwFlags := KEYEVENTF_KEYUP;
SendInput(1, input, sizeof(input));
或
PostMessage(GetParent(OpenDialog1.Handle), WM_KEYDOWN, VK_HOME, 0);
PostMessage(GetParent(OpenDialog1.Handle), WM_KEYUP, VK_HOME, 0);
如果我将这些代码片段放在 openDialog1.execute 之前,它似乎可以在我的 PC 上运行,但这是个坏主意,因为对话框尚未打开,因此可能收不到按键消息).
在 opendialog1.execute 调用之后尝试所有这些方法似乎没有任何作用。
建议的解决方案
keybd_event(VK_HOME, 0, 0, 0);
keybd_event(VK_HOME, 0, KEYEVENTF_KEYUP, 0);
不安全,无论您何时执行它。
如果我在应用程序中按 Ctrl+O 并在等待对话框显示时切换到其他应用程序怎么办?
然后这个其他应用程序将收到主页键。那么任何事情都可能发生。另一个应用程序可能正在显示控制患者 IV 药物流速的轨迹条,并且该 HOME 键可能将轨迹条设置为 0 cc/min.
更有可能:您在资源管理器 window 中丢失了 selection(可能包含一千张图像),文档中的插入符号位置(位于非常特殊的位置),select在树视图中编辑节点等。或者您的媒体播放器重新启动当前曲目。
是的,很多人(比如我自己)确实做多任务处理!
这是一个可能的(安全的)解决方案。不过,我并不认为它是最优雅的。
做法如下:
我使用
OnSelectionChange
事件在创建对话框 window 后有机会 运行 一些代码。但是,我必须手动确保在第一次触发此事件时只 运行 我的“文件名修复”。如果(默认)文件名非空,我还确保只 运行 此代码。第一次触发事件时,我在其中找到了编辑框。我“知道”它是正确的控件,因为 (1) 它是一个编辑框,并且 (2) 它的文本等于(默认)文件名(不为空)。
然后我专门指示此编辑框将其插入符号移动到第一个字符,然后 (re)select 每个字符。
完整代码:
type
TOpenDialogFileNameEditData = class
FileName: string;
Handle: HWND;
end;
function EnumChildProc(h: HWND; lp: LPARAM): BOOL; stdcall;
var
WndClass, WndTxt: array[0..1024] of Char;
begin
Result := True;
FillChar(WndClass, SizeOf(WndClass), 0);
FillChar(WndTxt, SizeOf(WndTxt), 0);
if GetClassName(h, WndClass, Length(WndClass)) <> 0 then
begin
if SameText(WndClass, 'Edit') then
begin
if GetWindowText(h, WndTxt, Length(WndTxt)) <> 0 then
begin
if WndTxt = TOpenDialogFileNameEditData(lp).FileName then
begin
TOpenDialogFileNameEditData(lp).Handle := h;
Exit(False);
end;
end;
end;
end;
end;
procedure TForm1.FODE(Sender: TObject);
begin
if Sender is TOpenDialog then
begin
var OpenDialog := TOpenDialog(Sender);
if OpenDialog.Tag <> 0 then
Exit;
OpenDialog.Tag := 1;
var Data := TOpenDialogFileNameEditData.Create;
try
Data.FileName := ExtractFileName(OpenDialog.FileName);
if Data.FileName.IsEmpty then
Exit;
if OpenDialog.Handle <> 0 then
begin
EnumChildWindows(OpenDialog.Handle, @EnumChildProc, NativeInt(Data));
if Data.Handle <> 0 then
begin
SendMessage(Data.Handle, EM_SETSEL, 0, 0); // set caret at first char
SendMessage(Data.Handle, EM_SETSEL, 0, -1); // (re)select all
end;
end;
finally
Data.Free;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
with TOpenDialog.Create(nil) do
try
FileName := 'This is the story of a horse that met a cat that met a dog the day before.txt';
OnSelectionChange := FODE;
Execute
finally
Free;
end;
end;
之前:
之后:
更新
根据要求,我制作了一个易于重用的单元和函数来应用此修复程序。
这是完整的单元:
unit OpenDialogUpgrader;
interface
uses
Windows, Messages, SysUtils, Types, Dialogs;
procedure FixOpenDialog(AOpenDialog: TOpenDialog);
implementation
type
TOpenDialogFileNameEditData = class
FileName: string;
Handle: HWND;
class procedure DialogSelectionChange(Sender: TObject);
end;
procedure FixOpenDialog(AOpenDialog: TOpenDialog);
begin
AOpenDialog.Tag := 0;
AOpenDialog.OnSelectionChange := TOpenDialogFileNameEditData.DialogSelectionChange;
end;
{ TOpenDialogFileNameEditData }
function EnumChildProc(h: HWND; lp: LPARAM): BOOL; stdcall;
var
WndClass, WndTxt: array[0..1024] of Char;
begin
Result := True;
FillChar(WndClass, SizeOf(WndClass), 0);
FillChar(WndTxt, SizeOf(WndTxt), 0);
if GetClassName(h, WndClass, Length(WndClass)) <> 0 then
begin
if SameText(WndClass, 'Edit') then
begin
if GetWindowText(h, WndTxt, Length(WndTxt)) <> 0 then
begin
if WndTxt = TOpenDialogFileNameEditData(lp).FileName then
begin
TOpenDialogFileNameEditData(lp).Handle := h;
Exit(False);
end;
end;
end;
end;
end;
class procedure TOpenDialogFileNameEditData.DialogSelectionChange(Sender: TObject);
begin
if Sender is TOpenDialog then
begin
var OpenDialog := TOpenDialog(Sender);
if OpenDialog.Tag <> 0 then
Exit;
OpenDialog.Tag := 1;
var Data := TOpenDialogFileNameEditData.Create;
try
Data.FileName := ExtractFileName(OpenDialog.FileName);
if Data.FileName.IsEmpty then
Exit;
if OpenDialog.Handle <> 0 then
begin
EnumChildWindows(OpenDialog.Handle, @EnumChildProc, NativeInt(Data));
if Data.Handle <> 0 then
begin
SendMessage(Data.Handle, EM_SETSEL, 0, 0); // set caret at first char
SendMessage(Data.Handle, EM_SETSEL, 0, -1); // (re)select all
end;
end;
finally
Data.Free;
end;
end;
end;
end.
要在您自己的单元 X
中使用此单元和函数,只需将单元 (OpenDialogUpgrader
) 添加到您的 X
单元的实现部分 uses
子句并更改你的标准
var OpenDialog := TOpenDialog.Create(nil);
try
OpenDialog.FileName := 'This is the story of a horse that met a cat that met a dog the day before.txt';
OpenDialog.Execute;
finally
OpenDialog.Free;
end;
进入
var OpenDialog := TOpenDialog.Create(nil);
try
OpenDialog.FileName := 'This is the story of a horse that met a cat that met a dog the day before.txt';
FixOpenDialog(OpenDialog); // <-- just call this prior to Execute
OpenDialog.Execute;
finally
OpenDialog.Free;
end;
当然,如果您的应用程序在 20 个不同的单元中有 73 个打开的对话框,您只需要这个 OpenDialogUpgrader
单元的一个副本,但您需要将其添加到实现部分 uses
在你的 20 个单元中的每个单元中。你需要在每个 TOpenDialog.Execute
.
FixOpenDialog