Показаны сообщения с ярлыком Gtk. Показать все сообщения
Показаны сообщения с ярлыком Gtk. Показать все сообщения

В одной из программ на работе используется ряд самописных Gtk-виджетов для настройки фильтров изображения. Виджеты лежат в Box'е, добавляются, удаляются и настраиваются пользователем. У каждого типа виджетов свой набор настроек. Все настройки виджеты хранят в своих свойствах.

Чтобы сохранять после перезапуска программы список фильтров и их параметры, была идея сделать некий обобщенны код, не зависимый от конкретной задачи, который бы сохранял объекты Gobject в файлы (типы объектов и значения свойств) и потом воссоздавал последовательность объектов по этим файлам.

В качестве "proof of concept" был написан код, клонирующий объект Gobject. Функция g_object_clone возвращает копию объекта, переданного ей в качестве параметра src. Код основан на примере со StackOverflow. Обращаю внимание, что полноценно копируются только простые свойства, для boxed-типов копируется указатель с инкрементированием счетчика ссылок.

Код gobject_clone.c:
// gcc `pkg-config --libs --cflags glib-2.0 gobject-2.0` gobject_clone.c point.c -o gobject_clone
#include <glib-object.h>
#include "point.h"
#include <stdio.h>
#include <string.h> //< For strcmp.

