Skip to content

Commit 7e2acfc

Browse files
authored
Merge pull request Ekopalypse#16 from alankilborn/filesavedlg
Add support for file-save dialog
2 parents b177218 + 9c7724e commit 7e2acfc

3 files changed

Lines changed: 99 additions & 44 deletions

File tree

helper/WinDialog/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
'Button', 'DefaultButton', 'CheckBoxButton', 'GroupBox', 'CommandButton', 'RadioButton', 'RadioPushButton', 'SplitButton',
5959
'Label', 'TruncatedLabel', 'BlackFramedLabel', 'CenteredLabel', 'RigthAlignedLabel',
6060
'ComboBox', 'ComboBoxEx', 'ListBox', 'TextBox', 'ListView', 'ProgressBar', 'StatusBar', 'UpDown', 'TreeView',
61-
'DirectoryPicker', 'FileOpenDialog'
61+
'DirectoryPicker', 'FileOpenDialog', 'FileSaveDialog'
6262
]
6363
__version__ = '0.3'
6464
__author__ = 'ekopalypse'
@@ -102,7 +102,7 @@
102102
# from .controls.systabcontrol32 import ...
103103
# from .controls.toolbarwindow32 import ...
104104

105-
from .com_dialogs import FileOpenDialog, DirectoryPicker
105+
from .com_dialogs import FileOpenDialog, DirectoryPicker, FileSaveDialog
106106

107107
from .resource_parser import parser
108108

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,43 @@
1-
from WinDialog import FileOpenDialog, DirectoryPicker
1+
from WinDialog import FileOpenDialog, DirectoryPicker, FileSaveDialog
22
from WinDialog.com_dialogs import FOS
33

4-
dlg = FileOpenDialog()
5-
dlg.setOptions(FOS.ALLOWMULTISELECT)
6-
print(dlg.show())
4+
def test_dlgs():
75

8-
print(DirectoryPicker().show())
6+
answer = notepad.messageBox('About to demo a file-open dialog where you can select multiple items -- proceed?', '', MESSAGEBOXFLAGS.YESNOCANCEL)
7+
if answer == MESSAGEBOXFLAGS.RESULTCANCEL: return
8+
if answer == MESSAGEBOXFLAGS.RESULTYES:
9+
open_dlg = FileOpenDialog()
10+
open_dlg.setOptions(FOS.ALLOWMULTISELECT)
11+
result = open_dlg.show()
12+
if len(result) > 0: notepad.messageBox(str(result), 'Result')
913

10-
options = dlg.getOptions()
11-
options &= ~FOS.ALLOWMULTISELECT
12-
dlg.setOptions(options)
13-
print(dlg.show())
14+
answer = notepad.messageBox('About to demo a file-open dialog where you can only select 1 item -- proceed?', '', MESSAGEBOXFLAGS.YESNOCANCEL)
15+
if answer == MESSAGEBOXFLAGS.RESULTCANCEL: return
16+
if answer == MESSAGEBOXFLAGS.RESULTYES:
17+
open_dlg = FileOpenDialog()
18+
open_options = open_dlg.getOptions()
19+
open_options &= ~FOS.ALLOWMULTISELECT
20+
open_dlg.setOptions(open_options)
21+
result = open_dlg.show()
22+
if len(result) > 0: notepad.messageBox(str(result), 'Result')
23+
24+
answer = notepad.messageBox('About to demo a file-save dialog -- proceed?', '', MESSAGEBOXFLAGS.YESNOCANCEL)
25+
if answer == MESSAGEBOXFLAGS.RESULTCANCEL: return
26+
if answer == MESSAGEBOXFLAGS.RESULTYES:
27+
save_dlg = FileSaveDialog()
28+
save_dlg.setFolder(r'c:')
29+
save_dlg.setFileTypes([['All files', '*.*'], ['Text Files', '*.txt'], ['Log Files', '*.log']])
30+
save_options = save_dlg.getOptions()
31+
save_options |= FOS.OVERWRITEPROMPT
32+
save_dlg.setOptions(save_options)
33+
result = save_dlg.show()
34+
if len(result) > 0: notepad.messageBox(str(result), 'Result')
35+
36+
answer = notepad.messageBox('About to demo a directory-picker dialog -- proceed?', '', MESSAGEBOXFLAGS.YESNOCANCEL)
37+
if answer == MESSAGEBOXFLAGS.RESULTCANCEL: return
38+
if answer == MESSAGEBOXFLAGS.RESULTYES:
39+
dir_pick_dlg = DirectoryPicker()
40+
result = dir_pick_dlg.show()
41+
if len(result) > 0: notepad.messageBox(str(result), 'Result')
42+
43+
test_dlgs()

