ruby-****@sourc*****
ruby-****@sourc*****
2009年 2月 8日 (日) 02:46:28 JST
------------------------- REMOTE_ADDR = 74.15.84.244 REMOTE_HOST = URL = http://ruby-gnome2.sourceforge.jp/hiki.cgi?tut-gtk2-txtw-tyu ------------------------- @@ -1,12 +1,198 @@ = The Text View Widget {{link "tut-gtk2-txtw-gsw", "tut-gtk2-txtw", "tut-gtk", nil}} -= Sorry this page is still under construction - == Test Your Understanding +We again reached the end of the session. So far we have learnt a lot, and it is time for us to try to tackle a more serious application. As always I encourage you to try to work through the exercise on your own. This exercise will let you practise interacting with a Gtk::TextView widget. Following are the specifications for our exercise application: +:Specs: + + Use the Gtk::Text View widget to create a simple text editor. You should provide the ability to perform multiple text editing functions, including creating a new document, opening a file, saving a file, searching the document, cutting, copying and pasting text. + + When creating a new document, you should make sure that this is really what user wants, because all changes will be lost, since this action should clear the screen, making it ready for new entry session. + {{image_right("txtw-tyu.png")}} {{br}} -((*simple-text-editor.rb*)) +((*childwidgets.rb*)) + + #!/usr/bin/env ruby + require 'gtk2' + + class TextEditor + attr_accessor :textview, :search + end + + # Verify that the user want to create a new document. + # If so, delete all of the text from the buffer. + def new_clicked(te) + dialog = Gtk::MessageDialog.new( + nil, + Gtk::Dialog::MODAL, + Gtk::MessageDialog::QUESTION, + Gtk::MessageDialog::BUTTONS_YES_NO, + "All changes will be lost. Do you want to continue?" + ) + dialog.title = "Information" + dialog.run do |r| + te.textview.buffer.text = "" if r == Gtk::Dialog::RESPONSE_YES + end + dialog.destroy + end + + # Replace the content of the current buffer with the + # content of a file. + def open_clicked(te) + dialog = Gtk::FileChooserDialog.new( + "Choose a file ...", + nil, + Gtk::FileChooser::ACTION_OPEN, + nil, + [ Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL ], + [ Gtk::Stock::APPLY, Gtk::Dialog::RESPONSE_APPLY ] + ) + dialog.run do |response| + if response == Gtk::Dialog::RESPONSE_APPLY + file = dialog.filename + content = IO.readlines(file) + te.textview.buffer.text = content.to_s + end + end + dialog.destroy + end + + # Save the content of the current buffer to a file. + def save_clicked(te) + + dialog = Gtk::FileChooserDialog.new( + "Save the file ...", + nil, + Gtk::FileChooser::ACTION_SAVE, + nil, + [ Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL ], + [ Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_APPLY ] + ) + dialog.run do |response| + if response == Gtk::Dialog::RESPONSE_APPLY + file = dialog.filename + content = te.textview.buffer.text + # Open for writing, write and close. + File.open(file, "w") { |f| f << content } + end + end + dialog.destroy + end + + # Copy the selected text to the clipboard and remove it from the buffer. + def cut_clicked(te) + clipboard = Gtk::Clipboard.get(Gdk::Selection::CLIPBOARD) + te.textview.buffer.cut_clipboard(clipboard, true) + end + + # Copy the selected text to the clipboard. + def copy_clicked(te) + clipboard = Gtk::Clipboard.get(Gdk::Selection::CLIPBOARD) + te.textview.buffer.copy_clipboard(clipboard) + end + + # Delete any selected text and insert the clipboard + # content into the document. + def paste_clicked(te) + clipboard = Gtk::Clipboard.get(Gdk::Selection::CLIPBOARD) + te.textview.buffer.paste_clipboard(clipboard, nil, true) + end + + # ------------------- + # Search for a text string from the current cursor position + # if there is no selected text, or one character after the + # cursor if there is. + def find_clicked(te) + find = te.search.text + first, last, success = te.textview.buffer.selection_bounds + + first = te.textview.buffer.start_iter unless success + + # forward_search(find, flags, limit=(nil==entire text buffer)) + first, last = first.forward_search(find, Gtk::TextIter::SEARCH_TEXT_ONLY, last) + + # Select the instance on the screen if the string is found. + # Otherwise, tell the user it has failed. + if (first) + mark = te.textview.buffer.create_mark(nil, first, false) + # Scrolls the Gtk::TextView the minimum distance so + # that mark is contained within the visible area. + te.textview.scroll_mark_onscreen(mark) + + te.textview.buffer.delete_mark(mark) + te.textview.buffer.select_range(first, last) + else + # Gtk::MessageDialog.new(parent, flags, message_type, button_type, message = nil) + dialogue = Gtk::MessageDialog.new( + nil, + Gtk::Dialog::MODAL, + Gtk::MessageDialog::INFO, + Gtk::MessageDialog::BUTTONS_OK, + "The text was not found!" + ) + dialogue.run + dialogue.destroy + end + first = last = nil # camcel any previous selections + end + + window = Gtk::Window.new(Gtk::Window::TOPLEVEL) + window.resizable = true + window.title = "Simple Text Editor" + window.border_width = 10 + window.signal_connect('delete_event') { Gtk.main_quit } + window.set_size_request(600, -1) + + ed = TextEditor.new + ed.textview = Gtk::TextView.new + ed.search = Gtk::Entry.new + ed.search.text = "Search for ..." + + new = Gtk::Button.new(Gtk::Stock::NEW) + open = Gtk::Button.new(Gtk::Stock::OPEN) + save = Gtk::Button.new(Gtk::Stock::SAVE) + cut = Gtk::Button.new(Gtk::Stock::CUT) + copy = Gtk::Button.new(Gtk::Stock::COPY) + paste = Gtk::Button.new(Gtk::Stock::PASTE) + find = Gtk::Button.new(Gtk::Stock::FIND) + + new.signal_connect("clicked") { |w| new_clicked(ed) } + open.signal_connect("clicked") { |w| open_clicked(ed) } + save.signal_connect("clicked") { |w| save_clicked(ed) } + cut.signal_connect("clicked") { |w| cut_clicked(ed) } + copy.signal_connect("clicked") { |w| copy_clicked(ed) } + paste.signal_connect("clicked") { |w| paste_clicked(ed) } + find.signal_connect("clicked") { |w| find_clicked(ed) } + + scrolled_win = Gtk::ScrolledWindow.new + scrolled_win.border_width = 5 + scrolled_win.add(ed.textview) + scrolled_win.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS) + + vbox = Gtk::VBox.new(true, 5) + vbox.pack_start(new, false, false, 0) + vbox.pack_start(open, false, false, 0) + vbox.pack_start(save, false, false, 0) + vbox.pack_start(cut, false, false, 0) + vbox.pack_start(copy, false, false, 0) + vbox.pack_start(paste, false, false, 0) + + searchbar = Gtk::HBox.new(false, 5) + searchbar.pack_start(ed.search, false, false, 0) + searchbar.pack_start(find, false, false, 0) + + table = Gtk::Table.new(2, 2, false) + + table.attach(scrolled_win, 0, 1, 0, 1, + Gtk::EXPAND | Gtk::FILL, Gtk::EXPAND | Gtk::FILL, 5, 5) + table.attach(vbox, 1, 2, 0, 1, + Gtk::SHRINK, Gtk::SHRINK, 5, 5) + table.attach(searchbar, 0, 1, 1, 2, + Gtk::FILL, Gtk::SHRINK, 5, 5) + window.add(table) + window.show_all + Gtk.main