В этом посте я расскажу о простом блокноте на языке программирования Vala. Программа создавалась с использованием среды разработки GNOME Builder и редактора интерфейсов Glade.
Внешний вид
Вот так приложение выглядит:
Слева можно видеть список всех заметок, которые автоматически сохраняются в специальной папке. Имя по умолчанию для любой заметки имеет вид даты и времени ее создания. Нажав на последнюю кнопку в хидербаре, можно назначить другое имя. Исходный код приложения находится здесь.
Иерархия элементов интерфейса в редакторе Glade:
Создание заметки
Нажав на первую кнопку, пользователь сразу же создает заметку с именем по умолчанию. За это отвечает следующий метод:
private void on_add_clicked(){
GLib.File file = GLib.File.new_for_path(directory_path+"/"+date_time());
try {
FileUtils.set_contents (file.get_path(), "");//создаем пустой файл
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
if(!is_empty(text_view.buffer.text)){
text_view.buffer.text = "";
}
show_notes();//показываем список заметок
}
Метод date_time
, который дает имя заметке:
private string date_time(){
var now = new DateTime.now_local ();
return now.format("%d")+"."+now.format("%m")+"."+now.format("%Y")+" "+now.format("%H")+":"+now.format("%M")+":"+now.format("%S");
}
Идем дальше. Метод для показа списка:
private void show_notes () {
list_store.clear();
list = new GLib.List<string> ();
try {
Dir dir = Dir.open (directory_path, 0);
string? file_name = null;
while ((file_name = dir.read_name ()) != null) {
list.append(file_name);
}
} catch (FileError err) {
stderr.printf (err.message);
}
Gtk.TreeIter iter;
foreach (string item in list) {
list_store.append(out iter);
list_store.set(iter, Columns.TEXT, item);
}
}
Метод вызывается каждый раз, когда нужно обновить список.
Удаление заметки
За удаление заметок отвечает вот такой метод:
private void on_delete_clicked(){
var selection = tree_view.get_selection();
selection.set_mode(Gtk.SelectionMode.SINGLE);
Gtk.TreeModel model;
Gtk.TreeIter iter;
if (!selection.get_selected(out model, out iter)) {
alert("Choose a note");
return;
}
GLib.File file = GLib.File.new_for_path(directory_path+"/"+item);
var dialog_delete_file = new Gtk.MessageDialog(this, Gtk.DialogFlags.MODAL,Gtk.MessageType.QUESTION, Gtk.ButtonsType.OK_CANCEL, "Delete note "+file.get_basename()+" ?");
dialog_delete_file.set_title("Question");
Gtk.ResponseType result = (Gtk.ResponseType)dialog_delete_file.run ();
dialog_delete_file.destroy();
if(result==Gtk.ResponseType.OK){
FileUtils.remove (directory_path+"/"+item);//удаляем файл
if(file.query_exists()){
alert("Delete failed");//не получилось удалить
}else{
show_notes();
text_view.buffer.text = "";//очищаем текстовую область
}
}
}
Удаление происходит только после подтверждения этого действия пользователем.
Сохранение заметок
Для сохранение заметок существует следующий код:
private void on_save_clicked(){
var selection = tree_view.get_selection();
selection.set_mode(Gtk.SelectionMode.SINGLE);
Gtk.TreeModel model;
Gtk.TreeIter iter;
if (!selection.get_selected(out model, out iter)) {
alert("Choose a note");
return;
}
if(is_empty(text_view.buffer.text)){
alert("Nothing to save");
return;
}
GLib.File file = GLib.File.new_for_path(directory_path+"/"+item);
var dialog_save_file = new Gtk.MessageDialog(this, Gtk.DialogFlags.MODAL,Gtk.MessageType.QUESTION, Gtk.ButtonsType.OK_CANCEL, "Save note "+file.get_basename()+" ?");
dialog_save_file.set_title("Question");
Gtk.ResponseType result = (Gtk.ResponseType)dialog_save_file.run ();
if(result==Gtk.ResponseType.OK){
try {
FileUtils.set_contents (file.get_path(), text_view.buffer.text);//записываем в файл содержимое текстовой области
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
show_notes();
}
dialog_save_file.destroy();
}
Здесь, при сохранении сначала идет проверка, а есть ли вообще, что сохранять. В случае, если текст не обнаружен, пользователь получает соответствующее сообщение.
Сохранение заметок под другим именем
Для того чтобы поменять имя заметки используется такой метод:
private void on_save_as_clicked(){
var selection = tree_view.get_selection();
selection.set_mode(Gtk.SelectionMode.SINGLE);
Gtk.TreeModel model;
Gtk.TreeIter iter;
if (!selection.get_selected(out model, out iter)) {
alert("Choose a note");//нужно выбрать заметку из списка
return;
}
if(is_empty(text_view.buffer.text)){
alert("Nothing to save");//нечего сохранять
return;
}
var dialog_save_note = new Gtk.Dialog.with_buttons ("Save note", this, Gtk.DialogFlags.MODAL);
var content_area = dialog_save_note.get_content_area ();
entry_name = new Gtk.Entry();
var label_name = new Gtk.Label.with_mnemonic ("_Name:");
var hbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 20);
hbox.set_border_width(15);
hbox.pack_start (label_name, false, true, 0);
hbox.pack_start (entry_name, true, true, 0);
content_area.add (hbox);
dialog_save_note.add_button ("OK", Gtk.ResponseType.OK);
dialog_save_note.add_button ("CLOSE", Gtk.ResponseType.CLOSE);
dialog_save_note.response.connect (on_save_response);
dialog_save_note.show_all ();
}
В вышеприведенном коде создается простенькое диалоговое окно для ввода нового имени заметки:
Для обработки нажатий на кнопки OK и CLOSE понадобится метод on_save_response
:
private void on_save_response (Gtk.Dialog dialog, int response_id) {
switch (response_id) {
case Gtk.ResponseType.OK:
if(is_empty(entry_name.get_text())){
alert("Enter the name");//нужно ввести имя
entry_name.grab_focus();
return;
}
GLib.File select_file = GLib.File.new_for_path(directory_path+"/"+item);
GLib.File edit_file = GLib.File.new_for_path(directory_path+"/"+entry_name.get_text().strip());
if (select_file.get_basename() != edit_file.get_basename() && !edit_file.query_exists()){
FileUtils.rename(select_file.get_path(), edit_file.get_path());//переименовываем файл
if(!edit_file.query_exists()){
alert("Rename failed");//не получилось переименовать
return;
}
try {
FileUtils.set_contents (edit_file.get_path(), text_view.buffer.text);
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
}else{
if (select_file.get_basename() != edit_file.get_basename()) {
alert("A note with the same name already exists");//такое имя уже есть
entry_name.grab_focus();
return;
}
try {
FileUtils.set_contents (edit_file.get_path(), text_view.buffer.text);
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
}
show_notes();
dialog.destroy();
break;
case Gtk.ResponseType.CLOSE:
dialog.destroy();
break;
case Gtk.ResponseType.DELETE_EVENT:
dialog.destroy();
break;
}
}
Обязательно нужно проверить существует ли заметка с таким же именем и если существует, то предложить пользователю ввести другое имя.
Отображение текста заметки
Чтобы показать содержимое заметки используется такой код:
private void on_select_item () {
var selection = tree_view.get_selection();
selection.set_mode(Gtk.SelectionMode.SINGLE);
Gtk.TreeModel model;
Gtk.TreeIter iter;
if (!selection.get_selected(out model, out iter)) {
return;
}
Gtk.TreePath path = model.get_path(iter);
var index = int.parse(path.to_string());
if (index >= 0) {
item = list.nth_data(index);
}
string text;
try {
FileUtils.get_contents (directory_path+"/"+item, out text);
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
text_view.buffer.text = text;//показываем текст заметки
}
На этом все! До встречи в следующих постах!
Дата-центр ITSOFT — размещение и аренда серверов и стоек в двух дата-центрах в Москве. За последние годы UPTIME 100%. Размещение GPU-ферм и ASIC-майнеров, аренда GPU-серверов, лицензии связи, SSL-сертификаты, администрирование серверов и поддержка сайтов.
EvilGenius18
Все Линукс системы идут с Python языком, чем он не угодил?
Зачем создавать еще один язык программирования для этого?
Не понимаю этого тренда. Есть у вас велосипед, так улучшайте его всем миром, но зачем каждый день создавать новый велосипед с нуля, который делает то же самое? Вот и получается, что у нас миллион разных фиговеньких языков программирования, вместо 3 офигенных, которые могут все, для которых есть все нужные библиотеки и, которые работают во все средах на любом железе
BOOTLOADER
Это специальный язык для создания блокнотов :))))
Автору спасибо. Узнал, что есть ещё один язык.
denvist
Его как минимум Elementary OS использует в своих наработках. Получается вполне годно.
DreamingKitten
Vala транспилируется в C и плотно завязан на GLib, так что с библиотеками там всё ок. И не сказать, чтобы он сильно новый — 15 лет как уже.
cbelkin
Довольно таки неплохо. В Python у меня был опыт с двумя тулкитами, поддерживающими нативный интерфейс системы: PyQt и PySide. Оба этих пакета используют биндинги на Qt фреймворк, а он, как известно, отрисовывает окна в нативном стиле.
К тому же эти пакеты различаются типом лицензирования, поэтому можно выбрать ту, что наиболее подходит при конкретной разработке. Поэтому возможность разрабатывать GUI приложения на Python существует. При том без танцев с бубном.
Другой вопрос, что сама разработка GUI приложений на Python является экзотикой и является весьма спорной с эстетической точки зрения.
maxzhurkin
Вообще говоря, этот язык появился давно и был создан для упрощения разработки отдельных приложений для GNOME, так что вы немного (лет примерно на 15) опоздали
cbelkin
Поскольку у самого ядра нет бинарной зависимости от Python, то не все дистрибутивы включают интерпретатор по-умолчанию. Отсюда в минималистичных дистрибутивах (таких как ArchLinux, Gentoo и тем более LFS) вполне можно работать без Python. К FreeBSD это, кстати, тоже относится.
Пару лет просидел на ArchLinux. И помнится, что даже когда накатывал GUI (чаще всего плазму), то Python и в этом случае не требовался. Но, конечно, когда начинаешь устанавливать пакет за пакетом, то где-то в зависимостях Python и проскочит.
Мне кажется невозможно создать универсальный язык программирования, пригодный для решения любых задач. Это как набор взаимоисключающих параграфов. Даже если попытаться, то рано или поздно придётся пойти на компромисс с решением какой-то проблемы. К тому же у разных людей своих вкусы, предпочтения и взгляды на то, какой должен быть их любимый язык. Из каждого языка ещё дополнительно выходит культура разработки на нём.
На мой взгляд гораздо интереснее, когда много культур и подходов, чем какой-то один. Как, например, был бы какой-то один музыкальный жанр. Ведь программирование — это тоже немножко искусство и творчество.
Ещё можно поразмыслить с той точки зрения, что языки конкурируют между собой, а это повышает требования к качеству с каждым днем, что в свою очередь ускоряет развитие и эволюцию. Разработчики новых и старых языков учатся на ошибках друг друга, следят за тенденциями итак далее.
Что касается самого языка Vala, то я вижу в нем достаточно неплохое компромиссное решение между Java, C++ и C. Из Java взят удобный стиль объектно-ориентированного описания, но при этом отсутствие виртуальной машины, трансляция кода в C и последующая компиляция в бинарь. Также совместимость с библиотеками C/C++. Я считаю такой язык имеет место быть.
К тому же ребята из популярного Linux дистрибутива elementaryOS совсем даже не чураются его использовать и декларируют как основной язык разработки приложений для своей операционной системы.
tzlom
Я бы хотел посмотреть на "минималистичную генту без питона" — учитывая что один только список ебилдов где-то 300 мегабайт занимает а portage написан на питоне :)
cbelkin
Пожалуй тут вы правы. Генту не очень удачный пример. Но это не отменяет мысли, что Python не является само-собой разумеющимся компонентом системы.
Я бы ещё сопоставил эту проблему с проблемой оболочек командной строки. Подавляющее большинство исходников ориентируются на sh-подобный синтаксис (Bourne shell). И по этой причине разработчики, конечно, включают её в стандартный набор ПО. Но тем не менее в качестве оболочки по-умолчанию может использоваться оболочка с другим скриптовым синтаксисом. И получается, что даже тут теоретически можно жить без sh/bash/zsh, поставив какой-нибудь tcsh или fish.
tzlom
Ну как бы да, у меня на работе tcsh как корпоративный стандарт шелла (то еще говно), хотя и bash и zsh тоже доступны. С другой стороны sh это не имплементация а POSIX стандарт, так что его можно смело ожидать на любой POSIX совместимой системе.