【问题标题】:GetSaveFileName / IFileSaveDialog - event on user input / react to file name change?GetSaveFileName / IFileSaveDialog - 用户输入事件/对文件名更改做出反应?
【发布时间】:2018-01-06 13:49:35
【问题描述】:

我目前在我的 C++ 应用程序中使用GetSaveFileName 对话框。 (据我所知,这已被 IFileDialog interface 取代,我选择不将此问题限制在已弃用的 API 上,而是接受两种实现的解决方案)。

挑战在于对用户输入做出反应(即用户手动输入文件名输入)并相应地修改文件对话框。

作为一个具体示例,请考虑在用户手动输入支持的文件扩展名时自动更改文件类型下拉列表中的文件类型。


我曾希望OPENFILENAME 结构的lpfnHook 成员可以为我做到这一点,不幸的是,文件名输入中的键入字符似乎没有触发事件。

【问题讨论】:

  • 开箱即用已经支持这种行为(至少在 IFileDialog 中是这样)。用户可以在文件名编辑框中输入文件过滤器,然后按回车键应用它。
  • 我看不到:在文件名编辑框中按回车相当于按“保存”-它不会更改文件过滤器。请注意,该应用程序具有多个具有相同扩展名的输出选项,即用户必须在对话框仍打开时进行选择,并且在用户关闭对话框后无法根据文件扩展名进行明确的选择。
  • 通过文件过滤器我的意思是*.png* 的存在使其作为过滤器而不是在按下 Enter 时结束文件选择对话框。它应该可以工作。
  • 啊,我看到了混乱:我不想设置文件过滤器只是为了过滤对话框中的文件 - 我需要文件过滤器来设置输出格式(我们可以放心地假设它是文件保存对话框)。目的是用户可以输入image.png,文件过滤器(以及输出格式)自动设置为“便携式网络图形(*.png)”。
  • 不要认为这是可能的。为什么不坚持平台标准,避免让可怜的用户感到困惑?

标签: c++ c winapi


【解决方案1】:

正确的解决方案是使用用户输入的任何文件名创建保存的文件,并根据所选过滤器格式化文件内容。在关闭对话框之前,用户应该可以随意更改过滤器。

无需对单个按键做出反应。但是,如果必须,那么在使用旧版GetSaveFileName() API 时,唯一的选择是直接子类化文件名编辑字段,例如使用SetWindowSubclass()。您可以使用带有edt1cmb13 控件ID 的GetDlgItem() 获取编辑字段的HWND。子类可以拦截按键消息,然后向对话框发送CDM_GETFILEPATH 消息以获取当前键入的文件名,从中解析扩展名,并相应地手动更新过滤器组合框。您可以使用 GetDlgItem()cmb1 控件 ID 获取组合框的 HWND

但是,在 Vista 和更高版本上,GetSaveFileName() 只是在使用 ComCtl32 v6 时更新的IFileSaveDialog API 的包装器,因此不能保证上述内容不再起作用。不过你可以试试。

如果您直接使用较新的IFileDialog API,它确实允许您通过IFileDialogCustomize 使用新控件自定义对话框,但它不允许您对现有控件进行子类化(它无法访问HWND s 的对话框或其控件。您将不得不求助于较低级别的挂钩来访问它们)。如果您确实设法对文件名编辑字段进行子类化,则可以使用IFileDialog::GetFileName() 来检索当前键入的文件名,但您不能直接更新过滤器组合框,因为一旦显示对话框就无法调用IFileDialog::SetFilterTypeIndex() (除非你能想办法得到它的HWND)。仅在 Vista 上,您可以尝试根本不指定过滤器(或者至少不指定过滤器 *.*),然后使用 IFileDialogCustomize::AddComboBox()IFileDialogControlEvents::OnItemSelected 的组合来模拟手动过滤器列表,以及 @987654342 @ 指定根据所选过滤器显示在对话框中的项目。但是,SetFilter() 已被弃用,不再适用于 Windows 7 及更高版本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多