helper/WinDialog/com_dialogs/__init__.py

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ def __post_init__(self, rclsid, riid, extend_vtable):
192192
self._set_title = WINFUNCTYPE(HRESULT, c_void_p, LPCWSTR)(self._vtable[17])
193193
self._set_ok_button_label = WINFUNCTYPE(HRESULT, c_void_p, LPCWSTR)(self._vtable[18])
194194
self._set_file_name_label = WINFUNCTYPE(HRESULT, c_void_p, LPCWSTR)(self._vtable[19])
195-
# self._get_result = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[20])
195+
self._get_result = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[20])
196196
self._add_place = WINFUNCTYPE(HRESULT, c_void_p, c_void_p, UINT)(self._vtable[21])
197197
self._set_default_extension = WINFUNCTYPE(HRESULT, c_void_p, LPCWSTR)(self._vtable[22])
198198
# self._close = WINFUNCTYPE(HRESULT, c_void_p, HRESULT)(self._vtable[23])
@@ -492,43 +492,68 @@ def setOptions(self, options):
492492
self._set_options(self.this, default_options.value | options)
493493

494494

495-
# @dataclass
496-
# class FileSaveDialog(FileDialog):
497-
# # https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ifilesavedialog
498-
# '''
499-
# FileSaveDialog Class
495+
@dataclass
496+
class FileSaveDialog(FileDialog):
497+
# https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ifilesavedialog
498+
'''
499+
FileSaveDialog Class
500500
501-
# Represents the standard COM-based file open dialog window.
501+
Represents the standard COM-based file save dialog window.
502502
503-
# The FileSaveDialog class provides a template for creating and managing dialog windows.
504-
# It encapsulates properties and behaviors common to dialog windows, such as
505-
# title, size, position, styles, and controls.
503+
The FileSaveDialog class provides a template for creating and managing dialog windows.
504+
It encapsulates properties and behaviors common to dialog windows, such as
505+
title, size, position, styles, and controls.
506506
507-
# Attributes:
508-
# title (str): The title of the dialog window.
509-
# parent (int): The handle of the parent window for the dialog.
510-
# '''
507+
Attributes:
508+
title (str): The title of the dialog window.
509+
parent (int): The handle of the parent window for the dialog.
510+
'''
511511

512-
# def __post_init__(self):
513-
# """
514-
# Perform post-initialization tasks for the FileSaveDialog object.
512+
selectedItem: List = field(default_factory=list)
513+
parent: int = notepad.hwnd
515514

516-
# This method is automatically called after the initialization of the FileSaveDialog object.
517-
# It creates the com object and its vtable (object methods).
515+
def __post_init__(self):
516+
"""
517+
Perform post-initialization tasks for the FileSaveDialog object.
518518
519-
# Args:
520-
# None.
519+
This method is automatically called after the initialization of the FileSaveDialog object.
520+
It creates the com object and its vtable (object methods).
521521
522-
# Returns:
523-
# None.
524-
# """
525-
# super().__post_init__(GUID('C0B4E2F3-BA21-4773-8DBA-335EC946EB8B'), GUID('84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB'), 5)
522+
Args:
523+
None.
526524
527-
# def show(self, hwnd=None):
528-
# try:
529-
# self._show(self.this, hwnd)
530-
# except OSError as e:
531-
# if len(e.args) > 3 and e.args[3] == -2147023673:
532-
# pass # User cancelled dialog
533-
# else:
534-
# raise
525+
Returns:
526+
None.
527+
"""
528+
super().__post_init__(GUID('C0B4E2F3-BA21-4773-8DBA-335EC946EB8B'), GUID('84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB'), 5)
529+
# self._set_saveas_item = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[27])
530+
# self._set_properties = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[28])
531+
# self._set_collected_properties = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[29])
532+
# self._get_properties = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[30])
533+
# self._apply_properties = WINFUNCTYPE(HRESULT, c_void_p, POINTER(c_void_p))(self._vtable[30])
534+
535+
def show(self, hwnd=None):
536+
'''
537+
This method displays the dialog on the screen.
538+
The method blocks until the dialog is closed.
539+
540+
Args:
541+
None
542+
543+
Returns:
544+
list: A single-element list containing the selected item (or empty list if cancelled or some error)
545+
'''
546+
try:
547+
self.selectedItem.clear()
548+
self._show(self.this, self.parent)
549+
ishell_object = c_void_p()
550+
if self._get_result(self.this, byref(ishell_object)) == 0:
551+
ishell_item = IShellItem(ishell_object)
552+
self.selectedItem.append(ishell_item.get_display_name())
553+
ishell_item.release()
554+
except OSError as e:
555+
if len(e.args) > 3 and e.args[3] == -2147023673: # see, e.g., https://knowledge.broadcom.com/external/article/152212/error-codes-list-for-microsoft-technolog.html
556+
pass # User cancelled dialog
557+
else:
558+
raise
559+
return self.selectedItem

0 commit comments

Comments
 (0)