// See http://stackoverflow.com/questions/3003655/is-there-a-good-way-to-copy-a-gtk-widget?answertab=votes#tab-top
static GObject *g_object_clone(GObject *src)
{
  GObject *dst;
  GParameter *params;
  GParamSpec **specs;
  guint n, n_specs, n_params;

  specs = g_object_class_list_properties(G_OBJECT_GET_CLASS(src), &n_specs);
  params = g_new0(GParameter, n_specs);
  n_params = 0;

  for (n = 0; n < n_specs; ++n)
    if((specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE)
    {
      params[n_params].name = g_intern_string(specs[n]->name);
      g_value_init(&params[n_params].value, specs[n]->value_type);
      g_object_get_property(src, specs[n]->name, &params[n_params].value);
      ++n_params;
    }

  dst = g_object_newv(G_TYPE_FROM_INSTANCE(src), n_params, params);
  g_free(specs);
  g_free(params);

  return dst;
}

// Print, clear, print again.
static void psp (Point *p)
{
  g_print("OBJECT %p\n", p);
  g_print("  Before clearing:\n");
  point_print(p);
  g_signal_emit_by_name(p, "clear");
  g_print("  After clearing:\n");
  point_print(p);
  g_print("  ...\n");
}

int main(int argc, char **argv)
{
  g_type_init();

  GArray *array = g_array_new(FALSE, FALSE, sizeof(gint));
  gint val1 = 33, val2 = 44;
  g_array_append_val(array, val1);
  g_array_append_val(array, val2);
  g_array_append_val(array, val1);

  GObject *p1 = g_object_new(TYPE_POINT, "x", 5, "y", 10, "a", array, NULL);
  GObject *p2 = g_object_clone(p1); //< Note: garray uses ref/unref for copy/free.

  psp(POINT(p1));

  g_print("Appending value '%d' to array.\n", val2);
  g_print("  ...\n");
  g_array_append_val(array, val2);

  psp(POINT(p2));

  g_clear_object(&p1);
  g_clear_object(&p2);

  return 0;
}
В качестве объектов в примере взят простенький класс Point с гитхаба за авторством Jacob Gelbman. Код point.h:
// https://github.com/zorgnax/gobject-examples/tree/master/02-point-inheritance
#ifndef __POINT_H__
#define __POINT_H__
#include <glib.h>
#include <glib-object.h>

#define TYPE_POINT           (point_get_type             ())
#define POINT(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_POINT, Point))
#define POINT_CLASS(cls)     (G_TYPE_CHECK_CLASS_CAST    ((cls), TYPE_POINT, PointClass))
#define IS_POINT(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_POINT))
#define IS_POINT_CLASS(cls)  (G_TYPE_CHECK_CLASS_TYPE    ((cls), TYPE_POINT))
#define POINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS  ((obj), TYPE_POINT, PointClass))

typedef struct _PointClass PointClass;
typedef struct _Point      Point;

struct _PointClass
{
  GObjectClass parent;
  void (*clear) (Point *self);
};

struct _Point
{
  GObject parent;
  gint    x;
  gint    y;
  GArray *array;
};

GType point_get_type(void);
void  point_print(Point *self);

#endif /*__POINT_H__*/

Код point.c:
// https://github.com/zorgnax/gobject-examples/tree/master/02-point-inheritance
#include <glib-object.h>
#include "point.h"

G_DEFINE_TYPE(Point, point, G_TYPE_OBJECT);

enum
{
  PROP_0,
  PROP_ARRAY,
  PROP_X,
  PROP_Y
};

enum
{
  CLEAR,
  LAST_SIGNAL
};

static guint point_signals[LAST_SIGNAL] = {0};


void point_print (Point *self)
{
  g_print("    x: %d, y: %d\n", self->x, self->y);

  g_print("    ar:");
    if(self->array)
    {
      guint i;
      for(i = 0; i < self->array->len; i++)
        g_print(" %d", g_array_index(self->array, gint, i));
    }
    else
      g_print("null");
  g_print("\n");
}

static void point_clear (Point *self)
{
  g_object_set(self, "x", 0, "y", 0, "a", NULL, NULL);
}

static void point_get_property(GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec)
{
  Point *point = POINT(obj);

  switch (prop_id)
  {
    case PROP_ARRAY:
      g_value_set_boxed(value, point->array);
    break;

    case PROP_X:
      g_value_set_int(value, point->x);
    break;

    case PROP_Y:
      g_value_set_int(value, point->y);
    break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
    break;
  }
}

static void point_set_property(GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec)
{
  Point *point = POINT(obj);

  switch (prop_id)
  {
    case PROP_ARRAY:
      if(point->array) g_array_unref(point->array);
      point->array = g_value_dup_boxed(value);
    break;

    case PROP_X:
      point->x = g_value_get_int(value);
    break;

    case PROP_Y:
      point->y = g_value_get_int(value);
    break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
    break;
  }
}

static void point_finalize(GObject *point)
{
  if(POINT(point)->array) g_array_unref(POINT(point)->array);

  G_OBJECT_CLASS(point_parent_class)->finalize(point);
}

static void point_class_init (PointClass *cls)
{
  GObjectClass *g_object_class = G_OBJECT_CLASS(cls);
  GParamSpec *array_param;
  GParamSpec *x_param;
  GParamSpec *y_param;

  g_object_class->get_property = point_get_property;
  g_object_class->set_property = point_set_property;
  g_object_class->finalize = point_finalize;

  cls->clear = point_clear;

  array_param = g_param_spec_boxed(
    "a", "a", "some int array",
    G_TYPE_ARRAY,
    G_PARAM_READWRITE);

  x_param = g_param_spec_int(
    "x", "x", "x loc of point",
    INT_MIN, /* => */ INT_MAX,
    0,
    G_PARAM_READWRITE);

  y_param = g_param_spec_int(
    "y", "y", "y loc of point",
    INT_MIN, /* => */ INT_MAX,
    0,
    G_PARAM_READWRITE);

  g_object_class_install_property(
    g_object_class,
    PROP_ARRAY,
    array_param);

  g_object_class_install_property(
    g_object_class,
    PROP_X,
    x_param);

  g_object_class_install_property(
    g_object_class,
    PROP_Y,
    y_param);

  point_signals[CLEAR] = g_signal_new(
    "clear",                               /* signal_name */
    TYPE_POINT,                            /* itype */
    G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, /* signal_flags */
    G_STRUCT_OFFSET(PointClass, clear),    /* class_offset */
    NULL,                                  /* accumulator */
    NULL,                                  /* accu_data */
    g_cclosure_marshal_VOID__VOID,         /* c_marshaller */
    G_TYPE_NONE,                           /* return_type */
    0);                                    /* n_params */
}

static void point_init(Point *point)
{
  point->array = NULL;
}

Есть такая особенность в GTK, что если положить с помощью gtk_expander_set_label_widget в GtkExpander активируемый виджет вроде GtkCheckButton или GtkSwitch, то активируемый виджет вроде как работает (можно кликнуть по нему и получить статус "active"), но отрисовывается не правильно. Например, в случае GtkCheckButton не рисуется галочка, даже если кнопка в активном состоянии. В принципе даже из названия "label_widget" видно, что разработчиками не закладывалось, что кто-то будет туда класть какой-то активный элемент, максимум GtkLabel или картинку. Однако есть способ заставить активные виджеты работать, если виджет класть в Expander уже после того, как Expander сформирован.

Ниже пример на питоне. Отмечу, что обязательно нужно класть в label_widget GtkBox, а уже в него складывать свои активные виджеты. Функцию hacked_idle можно объявить один раз и использовать для всех Expander'ов.


import gi, sys
from gi.repository import Gtk, GLib


def hacked_idle(expander):
  hbox = expander.get_label_widget()
  expander.set_label_widget(None)
  expander.set_label_widget(hbox)
  return False

def expander_realize_cb(widget):
  GLib.idle_add(hacked_idle, widget)
  return False


class Test:
  def __init__(self):
    window = Gtk.Window()
    window.set_default_size(640, 480)
    window.connect_after("destroy", self.destroy)

    exp = Gtk.Expander()
    exp.connect("realize", expander_realize_cb)
    exp.set_expanded(True)
    window.add(exp)

    hbox = Gtk.Box(Gtk.Orientation.HORIZONTAL, 5)
    exp.set_label_widget(hbox)

    check = Gtk.CheckButton()
    check.set_label("Hi, There!!");
    hbox.add(check)

    switch = Gtk.Switch()
    hbox.add(switch)

    big_label = Gtk.Label()
    big_label.set_markup("<big>Hello, World!!!</big>")
    exp.add(big_label)

    window.show_all()

  def destroy(window, self):
    Gtk.main_quit()

def main():
  app = Test()
  Gtk.main()

if __name__ == "__main__":
    sys.exit(main())

В свежеустановленной Astra Linux не работала функция gtk_show_uri() с URI типа ghelp.

В GError при этом можно было увидеть ошибку:
'Действие не поддерживается'.
Или, с LANG=C:
'Operation not supported'.

Естественно, yelp был установлен.
Вопреки некоторым советам из интернетов, gvfs тут ни при чем.
Проблема решилась установкой пакета desktop-file-utils.

Код основан на примере "Rotated button" из gtk-demo. Собирается под Gtk-2. Местами код неидеален (например виджет RotatedBin.scale создается вручную в main), но, думаю, вполне может быть полезен.

Скрин:
[Image]

Код:
https://docs.google.com/file/d/0B40UHa6ea9QkdUFTVnRqNnFaTDg/edit

Пара советов как привести изначально унылый внешний вид OpenOffice и Java-приложений к стилю программ на Gtk:



OpenOffice.org

Создаем файл /etc/profile.d/openoffice.sh со следующим содержанием:

#
# /etc/profile.d/openoffice.sh

export SAL_USE_VCLPLUGIN=gtk
export OOO_FORCE_DESKTOP=gnome
Теперь достаточно перелогиниться в системе, необходимые настройки подхватятся.

Java

Создаем файл /etc/profile.d/gtkjava.sh со следующим содержанием:
#
# /etc/profile.d/gtkjava.sh
export _JAVA_OPTIONS=" -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel \
-Dawt.useSystemAAFontSettings=on"
Также перелогинимся.

В связи со скудностью документации по библиотеке GtkExtra, мною был составлен довольно подробно комментированный простенький пример, по которому можно понять принципы построения графиков с помощью GtkExtra, его и выкладываю в блоге.
Пример во многом аналогичен примеру testiterator из стандартной поставки GtkExtra и выглядит так:

Собственно текст примера:
// Пример дынных для отрисовки -->
    // Количество точек = 12
    int nt = 12;

    // Структура для пар координат "время - значение"
    struct pair
    {
        double x;   // По X - Время
        double y;   // По Y - Значение
    };

    // Область памяти с парами координат "время - значение"
    struct pair mem[12] =
    {
        {   0,      0.2},   // 1
        {   1.5,    0},
        {   2.4,    1},
        {   3.7,    0},
        {   4.44,   0.55},  // 5
        {   6.3,    0.73},
        {   7,      0.21},
        {   8.9,    0.1},
        {   11,     0.2},
        {   14.6,   0.2},   // 10
        {   17,     0.2},
        {   20,     1}      // 12
    };
// Пример дынных для отрисовки <--


// Стандартные для GTK вещи -->
    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <gtk/gtk.h>
    #include <gdk/gdk.h>

    void quit ()
    {
      gtk_main_quit();
    }
// Стандартные для GTK вещи <--


#include <gtkplotcanvas.h> 
#include <gtkplotcanvastext.h> 
#include <gtkplotcanvasplot.h> 
#include <gtkplotdata.h> 


// Массив текста для подписей к точкам
static gchar point_label[100];

// Функция, запускаемая для получения точек
// (функция запускается по разу для каждой точки)
static void graph_iter
    (
    GtkPlot *plot,
    GtkPlotData *data,
    gint iter,
    gdouble *x,
    gdouble *y,
    gdouble *z,
    gdouble *a,
    gdouble *dx,
    gdouble *dy,
    gdouble *dz,
    gdouble *da,
    gchar **label,
    gboolean *error
    )
{
    // Достаем из объекта data указатель на область памяти с координатами точек
    double *memory = (double *) g_object_get_data(G_OBJECT(data), "Dots_memory_pointer");

    // Распаковываем координаты из памяти
    *x = *(
                memory          // Начало области памяти
                + 0             // X - первый в парах, так что без смещения
                + 2 * iter);    // Смещение к нужной паре
    *y = *(
                memory          // Начало области памяти
                + 1             // Y - второй в парах, смещение к нему
                + 2 * iter);    // Смещение к нужной паре

    // Подписи к точкам
    sprintf(point_label, "Точка #%d\n", iter + 1);
    *label = point_label;

    *error = FALSE;
}


void graph_open
    (
        GtkWidget *container,   // Контейнер, в котором рисовать график
        int dots_number,        // Количесвто точек
        void *memory            // Область памяти, содержащее координаты этих точек
    )
{
    // Создаем холст canvas 900x700 пикселей в окне -->
        GtkWidget *canvas;      // Виджет
        canvas = gtk_plot_canvas_new(   // Создаем
            900, 700,                   // Размер
            1.);                        // В натуральную величину (например для уменьшения в два раза следует поставить 0.5)
        gtk_container_add(GTK_CONTAINER(container), canvas);    // Помещаем в контейнер
    // Создаем холст canvas 900x700 пикселей в окне <--


    // Создадим подпись вверху холста -->
        GtkWidget *top_label;
        
        top_label = (GtkWidget *) gtk_plot_canvas_text_new(
                "Times-BoldItalic",             // Шрифт (можно выставить NULL для шрифта по умолчанию)
                                                    // Доступные шрифты можно посмотреть в файле gtkplotps.c
                20,                             // Высота шрифта
                0,                              // Угол наклона надписи
                NULL,                           // Цвет шрифта
                NULL,                           // Цвет фона надписи
                TRUE,                           // Прозрачность
                GTK_JUSTIFY_CENTER,             // Выравнивание
                "My first plot (первый плот).");// Собственно текст

        gtk_plot_canvas_put_child(          // Помещаем на холст
                GTK_PLOT_CANVAS(canvas),            // Холст
                (GtkPlotCanvasChild *) top_label,   // Что помещать (child)
                            // Координаты:
                .50,                                // x1 - отступ по горизонтали, в процентах от холста (зд. 50%, т.е. посередине)
                .05,                                // y1 - отступ по вертикалии, в процентах от холста (зд. 5%, т.е. почти наверху)
                0.,                                 // x2
                0.);                                // y2
    // Создадим подпись вверху холста <--


    // Устанавливаем цвет холста -->
        GdkColor color;
        gdk_color_parse("light blue", &color);
        gdk_color_alloc(gtk_widget_get_colormap(canvas), &color);
        gtk_plot_canvas_set_background(GTK_PLOT_CANVAS(canvas), &color);
    // Устанавливаем цвет холста <--


    // Создаем график plot (точнее основу графика - оси, подписи и т.п., без значений) -->
        GtkWidget *plot;    

        plot = gtk_plot_new_with_size(
            NULL,       // GdkDrawable виджет
            .65, .45);  // Высота и ширина виджета графика

        // Цвет графика -->
            gdk_color_parse("light yellow", &color);
            gdk_color_alloc(gtk_widget_get_colormap(plot), &color);
            gtk_plot_set_background(GTK_PLOT(plot), &color);
        // Цвет графика <--
        
        gtk_plot_set_range(     // По умолчанию график 1x1 деление,...
            GTK_PLOT(plot),     // ...выставим другие значения:
            0., 20.,            // По X - 20 делений
            0., 1.);            // По Y - 1 деление

        // Выставим с каким шагом проставлять метки координат на графике
        gtk_plot_set_ticks(GTK_PLOT(plot),
            GTK_PLOT_AXIS_X,    // По оси X
            2,                  // Цифры проставлять с шагом 2
            1);                 // Ставить засечки с шагом 1
        gtk_plot_set_ticks(GTK_PLOT(plot), GTK_PLOT_AXIS_Y, .1, 1);

        gtk_plot_grids_set_visible(GTK_PLOT(plot), // Координатная сетка
            TRUE,       // Вертикальная сетка сплошной линией относительно проставленных на оси цифр
            TRUE,       // Вертикальная сетка штриховой линией относительно проставленных на оси меток
            TRUE,       // Горизонтальная сетка сплошной линией относительно проставленных на оси цифр
            TRUE);      // Горизонтальная сетка штриховой линией относительно проставленных на оси меток

        gtk_widget_show(plot);  // Нужно вызвать функцию отрисовки графика заранее,
                                // иначе потом не удасться добавить к графику данные
    // Создаем график plot (точнее основу графика - оси, подписи и т.п., без значений) <--


    // Подписи к графику -->
        // Верхнюю и правую просто скроем:
        gtk_plot_axis_hide_title(gtk_plot_get_axis(GTK_PLOT(plot), GTK_PLOT_AXIS_TOP));
        gtk_plot_axis_hide_title(gtk_plot_get_axis(GTK_PLOT(plot), GTK_PLOT_AXIS_RIGHT));

        // Остальные пропишем:
        gtk_plot_axis_set_title(gtk_plot_get_axis(GTK_PLOT(plot), GTK_PLOT_AXIS_LEFT), "Значение");
        gtk_plot_axis_set_title(gtk_plot_get_axis(GTK_PLOT(plot), GTK_PLOT_AXIS_BOTTOM), "Время");
    // Подписи к графику <--


    // Создаем child с только что созданным графиком plot и рисуем его на холсте (put_child) -->
        GtkPlotCanvasChild *child;

        child = (GtkPlotCanvasChild *) gtk_plot_canvas_plot_new(GTK_PLOT(plot)); // Создание структуры child

        gtk_plot_canvas_put_child(          // Помещаем на холст
                GTK_PLOT_CANVAS(canvas),    // Холст
                child,                      // Что помещать (child)
                            // Координаты:
                .15,                            // x1 - отступ по горизонтали, в процентах от холста
                .25,                            // y1 - отступ по вертикалии, в процентах от холста
                .80,                            // x2 - ширина графика
                .85);                           // y2 - высота графика
    // Создаем child с только что созданным графиком plot и рисуем его на холсте (put_child) <--


    // Строим на графике значения (пока просто линии между точками) -->
        GtkPlotData *dataset;

        dataset = (GtkPlotData *) gtk_plot_data_new_iterator(   // Заполняем структуру данных (значения и параметры)
            (GtkPlotIterator)graph_iter,                                    // Функция, запускаемая для получения (распаковки) точек
            dots_number,                                                    // Количество точек
            GTK_PLOT_DATA_X|GTK_PLOT_DATA_Y|GTK_PLOT_DATA_LABELS);          // Маска параметров
        
        // Здесь мы сохраним указатель на адрес области памяти с данными о точках...
        // ...в объекте dataset (см. GObject Reference Manual)
        g_object_set_data(G_OBJECT(dataset), "Dots_memory_pointer", memory);

        gtk_plot_data_show_labels(dataset, TRUE);   // Отображать подписи к точкам
        gdk_color_parse("dark green", &color);
        gdk_color_alloc(gtk_widget_get_colormap(plot), &color);
        gtk_plot_data_labels_set_attributes(dataset,
                "Helvetica-Bold",                   // Шрифт (можно выставить NULL для шрифта по умолчанию)
                14,                                 // Высота шрифта
                90,                                 // Угол наклона подписи
                &color,                             // Цвет шрифта
                NULL);                              // Цвет фона подписи

        gtk_plot_add_data(GTK_PLOT(plot), dataset); // Добавляем значения на график...
        gtk_widget_show(GTK_WIDGET(dataset));       // ...и отображаем их
    // Строим на графике значения (пока просто линии между точками) <--


    // Легенда графика
    gtk_plot_data_set_legend(dataset, "Легенда");


    // Настроим вид точек <--
        gdk_color_parse("green", &color);   // Цвет - зеленый
        gdk_color_alloc(gdk_colormap_get_system(), &color);

        gtk_plot_data_set_symbol(dataset,
             GTK_PLOT_SYMBOL_DIAMOND,       // Символ - ромб
             GTK_PLOT_SYMBOL_OPAQUE,        // Стиль - непрозрачный
             20, 2,                         // Размеры
             &color, &color                 // Цвета
             );
    // Настроим вид точек -->


    // Настроим вид линий -->
        gdk_color_parse("red", &color);     // Цвет - красный
        gdk_color_alloc(gdk_colormap_get_system(), &color);
        gtk_plot_data_set_line_attributes(dataset,
            GTK_PLOT_LINE_SOLID,            // GtkPlotLineStyle
            0,                              // GdkCapStyle (как рисовать концы линий, см. GDK Reference Manual)
            0,                              // GdkJoinStyle (как объединяются сегменты линий, см. GDK Reference Manual)
            3,                              // Ширина линии
            &color);                        // Цвет
    // Настроим вид линий <--
}


int main(int argc, char *argv[])
{
    // Стандартные для GTK вещи -->
        // Здесь создаем окно и сопутствующие виджеты
        GtkWidget *window;
        gtk_init(&argc,&argv);
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_signal_connect (GTK_OBJECT (window), "destroy",
            GTK_SIGNAL_FUNC(quit), NULL);
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

        GtkWidget *main_vbox;
        main_vbox = gtk_vbox_new(FALSE, 5);
        gtk_container_add(GTK_CONTAINER(window), main_vbox);
        gtk_widget_show(main_vbox);
        
        // Frame, в который будем класть виджет с графиком
        GtkWidget *main_frame;
        main_frame = gtk_frame_new("График");
        gtk_box_pack_start(GTK_BOX(main_vbox), main_frame, TRUE, TRUE, 0);

        GtkWidget *main_hbox;
        main_hbox = gtk_hbox_new(FALSE, 0);
        gtk_box_pack_end(GTK_BOX(main_vbox), main_hbox, FALSE, FALSE, 0);

        GtkWidget *close_button;
        close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); 
        g_signal_connect(GTK_OBJECT(close_button), "clicked", G_CALLBACK(quit), NULL);
        gtk_box_pack_end(GTK_BOX(main_hbox), close_button, FALSE, FALSE, 0);
    // Стандартные для GTK вещи <--

            // Здесь предположим у нас есть область памяти со значениями координат mem
            // и количество точек nt.
            // Эти данные и передаем в нашу функцию.
            graph_open(main_frame, nt, mem);

    // Стандартные для GTK вещи -->
        gtk_widget_show_all(GTK_WIDGET(window));
        gtk_main();
        return 0;
    // Стандартные для GTK вещи <--
}


//
// Gtk Extra Example
// http://damnsmallblog.blogspot.com
//

В примере довольно универсальной функции graph_open передаются три параметра:
1) Контейнер GTK, в котором и будет отрисовн график.
2) Количество точек для отрисовки.
3) Адрес области памяти, в которой лежат значения (double) координат точек.

Вспомогательная функция graph_iter служит для распаковки точек.
main - простенькое gtk-приложение, содержащее виджет main_frame в качестве контейнера для графика.


 

Copyright © 2007 DamnSmallBlog. Content is licensed under Creative Commons Attribution-Noncommercial.

Design: GeckoandFly and Blogcrowds.