Программирование проверки правописания: GTK+ и Qt
Содержание:
1.Проверка в GTK+ (Вы читаете данный раздел);
2. Проверка в Qt.
Данная статья посвящена использованию движка проверки правописания в графическом интерфейсе. «Движок» здесь в единственном числе, потому что оба популярных движка: Aspell и Hunspell - мы уже рассмотрели и могли убедиться, что они весьма похожи по набору функций и подходу к работе. Поэтому в примерах к этой статье там, где надо вызывать функции конкретного движка, будет использован псевдокод.
Кстати, в любом случае полезно написать свой класс-оболочку или набор функций-оберток, заключив в них вызов средств конкретного движка. Почему? Если вы задумаете вдруг сменить один движок на другой, необходимо будет переписать лишь «прослойку», не меняя остальной код. В ООП вообще хорошо бы сделать полностью абстрактный класс проверки правописания, а затем унаследовать от него воплощение некоего движка или движков. Таким образом, «переписывание» прослойки превратится в «дописывание», и появится возможность использовать даже несколько движков одновременно, задействовав механизм полиморфизма: объявили переменную типа класса-предка, присвоили ей экземпляр класса-потомка - и вперед.
Итак, проверку правописания условно разделим на фоновую и активную. Фоновая - когда пользователь набирает текст, а ошибочные слова как-то оформляются - чаще всего подчеркиваются красной линией. Активная - когда пользователь видит окно с интерфейсом, дающим возможность делать последовательный перебор слов, выбор вариантов замены и тому подобное.
В первом случае алгоритм примерно таков: после любой правки берем текущее слово и проверяем его правописание. Если слова в словаре нет - подчеркиваем слово. Когда именно осуществляется проверка: по таймеру через определенный промежуток времени или сразу после нажатия клавиш - дело стороннее. Активная форма проверки подразумевает последовательный перебор текста по словам. Текст предоставляется текстовым виджетом. Для примера в этой статье объединим обе формы проверки. У нас будет некий виджет с текстом, мы перебираем в нем все слова и подчеркиваем ошибочные. Так мы проиллюстрируем оба важных механизма: и подчеркивание, и перебор. Примеры будут основаны на библиотеках GTK+ 2 (для языка С) и Qt (конечно же, для C++).
Сначала обратимся к GTK+. Предполагаю, что вы имеете некоторый опыт работы с ее текстовыми виджетами, в частности с парой GtkTextBuffer и GtkTextView. Изложенные ниже алгоритмы работают и с движком GtkSourceView (http://projects.gnome.org/gtksourceview), но с некоторыми оговорками (разница в типах). В GTK+ подсветка как визуальное средство зиждется на применении тегов. Поэтому сначала - таблица тегов: создаем тег, назначаем ему свойства (цвет и тому подобное), помещаем в таблицу, а таблицу назначаем буферу GtkTextBuffer. Функция создания такой таблицы:
Теперь создадим пару буфер-виджет GtkTextBuffer/GtkTextView и привяжем к ней таблицу:
Затем, в ходе подготовки к проверке правописания, нам понадобится служебная функция, удаляющая из буфера всю цветовую разметку, заданную тегом под именем «spell_err». Но сначала напишем макрос, который подставляет вместо себя код, вызывающий функции для получения экземпляра тега из таблицы (по заданному имени). Делаем его макросом, потому что он еще пригодится.
В итераторы itstart и itend мы получаем начало и конец буфера. Затем вызываем gtk_text_buffer_remove_tag, чтобы удалить из буфера такой-то тег в пределах таких-то итераторов.
Приступим к написанию самой функции проверки правописания. Здесь будет использована только одна функция на псевдокоде - ПРОВЕРИТЬ_ПРАВОПИСАНИЕ (gchar *text) - аналог функции проверки правописания конкретного движка.
Вы не программист, а яростный поклонник современных технологий? Что ж, в таком случае я рекомендую Вам Iphone 6 купить (http://trafficcost.ru/541fe9128b30a8f7368b4575/subaccount)! Это наиболее технологичное мобильное электронное устройство, которое Вы только можете найти в свободной продаже!
1.
2. Проверка в Qt.
Данная статья посвящена использованию движка проверки правописания в графическом интерфейсе. «Движок» здесь в единственном числе, потому что оба популярных движка: Aspell и Hunspell - мы уже рассмотрели и могли убедиться, что они весьма похожи по набору функций и подходу к работе. Поэтому в примерах к этой статье там, где надо вызывать функции конкретного движка, будет использован псевдокод.
Кстати, в любом случае полезно написать свой класс-оболочку или набор функций-оберток, заключив в них вызов средств конкретного движка. Почему? Если вы задумаете вдруг сменить один движок на другой, необходимо будет переписать лишь «прослойку», не меняя остальной код. В ООП вообще хорошо бы сделать полностью абстрактный класс проверки правописания, а затем унаследовать от него воплощение некоего движка или движков. Таким образом, «переписывание» прослойки превратится в «дописывание», и появится возможность использовать даже несколько движков одновременно, задействовав механизм полиморфизма: объявили переменную типа класса-предка, присвоили ей экземпляр класса-потомка - и вперед.
Итак, проверку правописания условно разделим на фоновую и активную. Фоновая - когда пользователь набирает текст, а ошибочные слова как-то оформляются - чаще всего подчеркиваются красной линией. Активная - когда пользователь видит окно с интерфейсом, дающим возможность делать последовательный перебор слов, выбор вариантов замены и тому подобное.
В первом случае алгоритм примерно таков: после любой правки берем текущее слово и проверяем его правописание. Если слова в словаре нет - подчеркиваем слово. Когда именно осуществляется проверка: по таймеру через определенный промежуток времени или сразу после нажатия клавиш - дело стороннее. Активная форма проверки подразумевает последовательный перебор текста по словам. Текст предоставляется текстовым виджетом. Для примера в этой статье объединим обе формы проверки. У нас будет некий виджет с текстом, мы перебираем в нем все слова и подчеркиваем ошибочные. Так мы проиллюстрируем оба важных механизма: и подчеркивание, и перебор. Примеры будут основаны на библиотеках GTK+ 2 (для языка С) и Qt (конечно же, для C++).
Проверка в GTK+
Сначала обратимся к GTK+. Предполагаю, что вы имеете некоторый опыт работы с ее текстовыми виджетами, в частности с парой GtkTextBuffer и GtkTextView. Изложенные ниже алгоритмы работают и с движком GtkSourceView (http://projects.gnome.org/gtksourceview), но с некоторыми оговорками (разница в типах). В GTK+ подсветка как визуальное средство зиждется на применении тегов. Поэтому сначала - таблица тегов: создаем тег, назначаем ему свойства (цвет и тому подобное), помещаем в таблицу, а таблицу назначаем буферу GtkTextBuffer. Функция создания такой таблицы:
GtkTextTagTable* create _ tags _ table (void) {
// создаем тег с названием "spell _ err"
GtkTextTag *tag _ spell _ err = gtk _ text _ tag _ new ("spell _ err");
// назначаем ему красный цвет
g_ object _ set (G_ OBJECT (tag _ spell _ err), "foreground",
"#ff0000", NULL);
// ... и способ подчеркивания (PANGO _ UNDERLINE _ ERROR) g_ object _ set (G_ OBJECT (tag _ spell _ err), "underline",
PANGO _ UNDERLINE _ ERROR, NULL);
// теперь создаем таблицу
GtkTextTagTable *tags _ table = gtk _ text _ tag _ table _ new (); // и помещаем в нее созданный тег
gtk _text _tag _table _add (tags _table, tag _spell _err);
// все, возвращаем таблицу return tags _ table;
}
// создаем тег с названием "spell _ err"
GtkTextTag *tag _ spell _ err = gtk _ text _ tag _ new ("spell _ err");
// назначаем ему красный цвет
g_ object _ set (G_ OBJECT (tag _ spell _ err), "foreground",
"#ff0000", NULL);
// ... и способ подчеркивания (PANGO _ UNDERLINE _ ERROR) g_ object _ set (G_ OBJECT (tag _ spell _ err), "underline",
PANGO _ UNDERLINE _ ERROR, NULL);
// теперь создаем таблицу
GtkTextTagTable *tags _ table = gtk _ text _ tag _ table _ new (); // и помещаем в нее созданный тег
gtk _text _tag _table _add (tags _table, tag _spell _err);
// все, возвращаем таблицу return tags _ table;
}
Теперь создадим пару буфер-виджет GtkTextBuffer/GtkTextView и привяжем к ней таблицу:
GtkTextView *text_view = gtk _ text _ view _ new(); GtkTextBuffer *text _ buffer =
gtk _ text _ buffer _ new (create _ tags _ table ());
gtk _text _view _set _buffer (text _view, text _buffer);
gtk _ text _ buffer _ new (create _ tags _ table ());
gtk _text _view _set _buffer (text _view, text _buffer);
Затем, в ходе подготовки к проверке правописания, нам понадобится служебная функция, удаляющая из буфера всю цветовую разметку, заданную тегом под именем «spell_err». Но сначала напишем макрос, который подставляет вместо себя код, вызывающий функции для получения экземпляра тега из таблицы (по заданному имени). Делаем его макросом, потому что он еще пригодится.
#define get _ tag _ by _ name(text _ buffer,name)
gtk _text _tag _table _lookup(
gtk _text _ buffer _ get _tag _table(text _ buffer) ,name)
Теперь - уже упомянутая функция:
void hide _ error _ marks (GtkTextBuffer *text _ buffer) {
GtkTextIter itstart, itend;
gtk _ text _ buffer _ get _ bounds (text _ buffer, Sitstart, Sitend);
gtk _text _buffer _remove _tag (text _buffer,
get _tag _by _name (text _ buffer, "spell _err"),
Sitstart, Sitend);
}
gtk _text _tag _table _lookup(
gtk _text _ buffer _ get _tag _table(text _ buffer) ,name)
Теперь - уже упомянутая функция:
void hide _ error _ marks (GtkTextBuffer *text _ buffer) {
GtkTextIter itstart, itend;
gtk _ text _ buffer _ get _ bounds (text _ buffer, Sitstart, Sitend);
gtk _text _buffer _remove _tag (text _buffer,
get _tag _by _name (text _ buffer, "spell _err"),
Sitstart, Sitend);
}
В итераторы itstart и itend мы получаем начало и конец буфера. Затем вызываем gtk_text_buffer_remove_tag, чтобы удалить из буфера такой-то тег в пределах таких-то итераторов.
Приступим к написанию самой функции проверки правописания. Здесь будет использована только одна функция на псевдокоде - ПРОВЕРИТЬ_ПРАВОПИСАНИЕ (gchar *text) - аналог функции проверки правописания конкретного движка.
void do _ hl _ spell _ check (GtkTextBuffer *text _ buffer) {
GtkTextIter iter; GtkTextIter a; GtkTextIter b;
gchar *p = NULL; gchar *text;
// удаляем всю «ошибочную» подсветку, если
// таковая уже присутствует:
hide _ error _ marks (text _ buffer);
// получаем итератор начала буфера:
gtk _ text _ buffer _ get _ iter _ at _ offset (text _ buffer,
Siter, 0);
// если на итераторе iter начинается слово, // присваиваем итератору a положение итератора iter: if (gtk _ text _ iter _ starts _ word (Siter)) a = iter;
// входим в цикл проверки, с пословным перебором // содержимого буфера:
do
{
if (gtk _text _iter _starts _word (Siter)) {
b = iter;
if (gtk _text _iter _backward _char (Sb)) a = iter;
if (gtk _text _iter _forward _word _end (Siter)) if (gtk _text _iter _ends _word (Siter)) {
// получаем текущее (в переборе) слово:
text = gtk _ text _ iter _ get _ slice (Sa, Siter);
// если оно не NULL
if (text)
{
// и если длина его больше 1 if (g _ utf 8 _ strlen (text, -1) > 1) {
// то проверяем правописание: if (! ПРОВЕРИТЬ _ ПРАВОПИСАНИЕ (text)) {
// при ошибочности слова применяем тег
// к тексту между текущими итераторами:
gtk _ text _ buffer _ apply _ tag (
text _ buffer, get _ tag _ by _ name
(text _ buffer, "spell _ err"),
Sa, Siter); g _ free (text);
continue;
}
}
g _ free (text);
}
}
}
}
while (gtk _text _iter _forward _char (Siter));
}
GtkTextIter iter; GtkTextIter a; GtkTextIter b;
gchar *p = NULL; gchar *text;
// удаляем всю «ошибочную» подсветку, если
// таковая уже присутствует:
hide _ error _ marks (text _ buffer);
// получаем итератор начала буфера:
gtk _ text _ buffer _ get _ iter _ at _ offset (text _ buffer,
Siter, 0);
// если на итераторе iter начинается слово, // присваиваем итератору a положение итератора iter: if (gtk _ text _ iter _ starts _ word (Siter)) a = iter;
// входим в цикл проверки, с пословным перебором // содержимого буфера:
do
{
if (gtk _text _iter _starts _word (Siter)) {
b = iter;
if (gtk _text _iter _backward _char (Sb)) a = iter;
if (gtk _text _iter _forward _word _end (Siter)) if (gtk _text _iter _ends _word (Siter)) {
// получаем текущее (в переборе) слово:
text = gtk _ text _ iter _ get _ slice (Sa, Siter);
// если оно не NULL
if (text)
{
// и если длина его больше 1 if (g _ utf 8 _ strlen (text, -1) > 1) {
// то проверяем правописание: if (! ПРОВЕРИТЬ _ ПРАВОПИСАНИЕ (text)) {
// при ошибочности слова применяем тег
// к тексту между текущими итераторами:
gtk _ text _ buffer _ apply _ tag (
text _ buffer, get _ tag _ by _ name
(text _ buffer, "spell _ err"),
Sa, Siter); g _ free (text);
continue;
}
}
g _ free (text);
}
}
}
}
while (gtk _text _iter _forward _char (Siter));
}
Вы не программист, а яростный поклонник современных технологий? Что ж, в таком случае я рекомендую Вам Iphone 6 купить (http://trafficcost.ru/541fe9128b30a8f7368b4575/subaccount)! Это наиболее технологичное мобильное электронное устройство, которое Вы только можете найти в свободной продаже!