GTK3   テキストエディタ

ホーム   C/C++チュートリアル


テキストエディタ


  1. テキストビュー(textview)というウィジェットを使って テキストエディタを作っています。
  2. すでに存在するファイルを書き換えて保存する時には、 ダイアログが出ないようにしました。
  3. 未保存のファイルがある場合に、 新規ファイルや既存のファイルを開こうとしようとした時に、
    保存するかどうかの確認メッセージが出るようにしました。
  4. 未保存のファイルがある場合でも、 ウィンドウを閉じた時には保存するかどうかの確認メッセージは出ません。
    どうやって確認メッセージを出すか模索中です。
  5. コピー、カット、ペーストについては、右クリックするとコンテキストメニューが出ます。
    これはプログラムしたものではなく、 テキストビューにそういう機能が備わっているみたいです。
  6. Windows XP、macOS 10.11、Fedora 28、Ubuntu 16.04、Mint 18 以降に対応しています。

texteditor.c


/*************************************
    texteditor.c
    copyright    :  vivacocoa.jp
    last modified:  Jan. 10, 2020
************************************/

#include <gtk/gtk.h>
#include <string.h>     // for strcmp

    /*  Prototypes      */
void    activate();
void    new_file();
void    open_file();
void    save_file();
void    change_buffer();
void    close_buffer();
void    comfirm_save();

    /*  Global Variables*/
GtkWidget   *window;
char        *filename   =   "";
gint        edited      =   FALSE;

int     main(int argc, char **argv)
{
    GtkApplication  *app;
    guchar          status;
    
    app     =   gtk_application_new ("jp.vivacocoa.texteditor", 0   );
    g_signal_connect    (app, "activate", G_CALLBACK(activate), NULL);
    status  =   g_application_run   (G_APPLICATION(app),  argc, argv);
    g_object_unref                  (app);
    return  status;
}

void    activate(GtkApplication *app, gpointer data)
{
    GtkWidget       *vbox;
    GtkWidget       *menubar;
    GtkWidget       *menu;
    GtkWidget       *fileitem;
    GtkWidget       *newitem;
    GtkWidget       *openitem;
    GtkWidget       *saveitem;
    GtkWidget       *separator;
    GtkWidget       *quititem;
    GtkWidget       *textview;
    GtkWidget       *scroll;
    GtkTextBuffer   *buffer;
    GtkAccelGroup   *accel_group;
    
    /*  Window          */
    window  =
    gtk_application_window_new      (app);
    gtk_window_set_title            (GTK_WINDOW(window),"TextEditor");
    gtk_window_set_default_size     (GTK_WINDOW(window),    300, 200);
    gtk_window_set_position         (GTK_WINDOW(window),    1       );
    
    /*  Container       */
    vbox    =   gtk_box_new         (GTK_ORIENTATION_VERTICAL,  0   );
    gtk_container_add               (GTK_CONTAINER(window),     vbox);
    
    /*  MenuBar         */
    menubar =   gtk_menu_bar_new    ();
    menu    =   gtk_menu_new        ();
    fileitem
    =   gtk_menu_item_new_with_label("File");
    gtk_menu_shell_append           (GTK_MENU_SHELL(menubar),fileitem);
    gtk_menu_item_set_submenu       (GTK_MENU_ITEM(fileitem), menu   );
    
    /*  MenuItems       */
    newitem
    =   gtk_menu_item_new_with_label("New");
    openitem
    =   gtk_menu_item_new_with_label("Open");
    saveitem
    =   gtk_menu_item_new_with_label("Save");
    separator
    =   gtk_separator_menu_item_new ();
    quititem
    =   gtk_menu_item_new_with_label("Quit");
    gtk_menu_shell_append           (GTK_MENU_SHELL(menu),  newitem );
    gtk_menu_shell_append           (GTK_MENU_SHELL(menu),  openitem);
    gtk_menu_shell_append           (GTK_MENU_SHELL(menu),  saveitem);
    gtk_menu_shell_append           (GTK_MENU_SHELL(menu), separator);
    gtk_menu_shell_append           (GTK_MENU_SHELL(menu),  quititem);
    
    /*  TextView        */
    textview
     =  gtk_text_view_new           ();
    scroll
    =  gtk_scrolled_window_new      (NULL,  NULL                    );
    gtk_scrolled_window_set_policy  (GTK_SCROLLED_WINDOW(scroll),1,1);
    gtk_text_view_set_monospace     (GTK_TEXT_VIEW(textview),   TRUE);
    buffer
    =  gtk_text_view_get_buffer     (GTK_TEXT_VIEW(textview)        );
    gtk_container_add               (GTK_CONTAINER(scroll), textview);
     
    /*  Pack to box     */
    gtk_box_pack_start              (GTK_BOX(vbox), menubar, 0, 0, 0);
    gtk_box_pack_end                (GTK_BOX(vbox), scroll , 1, 1, 0);
    
    /*  Accel group     */
    accel_group
    =   gtk_accel_group_new         ();
    gtk_window_add_accel_group      (GTK_WINDOW(window), accel_group);
    gtk_widget_add_accelerator      (newitem ,"activate",accel_group,
                                     GDK_KEY_n, GDK_CONTROL_MASK, 1 );
    gtk_widget_add_accelerator      (openitem,"activate",accel_group,
                                     GDK_KEY_o, GDK_CONTROL_MASK, 1 );
    gtk_widget_add_accelerator      (saveitem,"activate",accel_group,
                                     GDK_KEY_s, GDK_CONTROL_MASK, 1 );
    gtk_widget_add_accelerator      (quititem,"activate",accel_group,
                                     GDK_KEY_q, GDK_CONTROL_MASK, 1 );
    
    /*  Signals         */
    g_signal_connect                (newitem ,  "activate",
                                     G_CALLBACK(new_file) , buffer  );
    g_signal_connect                (openitem,  "activate",
                                     G_CALLBACK(open_file), buffer  );
    g_signal_connect                (saveitem,  "activate",
                                     G_CALLBACK(save_file), buffer  );
    g_signal_connect                (quititem,  "activate",
                                     G_CALLBACK(close_buffer),buffer);
    g_signal_connect                (buffer  ,  "changed",
                                     G_CALLBACK(change_buffer), NULL);
    
    /*  Show window     */
    gtk_widget_show_all             (window);
}

    /*  New file        */
