ホーム
C/C++チュートリアル
テキストエディタ
-
テキストビュー(textview)というウィジェットを使って
テキストエディタを作っています。
-
すでに存在するファイルを書き換えて保存する時には、
ダイアログが出ないようにしました。
-
未保存のファイルがある場合に、
新規ファイルや既存のファイルを開こうとしようとした時に、
保存するかどうかの確認メッセージが出るようにしました。
-
未保存のファイルがある場合でも、
ウィンドウを閉じた時には保存するかどうかの確認メッセージは出ません。
どうやって確認メッセージを出すか模索中です。
-
コピー、カット、ペーストについては、右クリックするとコンテキストメニューが出ます。
これはプログラムしたものではなく、
テキストビューにそういう機能が備わっているみたいです。
-
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);
}
Posted: Jan. 09, 2020
Update: Jan. 10, 2020