Отправляет email-рассылки с помощью сервиса Sendsay

Практические советы по GTK+

  Все выпуски  

Практические советы по GTK+ (Работа с принтером)


Работа с принтером

Поддержка работы с принтером появилась в GTK начиная с версии 2.10, причём на ОС Windows тоже. Рассмотрим высокоуровневую библиотеку печати на принтере.

 

Создадим простое приложение, в котором есть только текстовая метка и один пункт меню "Печать", при выборе которого появляется диалог, в котором можно выбрать принтер, размер бумаги, число копий и т.д.

Далее, при подтверждении печати получим изображение заданного виджета(всего окна) в виде картинки, изменим её масштабы до размера листа бумаги и отправим на печать картинку.

Печать идёт через библиотеку векторной графики Cairo, всю библиотеку изучать не будем, но для примера печати текста, а не только картинки, добавим текстовый заголовок вверху страницы для вывода на принтер.

 

Вот полный исходный код приложения для печати:

 

#include <gtk/gtk.h>

 

GtkWidget *window;// основное окно

 

static void begin_print (GtkPrintOperation *operation,GtkPrintContext *context,gpointer user_data)

{

       gtk_print_operation_set_n_pages (operation,1);// устанавливаем число страниц для печати

}

 

// процесс печати здесь

static void draw_page (GtkPrintOperation *operation,GtkPrintContext   *context,int page_nr,gpointer user_data)

{

       GtkWidget *widget = GTK_WIDGET(user_data);

       guint cx,cy;// размеры виджета

       doubleprint_scale=1;// коэффициент масштабирования виджета до размера листа

       cairo_t *cr;

       PangoLayout *layout;

       PangoFontDescription *desc;// описание шрифта

       double width,height;// размеры листа для печати

       double pixbuf_x=0;// точка, откуда будет печататься картинка

       double pixbuf_y=0;

       // печатаем только первую страницу

       if(page_nr) return;

       // размеры бумажной страницы

       width=gtk_print_context_get_width(context);

       height = gtk_print_context_get_height(context);

       // размеры виджета, который будем печатать

       if(!widget->window)gtk_widget_realize(widget);

       cx=widget->allocation.width;

       cy=widget->allocation.height;

 

       // Получаем указатель на контекст Cairo

       cr = gtk_print_context_get_cairo_context(context);

       cairo_move_to(cr,0,0);

 

       // Будем печатать виджет на весь лист, но с соблюдение пропорций, поэтому виждет подлежит масштабированию до размеров листа

       // Поиск коэффициента масштабирования

       {

               guint max=MAX(cx,cy);

               if(height>width)// обычная ориентация бумаги

               print_scale=width/max;

               else// альбомная ориентация бумаги

               print_scale=(height)/max;

       }

 

       

       // заголовок

       {

               int x=0,y=0;

               layout = gtk_print_context_create_pango_layout (context);

               pango_layout_set_text (layout,"Заголовок", -1);

               desc = pango_font_description_from_string ("sans 14");

               pango_layout_set_font_description (layout, desc);

               pango_font_description_free (desc);

               pango_layout_get_pixel_size(layout,&x,&y);

               pango_cairo_show_layout (cr, layout);// вывод в контекст печати

               g_object_unref (layout);

               pixbuf_y = y+2;

       }

 

       {

               GdkWindow *drawable;

               GdkPixbufFormat *info_pbuf=NULL;

               GdkPixbuf *pixbuf,*scale;

               

               GdkColormap *cmap = gdk_colormap_get_system();

               drawable = GDK_DRAWABLE(widget->window);

               pixbuf = gdk_pixbuf_get_from_drawable(NULL,drawable,NULL,widget->allocation.x,widget->allocation.y,0,0,cx,cy);

               // масштабирование

               cx*=print_scale;

               cy*=print_scale;

               scale = gdk_pixbuf_scale_simple (pixbuf,cx,cy,GDK_INTERP_HYPER);

               gdk_pixbuf_unref(pixbuf);

               pixbuf=scale;

               

               cairo_set_source_rgb (cr, 1.0, 0, 0);

               cairo_rectangle (cr, pixbuf_x, pixbuf_y,cx,cy);

 

               gdk_cairo_set_source_pixbuf(cr,pixbuf,pixbuf_x,pixbuf_y);

               cairo_fill (cr);// сбросить изображение в контекст

               gdk_pixbuf_unref(pixbuf);

       }

}

 

