[Программирование, GTK+, Разработка под Linux] Создатель динамических обоев на языке Vala
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Привет! Для создания динамических обоев в дистрибутивах GNU/Linux в большинстве случаев применяются специальные xml-файлы. Я решил создать программу, которая генерирует такой файл. Конечно, для этого есть готовые скрипты или даже можно вручную создать такой файл, но куда удобнее работать в программе с графическим интерфейсом. Здесь я тоже не первый, так как такие программы уже имеются в репозиториях, но почему бы не написать свой вариант?Небольшой обзор файлаПрограмма должна создавать файл с заданными пользователем параметрами. Уже готовый файл пользователь указывает в настройках в качестве обоев. В среде GNOME для этого понадобиться приложение GNOME Tweaks. Вот пример готового файла:
<background>
<starttime>
<year>2021</year>
<month>03</month>
<day>15</day>
<hour>14</hour>
<minute>0</minute>
<second>0</second>
</starttime>
<static>
<duration>3595.0</duration>
<file>/home/alex/DW_MACOSX/mojave_dynamic_1.jpeg</file>
</static>
<transition>
<duration>5.0</duration>
<from>/home/alex/DW_MACOSX/mojave_dynamic_1.jpeg</from>
<to>/home/alex/DW_MACOSX/mojave_dynamic_2.jpeg</to>
</transition>
<static>
<duration>3595.0</duration>
<file>/home/alex/DW_MACOSX/mojave_dynamic_2.jpeg</file>
</static>
<transition>
<duration>5.0</duration>
<from>/home/alex/DW_MACOSX/mojave_dynamic_2.jpeg</from>
<to>/home/alex/DW_MACOSX/mojave_dynamic_3.jpeg</to>
</transition>
<static>
<duration>3595.0</duration>
<file>/home/alex/DW_MACOSX/mojave_dynamic_3.jpeg</file>
</static>
<transition>
<duration>5.0</duration>
<from>/home/alex/DW_MACOSX/mojave_dynamic_3.jpeg</from>
<to>/home/alex/DW_MACOSX/mojave_dynamic_4.jpeg</to>
</transition>
<static>
<duration>3595.0</duration>
<file>/home/alex/DW_MACOSX/mojave_dynamic_4.jpeg</file>
</static>
<transition>
<duration>5.0</duration>
<from>/home/alex/DW_MACOSX/mojave_dynamic_4.jpeg</from>
<to>/home/alex/DW_MACOSX/mojave_dynamic_1.jpeg</to>
</transition>
</background>
Как видим файл совсем не сложный. В starttime указаны дата и время начала цикла показа обоев. Тег static содержит время показа отдельного изображения и путь к нему. В теге transition указано время перехода от одного изображения к другому и пути к соответствующим изображениям. Время указывается в секундах. Используем GNOME BuilderРешил попробовать поработать в GNOME Builder. Устанавливать лучше flatpak-версию из центра приложений или с сайта Flathub. Среда сама должна скачать необходимые Sdk и платформы. У классической deb-версии мною были замечены проблемы с загрузкой платформ и инструментов, также могут быть проблемы с запуском проекта. И еще я почему-то не нашел в этой версии конструктор интерфейсов, но может быть в старой версии его нет. У меня Debian 10, стабильная ветка, соответственно пакет среды будет довольно древний, а flatpak-пакет должен быть всегда самый новый. Создаем приложение GNOME на главной странице. Вводим название проекта, выбираем язык и лицензию. После того как откроется проект, нас должны интересовать только два файла. Это window.vala и window.ui. В первом будет находится вся логика приложения, а во втором описание графического интерфейса. Есть еще main.vala, но вносить в него какие-либо изменения нам не потребуется. Вот его содержимое:
int main (string[] args) {
var app = new Gtk.Application ("org.example.App", ApplicationFlags.FLAGS_NONE);
app.activate.connect (() => {
var win = app.active_window;
if (win == null) {
win = new Dwxmlcreator.Window (app);
}
win.present ();
});
return app.run (args);
}
GUIИнтерфейс приложения делал во встроенном дизайнере. Приводить содержимое ui-файла я не буду, так как он довольно монструозный и занимает больше шестисот строк. В конце поста будут ссылки на репозитории приложения в сервисах GitHub и SourceForge. В программе есть три страницы. На первой странице пользователь вводит дату и время начала показа обоев. На второй странице добавляет изображения для показа и на третьей вводит данные для сохранения готового xml-файла. Вот первая страница:
Вторая страница:
И третья страница:
Интерфейс немного не каноничный, если говорить о расположении текстовых меток, но выглядит, по моему мнению, довольно симпатично. ЛогикаПервые строчкиЗдесь все как обычно. Объявляем необходимые объекты, компоненты интерфейса и переменные. Добавляем в текстовые поля значки выбора файлов. Связываем кнопки с соответствующими методами и прописываем логику автоматического заполнения полей для удобства пользователя.
namespace Dwxmlcreator {
[GtkTemplate (ui = "/org/example/App/window.ui")]
public class Window : Gtk.ApplicationWindow {
[GtkChild]
Gtk.Stack stack;
[GtkChild]
Gtk.Box start_time_box;
[GtkChild]
Gtk.Box add_box;
[GtkChild]
Gtk.Box create_xml_box;//id в ui-файле
[GtkChild]
Gtk.Button add_start_time_button;
[GtkChild]
Gtk.Button add_button;
[GtkChild]
Gtk.Button add_image_button;
[GtkChild]
Gtk.Button create_button;
[GtkChild]
Gtk.Button back_button;
[GtkChild]
Gtk.Entry path_to_image;
[GtkChild]
Gtk.Entry transition_duration;
[GtkChild]
Gtk.Entry static_duration;
[GtkChild]
Gtk.Entry path_to_xml_directory;
[GtkChild]
Gtk.Entry xml_name;
[GtkChild]
Gtk.Entry day;
[GtkChild]
Gtk.Entry month;
[GtkChild]
Gtk.Entry year;
[GtkChild]
Gtk.Entry hours;
[GtkChild]
Gtk.Entry minutes;
[GtkChild]
Gtk.Entry seconds;
[GtkChild]
Gtk.Label image_counter;
StringBuilder builder;
string last_folder;
string main_part;
string start_time;
string first_image;
string image;
int counter = 0;
int duration;
public Window (Gtk.Application app) {
Object (application: app);
path_to_image.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, "document-open-symbolic");
path_to_image.icon_press.connect ((pos, event) => {
if (pos == Gtk.EntryIconPosition.SECONDARY) {
on_path_to_image();//выбор изображения
}
});
path_to_xml_directory.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, "document-open-symbolic");
path_to_xml_directory.icon_press.connect ((pos, event) => {
if (pos == Gtk.EntryIconPosition.SECONDARY) {
on_path_to_xml_directory();//выбор директории сохранения
}
});
add_start_time_button.clicked.connect(add_start_time);
add_image_button.clicked.connect(add_image);
add_button.clicked.connect(go_to_create_xml_page);
create_button.clicked.connect(create_xml);
back_button.clicked.connect(go_to_back);
set_widget_visible(back_button, false);//скрываем кнопку "назад" в хидербаре
builder = new StringBuilder();
var date_time = new DateTime.now_local();
day.set_text(date_time.format("%d"));//день
month.set_text(date_time.format("%m"));//месяц
year.set_text(date_time.format("%Y"));//год
if(int.parse(date_time.format("%M"))>=55){//если кол-во минут больше или равно 55-и
hours.set_text((int.parse(date_time.format("%H"))+1).to_string());//увеличиваем часы на единицу
}else{
hours.set_text(date_time.format("%H"));//показываем часы
}
}
Автоматически заполняются только все три поля даты и поле ввода часов. Количество часов увеличивается на единицу, если количество минут больше или равно 55-и. Зачем это? Мне показалось, что если не спешить, то за пять минут можно не успеть составить более-менее вменяемый по объему документ. В любом случае, решать вам. Можете закомментировать или вообще удалить эти строки.Кнопка "назад"В хидербаре только одна кнопка. Кнопка "назад", которая должна появляться только на второй странице, а при возврате на первую исчезать. При нажатии на кнопку срабатывает следующий метод:
private void go_to_back(){
if (stack.get_visible_child_name()=="page1"){
stack.visible_child = start_time_box;//page0
set_widget_visible(back_button, false);
}else{
stack.visible_child = add_box;
}
}
Определяем на какой странице находимся и если это страница с именем "page1", то есть вторая страница, то показываем первую (page0). Если условие не выполняется, то значит мы на третьей странице и идем на вторую. На первой странице кнопки нет.Время стартаЗа создание первой части нашего файла отвечает метод add_start_time. Вот он:
private void add_start_time(){
if(is_empty(year.get_text())||is_empty(month.get_text())||is_empty(day.get_text())||
is_empty(hours.get_text())||is_empty(minutes.get_text())||is_empty(seconds.get_text())){
alert("Enter correct data in all fields!");
return;
}
start_time ="<background>
<starttime>
<year>"+year.get_text()+"</year>
<month>"+month.get_text()+"</month>
<day>"+day.get_text()+"</day>
<hour>"+hours.get_text()+"</hour>
<minute>"+minutes.get_text()+"</minute>
<second>"+seconds.get_text()+"</second>
</starttime>\n";
stack.visible_child = add_box;//идем на вторую страницу
set_widget_visible(back_button, true);//делаем видимой кнопку в хидербаре
}
После проверки всех шести полей на пустоту записываем в переменную start_time содержимое этих полей с необходимыми тегами в начале и конце. Далее, переходим на вторую страницу, не забыв сделать кнопку возвращения в хидербаре видимой.Добавление изображенийОсновная часть документа конструируется с помощью метода add_image:
private void add_image(){
if(is_empty(path_to_image.get_text())||is_empty(transition_duration.get_text())||
is_empty(static_duration.get_text())){
alert("Enter correct data in all fields!");
return;
}
counter++;//счетчик для определения первого и последующих нажатий
duration = int.parse(static_duration.get_text())*60-int.parse(transition_duration.get_text());
if(counter != 1){//если не первое нажатие
image = path_to_image.get_text();
main_part ="<to>"+image+"</to>
</transition>
<static>
<duration>"+duration.to_string()+".0"+"</duration>
<file>"+image+"</file>
</static>
<transition>
<duration>"+transition_duration.get_text()+".0"+"</duration>
<from>"+image+"</from>\n";
}else{//если первое нажатие
first_image = path_to_image.get_text();//путь до первого изображения
main_part = "<static>
<duration>"+duration.to_string()+".0"+"</duration>
<file>"+first_image+"</file>
</static>
<transition>
<duration>"+transition_duration.get_text()+".0"+"</duration>
<from>"+first_image+"</from>\n";
}
image_counter.set_text(counter.to_string()+" images were added");//отображаем счетчик в текстовой метке
path_to_image.set_text("");//очищаем поле
builder.append(main_part);//добавляем в строковый билдер основную часть
}
Если пользователь добавляет первое изображение, то путь до него записывается в отдельную переменную first_image. Она понадобится потом для зацикливания показа обоев. Пути до остальных изображений записываются в переменную image.На последнюю страницу Когда пользователь добавит все нужные ему изображения, он может перейти к следующей, последней странице. За это отвечает метод go_to_create_xml_page:
private void go_to_create_xml_page(){
if(counter < 2){
alert("Add images");
return;
}
stack.visible_child = create_xml_box;
path_to_xml_directory.set_text(Environment.get_home_dir());
xml_name.set_text("dynamic_wallpaper_"+Random.int_range(100,10000).to_string());
}
Переход возможен, если добавлено как минимум два изображения. После перехода в поле выбора директории будет отображаться путь до вашей домашней папки. В поле имени будет предложен некоторый вариант имени файла, состоящий из фразы "dynamic_wallpaper" и рандомного числа от 100 до 10000.Создание документаМетод creat_xml завершает создание файла. Он дописывает недостающие строчки, собирает все части документа в одну кучу и создает файл в указанном месте.
private void create_xml(){
if(builder.str==""){
alert("Nothing to create");
return;
}
if(is_empty(path_to_xml_directory.get_text())||is_empty(xml_name.get_text())){
alert("Enter correct data in all fields!");
return;
}
string end_xml = "<to>"+first_image+"</to>
</transition>
</background>";//зацикливаем показ, добавив путь до первого изображения и создаем конец документа
builder.append(end_xml);//добавляем конец к основной части
builder.insert(0, start_time);//вставляем начало
GLib.File file = GLib.File.new_for_path(path_to_xml_directory.get_text()+"/"+xml_name.get_text()+".xml");
try {
FileUtils.set_contents (file.get_path(), builder.str);//создаем файл
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
if(file.query_exists()){
alert("File created successfully");
}else{
alert("An unknown error has occurred! Failed to create file");
}
counter = 0;
builder = new StringBuilder();
xml_name.set_text("");
image_counter.set_text("Add images");
}
Выбор изображенияЛюбая программа должна быть удобной. По возможности. В случае с диалогом выбора изображений, помимо фильтра, в нем присутствует отображение предпросмотра изображений и запоминание последней открытой папки. Без этих удобств пользователю приходилось бы каждый раз при открытии диалога переходить в папку изображений и при выборе ориентироваться на имена файлов и мелкие миниатюры изображений в списке.
private void on_path_to_image(){
var file_chooser = new Gtk.FileChooserDialog ("Select image file", this, Gtk.FileChooserAction.OPEN, "_Cancel", Gtk.ResponseType.CANCEL, "_Open", Gtk.ResponseType.ACCEPT);
Gtk.FileFilter filter = new Gtk.FileFilter ();
file_chooser.set_filter (filter);//добавляем фильтр
filter.add_mime_type ("image/jpeg");
filter.add_mime_type ("image/png");
Gtk.Image preview_area = new Gtk.Image ();
file_chooser.set_preview_widget (preview_area);//устанавливаем область для предпросмотра
file_chooser.update_preview.connect (() => {
string uri = file_chooser.get_preview_uri ();
string path = file_chooser.get_preview_filename();
if (uri != null && uri.has_prefix ("file://") == true) {
try {
Gdk.Pixbuf pixbuf = new Gdk.Pixbuf.from_file_at_scale (path, 250, 250, true);
preview_area.set_from_pixbuf (pixbuf);
preview_area.show ();
} catch (Error e) {
preview_area.hide ();
}
} else {
preview_area.hide ();
}
});
if (last_folder != null) {
file_chooser.set_current_folder (last_folder);//открываем последнюю папку
}
if (file_chooser.run () == Gtk.ResponseType.ACCEPT) {
last_folder = file_chooser.get_current_folder ();//запоминаем текущую папку
path_to_image.set_text(file_chooser.get_filename());
}
file_chooser.destroy ();
}
Остальные методыДиалог выбора папки для сохранения файла:
private void on_path_to_xml_directory(){
var file_chooser = new Gtk.FileChooserDialog ("Choose a directory", this, Gtk.FileChooserAction.SELECT_FOLDER, "_Cancel", Gtk.ResponseType.CANCEL, "_Open", Gtk.ResponseType.ACCEPT);
if (file_chooser.run () == Gtk.ResponseType.ACCEPT) {
path_to_xml_directory.set_text(file_chooser.get_filename());
}
file_chooser.destroy ();
}
Скрыть или показать какой-либо виджет (для кнопки "назад"):
private void set_widget_visible (Gtk.Widget widget, bool visible) {
widget.no_show_all = !visible;
widget.visible = visible;
}
Проверить текстовое поле на пустоту:
private bool is_empty(string str){
return str.strip().length == 0;
}
Показать сообщение пользователю:
private void alert (string str){
var dialog_alert = new Gtk.MessageDialog(this, Gtk.DialogFlags.MODAL, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, str);
dialog_alert.set_title("Message");
dialog_alert.run();
dialog_alert.destroy();
}
СборкаДля сборки приложения нужно нажать Export Bundle в окне, где отображается текущий статус проекта. Чтобы кнопка стала активной надо хотя бы раз запустить приложение. По умолчанию собираются flatpak-пакеты. В консоли после удачной сборки будет указан путь до готового файла. Также должен запуститься файловый менеджер, в котором будет открыта указанная в консоли директория. Если вам нужен исполняемый файл, то его следует искать там же в директории bin.Ссылка на GitHub: https://github.com/alexkdeveloper/dwxmlcreatorСсылка на SourceForge: https://sourceforge.net/projects/dwxmlcreator/Всем спасибо за внимание! До встречи в следующих постах!
===========
Источник:
habr.com
===========
Похожие новости:
- [Программирование, SQL, SQLite] SQLite — не игрушка
- [Системное администрирование, Системное программирование, DevOps] Искусство Helm Chart: паттерны из официальных чартов Kubernetes (перевод)
- [Программирование, Java, Микросервисы] Миграция API с REST на gRPC в WePay (перевод)
- [PHP, Программирование] Как дойти до CQRS, если у тебя PHP
- [Python, Программирование, Машинное обучение] NLP: ВЫДЕЛЯЕМ ФАКТЫ ИЗ ТЕКСТОВ С ПОМОЩЬЮ ТОМИТА-ПАРСЕРА
- [Высокая производительность, Разработка веб-сайтов, PHP, Программирование] Теория программирования: пакетные принципы и метрики
- [Настройка Linux, Системное программирование, Kubernetes] Скидка на экзамены по Kubernetes и Linux
- [Системное программирование, Реверс-инжиниринг, Программирование микроконтроллеров, Интернет вещей, DIY или Сделай сам] Hello NXP JN5169 World
- [Информационная безопасность, Программирование, Разработка под Android] Android — запрещенные приемы
- [JavaScript, Программирование] Как написать интерфейс пользователя (UI) PlayStation 5 на JavaScript (перевод)
Теги для поиска: #_programmirovanie (Программирование), #_gtk+, #_razrabotka_pod_linux (Разработка под Linux), #_programmirovanie (программирование), #_vala, #_gtk, #_rukovodstvo (руководство), #_linux, #_oboi (обои), #_blog_kompanii_itsoft (
Блог компании ITSOFT
), #_programmirovanie (
Программирование
), #_gtk+, #_razrabotka_pod_linux (
Разработка под Linux
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 05:44
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Привет! Для создания динамических обоев в дистрибутивах GNU/Linux в большинстве случаев применяются специальные xml-файлы. Я решил создать программу, которая генерирует такой файл. Конечно, для этого есть готовые скрипты или даже можно вручную создать такой файл, но куда удобнее работать в программе с графическим интерфейсом. Здесь я тоже не первый, так как такие программы уже имеются в репозиториях, но почему бы не написать свой вариант?Небольшой обзор файлаПрограмма должна создавать файл с заданными пользователем параметрами. Уже готовый файл пользователь указывает в настройках в качестве обоев. В среде GNOME для этого понадобиться приложение GNOME Tweaks. Вот пример готового файла: <background>
<starttime> <year>2021</year> <month>03</month> <day>15</day> <hour>14</hour> <minute>0</minute> <second>0</second> </starttime> <static> <duration>3595.0</duration> <file>/home/alex/DW_MACOSX/mojave_dynamic_1.jpeg</file> </static> <transition> <duration>5.0</duration> <from>/home/alex/DW_MACOSX/mojave_dynamic_1.jpeg</from> <to>/home/alex/DW_MACOSX/mojave_dynamic_2.jpeg</to> </transition> <static> <duration>3595.0</duration> <file>/home/alex/DW_MACOSX/mojave_dynamic_2.jpeg</file> </static> <transition> <duration>5.0</duration> <from>/home/alex/DW_MACOSX/mojave_dynamic_2.jpeg</from> <to>/home/alex/DW_MACOSX/mojave_dynamic_3.jpeg</to> </transition> <static> <duration>3595.0</duration> <file>/home/alex/DW_MACOSX/mojave_dynamic_3.jpeg</file> </static> <transition> <duration>5.0</duration> <from>/home/alex/DW_MACOSX/mojave_dynamic_3.jpeg</from> <to>/home/alex/DW_MACOSX/mojave_dynamic_4.jpeg</to> </transition> <static> <duration>3595.0</duration> <file>/home/alex/DW_MACOSX/mojave_dynamic_4.jpeg</file> </static> <transition> <duration>5.0</duration> <from>/home/alex/DW_MACOSX/mojave_dynamic_4.jpeg</from> <to>/home/alex/DW_MACOSX/mojave_dynamic_1.jpeg</to> </transition> </background> int main (string[] args) {
var app = new Gtk.Application ("org.example.App", ApplicationFlags.FLAGS_NONE); app.activate.connect (() => { var win = app.active_window; if (win == null) { win = new Dwxmlcreator.Window (app); } win.present (); }); return app.run (args); } Вторая страница: И третья страница: Интерфейс немного не каноничный, если говорить о расположении текстовых меток, но выглядит, по моему мнению, довольно симпатично. ЛогикаПервые строчкиЗдесь все как обычно. Объявляем необходимые объекты, компоненты интерфейса и переменные. Добавляем в текстовые поля значки выбора файлов. Связываем кнопки с соответствующими методами и прописываем логику автоматического заполнения полей для удобства пользователя. namespace Dwxmlcreator {
[GtkTemplate (ui = "/org/example/App/window.ui")] public class Window : Gtk.ApplicationWindow { [GtkChild] Gtk.Stack stack; [GtkChild] Gtk.Box start_time_box; [GtkChild] Gtk.Box add_box; [GtkChild] Gtk.Box create_xml_box;//id в ui-файле [GtkChild] Gtk.Button add_start_time_button; [GtkChild] Gtk.Button add_button; [GtkChild] Gtk.Button add_image_button; [GtkChild] Gtk.Button create_button; [GtkChild] Gtk.Button back_button; [GtkChild] Gtk.Entry path_to_image; [GtkChild] Gtk.Entry transition_duration; [GtkChild] Gtk.Entry static_duration; [GtkChild] Gtk.Entry path_to_xml_directory; [GtkChild] Gtk.Entry xml_name; [GtkChild] Gtk.Entry day; [GtkChild] Gtk.Entry month; [GtkChild] Gtk.Entry year; [GtkChild] Gtk.Entry hours; [GtkChild] Gtk.Entry minutes; [GtkChild] Gtk.Entry seconds; [GtkChild] Gtk.Label image_counter; StringBuilder builder; string last_folder; string main_part; string start_time; string first_image; string image; int counter = 0; int duration; public Window (Gtk.Application app) { Object (application: app); path_to_image.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, "document-open-symbolic"); path_to_image.icon_press.connect ((pos, event) => { if (pos == Gtk.EntryIconPosition.SECONDARY) { on_path_to_image();//выбор изображения } }); path_to_xml_directory.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, "document-open-symbolic"); path_to_xml_directory.icon_press.connect ((pos, event) => { if (pos == Gtk.EntryIconPosition.SECONDARY) { on_path_to_xml_directory();//выбор директории сохранения } }); add_start_time_button.clicked.connect(add_start_time); add_image_button.clicked.connect(add_image); add_button.clicked.connect(go_to_create_xml_page); create_button.clicked.connect(create_xml); back_button.clicked.connect(go_to_back); set_widget_visible(back_button, false);//скрываем кнопку "назад" в хидербаре builder = new StringBuilder(); var date_time = new DateTime.now_local(); day.set_text(date_time.format("%d"));//день month.set_text(date_time.format("%m"));//месяц year.set_text(date_time.format("%Y"));//год if(int.parse(date_time.format("%M"))>=55){//если кол-во минут больше или равно 55-и hours.set_text((int.parse(date_time.format("%H"))+1).to_string());//увеличиваем часы на единицу }else{ hours.set_text(date_time.format("%H"));//показываем часы } } private void go_to_back(){
if (stack.get_visible_child_name()=="page1"){ stack.visible_child = start_time_box;//page0 set_widget_visible(back_button, false); }else{ stack.visible_child = add_box; } } private void add_start_time(){
if(is_empty(year.get_text())||is_empty(month.get_text())||is_empty(day.get_text())|| is_empty(hours.get_text())||is_empty(minutes.get_text())||is_empty(seconds.get_text())){ alert("Enter correct data in all fields!"); return; } start_time ="<background> <starttime> <year>"+year.get_text()+"</year> <month>"+month.get_text()+"</month> <day>"+day.get_text()+"</day> <hour>"+hours.get_text()+"</hour> <minute>"+minutes.get_text()+"</minute> <second>"+seconds.get_text()+"</second> </starttime>\n"; stack.visible_child = add_box;//идем на вторую страницу set_widget_visible(back_button, true);//делаем видимой кнопку в хидербаре } private void add_image(){
if(is_empty(path_to_image.get_text())||is_empty(transition_duration.get_text())|| is_empty(static_duration.get_text())){ alert("Enter correct data in all fields!"); return; } counter++;//счетчик для определения первого и последующих нажатий duration = int.parse(static_duration.get_text())*60-int.parse(transition_duration.get_text()); if(counter != 1){//если не первое нажатие image = path_to_image.get_text(); main_part ="<to>"+image+"</to> </transition> <static> <duration>"+duration.to_string()+".0"+"</duration> <file>"+image+"</file> </static> <transition> <duration>"+transition_duration.get_text()+".0"+"</duration> <from>"+image+"</from>\n"; }else{//если первое нажатие first_image = path_to_image.get_text();//путь до первого изображения main_part = "<static> <duration>"+duration.to_string()+".0"+"</duration> <file>"+first_image+"</file> </static> <transition> <duration>"+transition_duration.get_text()+".0"+"</duration> <from>"+first_image+"</from>\n"; } image_counter.set_text(counter.to_string()+" images were added");//отображаем счетчик в текстовой метке path_to_image.set_text("");//очищаем поле builder.append(main_part);//добавляем в строковый билдер основную часть } private void go_to_create_xml_page(){
if(counter < 2){ alert("Add images"); return; } stack.visible_child = create_xml_box; path_to_xml_directory.set_text(Environment.get_home_dir()); xml_name.set_text("dynamic_wallpaper_"+Random.int_range(100,10000).to_string()); } private void create_xml(){
if(builder.str==""){ alert("Nothing to create"); return; } if(is_empty(path_to_xml_directory.get_text())||is_empty(xml_name.get_text())){ alert("Enter correct data in all fields!"); return; } string end_xml = "<to>"+first_image+"</to> </transition> </background>";//зацикливаем показ, добавив путь до первого изображения и создаем конец документа builder.append(end_xml);//добавляем конец к основной части builder.insert(0, start_time);//вставляем начало GLib.File file = GLib.File.new_for_path(path_to_xml_directory.get_text()+"/"+xml_name.get_text()+".xml"); try { FileUtils.set_contents (file.get_path(), builder.str);//создаем файл } catch (Error e) { stderr.printf ("Error: %s\n", e.message); } if(file.query_exists()){ alert("File created successfully"); }else{ alert("An unknown error has occurred! Failed to create file"); } counter = 0; builder = new StringBuilder(); xml_name.set_text(""); image_counter.set_text("Add images"); } private void on_path_to_image(){
var file_chooser = new Gtk.FileChooserDialog ("Select image file", this, Gtk.FileChooserAction.OPEN, "_Cancel", Gtk.ResponseType.CANCEL, "_Open", Gtk.ResponseType.ACCEPT); Gtk.FileFilter filter = new Gtk.FileFilter (); file_chooser.set_filter (filter);//добавляем фильтр filter.add_mime_type ("image/jpeg"); filter.add_mime_type ("image/png"); Gtk.Image preview_area = new Gtk.Image (); file_chooser.set_preview_widget (preview_area);//устанавливаем область для предпросмотра file_chooser.update_preview.connect (() => { string uri = file_chooser.get_preview_uri (); string path = file_chooser.get_preview_filename(); if (uri != null && uri.has_prefix ("file://") == true) { try { Gdk.Pixbuf pixbuf = new Gdk.Pixbuf.from_file_at_scale (path, 250, 250, true); preview_area.set_from_pixbuf (pixbuf); preview_area.show (); } catch (Error e) { preview_area.hide (); } } else { preview_area.hide (); } }); if (last_folder != null) { file_chooser.set_current_folder (last_folder);//открываем последнюю папку } if (file_chooser.run () == Gtk.ResponseType.ACCEPT) { last_folder = file_chooser.get_current_folder ();//запоминаем текущую папку path_to_image.set_text(file_chooser.get_filename()); } file_chooser.destroy (); } private void on_path_to_xml_directory(){
var file_chooser = new Gtk.FileChooserDialog ("Choose a directory", this, Gtk.FileChooserAction.SELECT_FOLDER, "_Cancel", Gtk.ResponseType.CANCEL, "_Open", Gtk.ResponseType.ACCEPT); if (file_chooser.run () == Gtk.ResponseType.ACCEPT) { path_to_xml_directory.set_text(file_chooser.get_filename()); } file_chooser.destroy (); } private void set_widget_visible (Gtk.Widget widget, bool visible) {
widget.no_show_all = !visible; widget.visible = visible; } private bool is_empty(string str){
return str.strip().length == 0; } private void alert (string str){
var dialog_alert = new Gtk.MessageDialog(this, Gtk.DialogFlags.MODAL, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, str); dialog_alert.set_title("Message"); dialog_alert.run(); dialog_alert.destroy(); } =========== Источник: habr.com =========== Похожие новости:
Блог компании ITSOFT ), #_programmirovanie ( Программирование ), #_gtk+, #_razrabotka_pod_linux ( Разработка под Linux ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 05:44
Часовой пояс: UTC + 5