void    new_file(GtkWidget *widget, gpointer buffer)
{
    if (edited) comfirm_save(buffer);
    
    filename    =   "Untitled";
    gtk_text_buffer_set_text        (buffer,    "", -1              );
    gtk_window_set_title            (GTK_WINDOW(window),    filename);
    edited      =   FALSE;
}

    /*  Open file       */
void    open_file(GtkWidget *widget, gpointer buffer)
{
    if (edited) comfirm_save(buffer);
    
    gint        result;
    GtkWidget   *dialog
    =   gtk_file_chooser_dialog_new ("Open File", GTK_WINDOW(window ),
                                     0, "Cancel", -6, "Open", -3,
                                     NULL                           );
    result  =   gtk_dialog_run      (GTK_DIALOG(dialog)             );
    if (result == -3)
    {
        gchar   *contents;
        gsize   length;
        GtkFileChooser  *chooser
        =   GTK_FILE_CHOOSER        (dialog);
        filename
        =   gtk_file_chooser_get_filename
                                    (chooser);
        GFile   *file
        =   g_file_new_for_path     (filename);
        gchar   *basename
        =   g_file_get_basename     (file);
        if (g_file_load_contents
           (file, NULL, &contents, &length, NULL, NULL)             )
        {
            gtk_text_buffer_set_text(buffer, contents, length       );
            gtk_window_set_title(GTK_WINDOW(window),    basename    );
            edited  =   FALSE;
        }
        g_free(contents);
        g_free(basename);
    }
    gtk_widget_destroy(dialog);
}

    /* Save file        */
void    save_file(GtkWidget *widget, gpointer buffer)
{
    if (edited && strcmp("Untitled", filename))
    {
        GtkTextIter startiter, enditer;
        gtk_text_buffer_get_start_iter  (buffer, &startiter );
        gtk_text_buffer_get_end_iter    (buffer, &enditer   );
        gchar   *contents
        =   gtk_text_buffer_get_text    (buffer, &startiter,
                                         &enditer, FALSE    );
        GFile   *file
        =   g_file_new_for_path         (filename           );
        gchar   *basename
        =   g_file_get_basename         (file               );
        if (g_file_replace_contents         (file, contents,
                                         strlen(contents),
                                         NULL, FALSE,
                                         G_FILE_CREATE_NONE,
                                         NULL, NULL, NULL   ))
        {
            edited  =   FALSE;
            gtk_window_set_title    (GTK_WINDOW(window), basename   );
        }   
        g_free(contents);
        g_free(basename);
    } else if (edited)
    {
        gint        result;
        GtkWidget   *dialog
        =   gtk_file_chooser_dialog_new ("Save File",
                                         GTK_WINDOW(window ),   1,
                                         "Cancel", -6, "Save", -3,
                                        NULL                        );
        result  =   gtk_dialog_run      (GTK_DIALOG(dialog)         );
        if (result == -3)
        {
            GtkTextIter startiter, enditer;
            gtk_text_buffer_get_start_iter  (buffer, &startiter     );
            gtk_text_buffer_get_end_iter    (buffer, &enditer       );
            gchar   *contents
            =   gtk_text_buffer_get_text    (buffer, &startiter,
                                             &enditer, FALSE        );
            GtkFileChooser  *chooser
            =   GTK_FILE_CHOOSER            (dialog);
            gtk_file_chooser_set_do_overwrite_confirmation(chooser,1);
            gtk_file_chooser_set_current_name   (chooser, "Untitled");
            filename
            =   gtk_file_chooser_get_filename
                                            (chooser);
            GFile   *file
            =   g_file_new_for_path         (filename);
            gchar   *basename
            =   g_file_get_basename         (file);
            if (g_file_replace_contents     (file, contents,
                                             strlen(contents),
                                             NULL, FALSE,
                                             G_FILE_CREATE_NONE,
                                             NULL, NULL, NULL       ))
            {
                edited  =   FALSE;
                gtk_window_set_title    (GTK_WINDOW(window), basename);
            }
            g_free(contents);
            g_free(basename);
        }
        gtk_widget_destroy(dialog);
    }
}

    /*  Change buffer   */
