# FileChooserDialog(Python)

Marta Maria Casetti
mmcasetti@gmail.com 2012
"열기" 및 "저장" 명령에 알맞은 대화상자
조성호
shcho@gnome.org 2017-2019.

# FileChooserDialog

FileChooserDialog는 TextView에 열었거나 바닥부터 새로 작성한 텍스트 문서를 저장합니다(하단 참고).

새 문서를 열 때 FileChooserDialog를 호출할 수 있습니다.

# 예제를 다시 만드는 과정

"New", "Open", "Save", "Save as", "Quit" 항목이 들어간 app-menu 설명 .ui 파일을 만드십시오. 글레이드 개발 환경이나 텍스트 편집기에서 처리할 수 있습니다. 내용을 참고하십시오.

Gtk.TextViewGtk.Buffer `self.buffer`와 `None`으로 초기값을 설정한 Gio.File 형식의 `self.file` 로 Gtk.TextView 파이썬 프로그램을 만드십시오.

이 프로그램에서 app-menu에 항목마다 관련 동작을 만드시고, 콜백 함수에 연결하신 다음, Gtk.Builder의 `do_startup()` 메서드로 메뉴를 가져오십시오.

"새 파일" 및 "끝내기" 동작과 콜백 함수는 조금 단순합니다. 를 참고해보시죠. 시그널 및 콜백 함수에 대한 자세한 설명은 를 살펴보십시오.

"열기" 콜백 함수에서는 "열기" 동작에 맞게 Gtk.FileChooserDialog를 만들고 연 다음, FileChooserDialog의 "열기" 및 "취소" 단추에 제각기 다른 콜백 함수를 연결해야합니다.

"다른 이름으로 저장"은 "열기"와 근본적으로 비슷하게 동작하지만, "저장" 단추의 콜백 함수 동작은 좀 더 복잡한 메서드 `save_to_file()`에 따릅니다.

"저장" 동작은, `self.file` 이 새 파일이어서 파일이 `None`(없음)일 경우로 경우의 수를 줄일 수 있으며, 이때는 "다른 이름으로 저장"인 경우로 되돌릴 수 있습니다. 그리고 파일이 `None`(없음) 상태가 아닐 경우, `save_to_file()` 호출만으로 과정을 줄입니다.

마지막으로, `save_to_file()` 메서드는 146번째 줄부터 175번째 줄 까지의 부분을 참고하십시오.

# app-menu를 만드는 XML 파일

<?xml version="1.0"?> <interface> <menu id="appmenu"> <section> <item> <attribute name="label">New</attribute> <attribute name="action">win.new</attribute> </item> <item> <attribute name="label">Open</attribute> <attribute name="action">win.open</attribute> </item> </section> <section> <item> <attribute name="label">Save</attribute> <attribute name="action">win.save</attribute> </item> <item> <attribute name="label">Save As...</attribute> <attribute name="action">win.save-as</attribute> </item> </section> <section> <item> <attribute name="label">Quit</attribute> <attribute name="action">app.quit</attribute> </item> </section> </menu> </interface>

# 예제 결과를 만드는 코드

from gi.repository import Gtk from gi.repository import Gdk from gi.repository import Gio from gi.repository import GObject import sys

class MyWindow(Gtk.ApplicationWindow):

def __init__(self, app): Gtk.Window.__init__( self, title="FileChooserDialog Example", application=app) self.set_default_size(400, 400)

# the actions for the window menu, connected to the callback functions new_action = Gio.SimpleAction.new("new", None) new_action.connect("activate", self.new_callback) self.add_action(new_action)

open_action = Gio.SimpleAction.new("open", None) open_action.connect("activate", self.open_callback) self.add_action(open_action)

save_action = Gio.SimpleAction.new("save", None) save_action.connect("activate", self.save_callback) self.add_action(save_action)

save_as_action = Gio.SimpleAction.new("save-as", None) save_as_action.connect("activate", self.save_as_callback) self.add_action(save_as_action)

# the file self.file = None

# the textview with the buffer self.buffer = Gtk.TextBuffer() textview = Gtk.TextView(buffer=self.buffer) textview.set_wrap_mode(Gtk.WrapMode.WORD)

# a scrolled window for the textview self.scrolled_window = Gtk.ScrolledWindow() self.scrolled_window.set_policy( Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.scrolled_window.add(textview) self.scrolled_window.set_border_width(5)

# add the scrolled window to the window self.add(self.scrolled_window)

# callback for new def new_callback(self, action, parameter): self.buffer.set_text("") print("New file created")

# callback for open def open_callback(self, action, parameter): # create a filechooserdialog to open: # the arguments are: title of the window, parent_window, action, # (buttons, response) open_dialog = Gtk.FileChooserDialog("Pick a file", self, Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT))

# not only local files can be selected in the file selector open_dialog.set_local_only(False) # dialog always on top of the textview window open_dialog.set_modal(True) # connect the dialog with the callback function open_response_cb() open_dialog.connect("response", self.open_response_cb) # show the dialog open_dialog.show()

# callback function for the dialog open_dialog def open_response_cb(self, dialog, response_id): open_dialog = dialog # if response is "ACCEPT" (the button "Open" has been clicked) if response_id == Gtk.ResponseType.ACCEPT: # self.file is the file that we get from the FileChooserDialog self.file = open_dialog.get_file() # an empty string (provisionally) content = "" try: # load the content of the file into memory: # success is a boolean depending on the success of the operation # content is self-explanatory # etags is an entity tag (can be used to quickly determine if the # file has been modified from the version on the file system) [success, content, etags] = self.file.load_contents(None) except GObject.GError as e: print("Error: " + e.message) # set the content as the text into the buffer self.buffer.set_text(content, len(content)) print("opened: " + open_dialog.get_filename()) # if response is "CANCEL" (the button "Cancel" has been clicked) elif response_id == Gtk.ResponseType.CANCEL: print("cancelled: FileChooserAction.OPEN") # destroy the FileChooserDialog dialog.destroy()