static void end_print (GtkPrintOperation *operation,GtkPrintContext   *context,gpointer user_data)

{

}

 

// Вывод на принтер содержимого виджета widget

void printing(GtkWidget *widget)

{

       GtkPrintOperation *print;

       GtkPrintOperationResult res;

       // Настройки принтера, после первой печати берём их из принтера

       static GtkPrintSettings *settings=NULL;

 

       // Создаём объект высокоуровневой печати типа GtkPrintOperation

       print = gtk_print_operation_new();

 

       // восстанавливаем настройки принтера (при второй и последующих сессиях печати)

       if (settings != NULL)

       gtk_print_operation_set_print_settings (print, settings);

 

       g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), NULL);

       g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), widget);

       g_signal_connect (print, "end-print", G_CALLBACK (end_print), NULL);

 

       // запуск процесса печати

       res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,GTK_WINDOW (window), NULL);

       // если в диалоге согласились вывести документ на печать

       if (res == GTK_PRINT_OPERATION_RESULT_ERROR)

       {

               GError *error = NULL;

               GtkWidget *error_dialog = gtk_message_dialog_new (GTK_WINDOW (window),

               GTK_DIALOG_DESTROY_WITH_PARENT,

               GTK_MESSAGE_ERROR,

               GTK_BUTTONS_CLOSE,

               "Невозможно напечатать страницу!\n",

               NULL);

               g_signal_connect (error_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);

               gtk_widget_show (error_dialog);

               g_error_free (error);

       }

       else

       // если процесс печати прошёл успешно

       if (res == GTK_PRINT_OPERATION_RESULT_APPLY)

       {

               // удаляем предыдущие настройки принтера, которые могли устареть, если что-то в них поменяли

               if (settings != NULL)

                       g_object_unref (settings);

               // запоминаем текущие настройки принтера, чтобы при повторной печати их не менять снова

               settings = g_object_ref(gtk_print_operation_get_print_settings(print));

       }

       // Удаляем объект высокоуровневой печати типа GtkPrintOperation

       g_object_unref (print);

}

 

// обработчик выбора элемента меню

static void  menuitem_response (GtkMenuItem *menuitem,gpointer user_data)

{

       // печатаем всё содержимое окна

       printing(window);

}

int main(int argc, char* argv[])

{

       GtkWidget *vbox;

       GtkWidget *menubar;

       GtkWidget *label;// текстовая метка

       gtk_init(&argc,&argv);// Инициализация  GTK;

 

       // Создаём главное окно

       window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

       // Подключение сигналов

       gtk_signal_connect( GTK_OBJECT( window ),"delete_event",GTK_SIGNAL_FUNC(gtk_false),NULL);

       gtk_signal_connect( GTK_OBJECT( window ),"destroy",GTK_SIGNAL_FUNC(gtk_main_quit), NULL);

       // меняем заголовок окна

       gtk_window_set_title(GTK_WINDOW(window),"Первое приложение");

 

       vbox = gtk_vbox_new (FALSE, 4);

       gtk_container_add(GTK_CONTAINER (window),vbox);

 

       // Создать меню

       {

               GtkWidget *menuitem;

               // создаём основное меню

               menubar = gtk_menu_bar_new();

               gtk_box_pack_start(GTK_BOX(vbox),menubar,FALSE,F˜LSE,0);// упаковка меню в основное окно

               // Первый элемент главного меню [с подменю] - File

               menuitem = gtk_menu_item_new_with_mnemonic("Печать");// создаём элемент меню

               gtk_menu_shell_append (GTK_MENU_SHELL(menubar), menuitem);// вставляем элемент меню в главное меню

               g_signal_connect(G_OBJECT (menuitem),"activate",G_CALLBACK (menuitem_response),NULL);// подключаем обработчик меню

 

       }

       // главный виджет в окне

       label = gtk_label_new("Привет!");

       // упаковываем его в окно

       gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,10);

       // отображение основного окна и всего, что в нём есть

       gtk_widget_show_all(window);

 

       // главный цикл приложения - на нём программа 'зависнет', до выполнения функции gtk_main_quit();

       gtk_main();

       return 0;

}

 Внимание! Все выпуски, включая этот, можно найти в одном файле gtk_book.zip

 


В избранное