void    change_buffer(GtkTextBuffer *buffer, gpointer data)
{
    if (!edited)
    {
        char    title[256];
        if (!strcmp(filename, ""))
        {
            filename    =   "Untitled";
            sprintf(title, "%s - edited", filename);
        } else {
            GFile   *file
            =   g_file_new_for_path (filename);
            gchar   *basename    =   g_file_get_basename (file);
            sprintf     (title, "%s - edited", basename);
            g_free(basename);
        }
        edited  =   TRUE;
        gtk_window_set_title    (GTK_WINDOW(window), title);
    }
}

    /* Close bufffer    */
void    close_buffer(GtkWidget widget, gpointer buffer)
{
    if (edited) comfirm_save(buffer);
    gtk_widget_destroy(window);
}

    /*  Comfirm save    */
void    comfirm_save(gpointer buffer)
{
    gint        result;
    GtkWidget   *dialog
    =   gtk_message_dialog_new      (GTK_WINDOW(window),
                                     GTK_DIALOG_DESTROY_WITH_PARENT,
                                     GTK_MESSAGE_QUESTION,
                                     GTK_BUTTONS_YES_NO,
                    "This file has changed. Do you want to save?"   );
    gtk_window_set_title            (GTK_WINDOW(dialog),
                                     filename);
    result  =   gtk_dialog_run      (GTK_DIALOG(dialog));
    gtk_widget_destroy              (dialog);
    if (result  == GTK_RESPONSE_YES) save_file(window,  buffer      );
}
    

実行結果

もう一つの形のsave_file


        /* Save file        */
void    save_file(GtkWidget *widget, gpointer buffer)
{
    GFile       *file;
    gchar       *basename;
    gchar       *contents;
    gsize       length;
    gint        result;
    GtkTextIter startiter, enditer;
    GtkWidget   *dialog
    =   gtk_file_chooser_dialog_new ("Save File", GTK_WINDOW(window),
                                     1, "Cancel", -6, "Save", -3,
                                     NULL                           );
    result  =   gtk_dialog_run      (GTK_DIALOG(dialog)             );
    if (result == -3)
    {
        gtk_text_buffer_get_start_iter
                                    (buffer, &startiter );
        gtk_text_buffer_get_end_iter
                                    (buffer, &enditer   );
        contents
        =   gtk_text_buffer_get_text(buffer, &startiter, &enditer, 0);
        GtkFileChooser  *chooser
        =   GTK_FILE_CHOOSER        (dialog);
        filename
        =   gtk_file_chooser_get_filename
                                    (chooser);
        file
        =   g_file_new_for_path     (filename);
        basename
        =   g_file_get_basename     (file);
        GFileOutputStream *output
        =   g_file_replace          (file, NULL, FALSE,
                                     G_FILE_CREATE_NONE, NULL, NULL );
        g_output_stream_write       (G_OUTPUT_STREAM(output),
                                     contents, strlen(contents),
                                     NULL, NULL);
        g_output_stream_close       (G_OUTPUT_STREAM(output),
                                     NULL, NULL);
        g_free(contents);
        gtk_window_set_title        (GTK_WINDOW(window), basename   );
        g_free(basename);
    }
    gtk_widget_destroy(dialog);
}
    



41098 visits
Posted: Jan. 09, 2020
Update: Jan. 10, 2020

ホーム   C/C++チュートリアル   目次