# callback function for save_as def save_as_callback(self, action, parameter): # create a filechooserdialog to save: # the arguments are: title of the window, parent_window, action, # (buttons, response) save_dialog = Gtk.FileChooserDialog("Pick a file", self, Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT)) # the dialog will present a confirmation dialog if the user types a file name that # already exists save_dialog.set_do_overwrite_confirmation(True) # dialog always on top of the textview window save_dialog.set_modal(True) # if self.file has already been saved if self.file is not None: try: # set self.file as the current filename for the file chooser save_dialog.set_file(self.file) except GObject.GError as e: print("Error: " + e.message) # connect the dialog to the callback function save_response_cb() save_dialog.connect("response", self.save_response_cb) # show the dialog save_dialog.show()

# callback function for the dialog save_dialog def save_response_cb(self, dialog, response_id): save_dialog = dialog # if response is "ACCEPT" (the button "Save" has been clicked) if response_id == Gtk.ResponseType.ACCEPT: # self.file is the currently selected file self.file = save_dialog.get_file() # save to file (see below) self.save_to_file() # if response is "CANCEL" (the button "Cancel" has been clicked) elif response_id == Gtk.ResponseType.CANCEL: print("cancelled: FileChooserAction.SAVE") # destroy the FileChooserDialog dialog.destroy()

# callback function for save def save_callback(self, action, parameter): # if self.file is not already there if self.file is not None: self.save_to_file() # self.file is a new file else: # use save_as self.save_as_callback(action, parameter)

# save_to_file def save_to_file(self): # get the content of the buffer, without hidden characters [start, end] = self.buffer.get_bounds() current_contents = self.buffer.get_text(start, end, False) # if there is some content if current_contents != "": # set the content as content of self.file. # arguments: contents, etags, make_backup, flags, GError try: self.file.replace_contents(current_contents, None, False, Gio.FileCreateFlags.NONE, None) print("saved: " + self.file.get_path()) except GObject.GError as e: print("Error: " + e.message) # if the contents are empty else: # create (if the file does not exist) or overwrite the file in readwrite mode. # arguments: etags, make_backup, flags, GError try: self.file.replace_readwrite(None, False, Gio.FileCreateFlags.NONE, None) print("saved: " + self.file.get_path()) except GObject.GError as e: print("Error: " + e.message)

class MyApplication(Gtk.Application):

def __init__(self): Gtk.Application.__init__(self)

def do_activate(self): win = MyWindow(self) win.show_all()

def do_startup(self): Gtk.Application.do_startup(self)

# app action quit, connected to the callback function quit_action = Gio.SimpleAction.new("quit", None) quit_action.connect("activate", self.quit_callback) self.add_action(quit_action)

# get the menu from the ui file with a builder builder = Gtk.Builder() try: builder.add_from_file("filechooserdialog.ui") except: print("file not found") sys.exit() menu = builder.get_object("appmenu") self.set_app_menu(menu)

# callback function for quit def quit_callback(self, action, parameter): self.quit()

app = MyApplication() exit_status = app.run(sys.argv) sys.exit(exit_status)

# FileChooserDialog에 쓸만한 메서드

참고로 FileChooserDialog 동작은 `Gtk.FileChooserAction.OPEN`(사용자가 기존 파일을 선택하기만 할 수 있음) `Gtk.FileChooserAction.SAVE`(사용자가 기존 파일을 선택하거나, 새 파일 이름을 입력할 수 있음), `Gtk.FileChooserAction.SELECT_FOLDER`(사용자가 기존 폴더를 선택하기만 할 수 있음), `Gtk.FileChooserAction.CREATE_FOLDER`(사용자가 기존 폴더를 선택하거나, 새 폴더 이름을 입력할 수 있음) 중 하나일 수 있습니다.

에서 사용한 메서드 주변을 보자면:

`set_show_hidden(True)` 함수로 숨김 파일과 숨김 폴더를 나타냈습니다.

`set_select_multiple(True)` 함수로 여러 파일을 선택할 수 있게 했습니다. `Gtk.FileChooserAction.OPEN` 또는 `Gtk.FileChooserAction.SELECT_FOLDER` 모드일 때만 가능합니다.

"다른 이름으로 저장" 대화 상자에서 `set_current_name(current_name)` 함수로 파일 선택 창의 `current_name`을 마치 사용자가 입력한 것처럼 설정했습니다. `current_name` 값은 Untitled.txt와 같은 값이 될 수 있습니다. 이 메서드는 "다른 이름으로 저장" 대화상자를 제외하고느 사용하지 않는게 좋습니다.

기본 현재 폴더는 "최근 항목" 입니다. 다른 폴더를 지정하려면 `set_current_folder_uri(uri)` 함수를 사용하십시오. 그러나 참고로 "다른 이름으로 저장" 명령을 사용하거나 이미 파일을 어딘가에 저장했을 경우에만 이 메서드를 사용하여 파일 선택 대화상자를 통해 지정 폴더를 나타내야합니다.

# API 참고서

이 예제는 다음 참고자료가 필요합니다:

GtkFileChooserDialog

GtkFileChooser

GtkWindow

GtkTextView

GtkTextBuffer

GtkScrolledWindow

GFile

GSimpleAction

GtkBuilder