رسم رسم بياني بالقاهرة في GTK3

صورة

صفيف من نوع تعويم يعمل كمدخل. يقوم البرنامج بتنظيم العرض ، التمدد ، التمرير في الرسم البياني.

نمط الكتابة هو C مع الفئات (بدون gtkmm). تبين أنها ليست مثالية ، مع تجريد التدفق. على وجه الخصوص ، تؤدي وظائف رد الاتصال إلى تدهور التغليف ، ويجب نقل جزء كبير من المتغيرات إلى القسم العام.
بشكل أساسي ، يمكن وضع وظائف رد الاتصال في ملف جنبًا إلى جنب مع بقية وظائف الفئة ، والتي دعوتها إلى المعلمات الرسومية. في GTK ، كل نوع من عناصر واجهة المستخدم له إشاراته الخاصة ، وبعضها موروث. على سبيل المثال ، يحتوي GtkEventBox على إشارة "button-press-event" ، ولكن ليس لديه "الحدث-التكوين" المطلوب للرد على تغيير حجم الأداة ، لأن GtkEventBox يأخذ دائمًا حجم المحتوى. ويتم تعيين حجم المحتوى باليد. يمكنك استخدام حاوية GtkFrame.

cairo_surface_t  *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
cairo_t  *cr = cairo_create(surface);

في cairo_t ، يتم إنشاء الخطوط والعلامات التي يتم عرضها بواسطة دالة cairo_stroke. عند التنميط ، اتضح أن cairo_stroke يستغرق الكثير من وقت المعالج ، لذلك يجب استخدامه بأقل قدر ممكن ، ووقت التنفيذ لوظائف
مثل cairo_move_to ، cairo_line_to صغير جدًا. بعد cairo_stroke ، يتم مسح محتويات cairo_t ولن يؤدي استدعاء cairo_stroke (cr) مرة أخرى إلى إخراج أي شيء. يمكنك استخدام
cairo_stroke_preserve لحفظ المحتوى و cairo_save / cairo_restore ، لكنني لم أستخدمها.

إذا تم تغيير الأبعاد (عن طريق التمدد بالماوس ، إشارة config_event_cb) ، فمن الضروري لكل رسم رسم وإعادة إنشاء cairo_surface_t و cairo_t. إذا قمت بإرجاع الجدول الزمني ، فلا داعي لإعادة إنشائه

    cairo_set_source_rgb(cr,0.8,0.8,0.8);
    cairo_paint(cr);

بعد ذلك ، يتم ترجمة cairo_surface_t إلى صورة

void gtk_image_set_from_surface (GtkImage *image, cairo_surface_t *surface);

ثم يتم إدراج هذه الصورة على النحو التالي

eventbox=gtk_event_box_new();
    g_signal_connect(eventbox,"button-press-event", G_CALLBACK(eventbox_press_cb), this);
    GtkAdjustment *adj_h=gtk_adjustment_new(0,0,100,1,5,10);
    GtkAdjustment *adj_v=gtk_adjustment_new(0,0,100,1,5,10);
    GtkWidget *viewport=gtk_viewport_new(adj_h, adj_v);
    scrolledwindow=gtk_scrolled_window_new(adj_h, adj_v);
    g_object_set(scrolledwindow, "hscrollbar-policy", GTK_POLICY_EXTERNAL, "vscrollbar-policy", GTK_POLICY_EXTERNAL, NULL);
    gtk_container_add(GTK_CONTAINER(viewport), scrolledwindow);
    gtk_widget_set_events(scrolledwindow, GDK_SCROLL_MASK); 
    g_signal_connect(scrolledwindow,"scroll-event",G_CALLBACK(eventbox_scroll_cb), this);
    GtkWidget *box=gtk_box_new(GTK_ORIENTATION_VERTICAL,0);
    adj=gtk_adjustment_new(0,0,110,1,5,10);
    g_signal_connect(adj,"value-changed", G_CALLBACK(adj_changed_cb), this);
    scrollbar=gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL,adj);
    gtk_box_pack_end(GTK_BOX(box),scrollbar, FALSE,FALSE,0);
    image_from_surface=gtk_image_new_from_surface(surface);
    gtk_container_add(GTK_CONTAINER(scrolledwindow),image_from_surface);
    gtk_box_pack_start(GTK_BOX(box),viewport, TRUE,TRUE,0);
    gtk_container_add(GTK_CONTAINER(eventbox),box);

لقد قمت بإزالة البادئات ، على سبيل المثال ، النوافذ المتحركة التي تم تمريرها من النوع GtkScrolledWindow.
ترتيب المرفقات لفترة وجيزة صورة>> نافذة عرضية -> إطار عرض -> مربع -> صندوق الأحداث -> (إطار)
إذا قمت بإزالة نافذة عرض قابلة للتمرير-> حاويات إطار العرض ، فسيزداد الرسم البياني فقط ، ولكنه لن ينخفض. يضيف مربع التمرير. قد تلاحظ أن هناك 3 ، ولكن لم يتم استخدام 2 منها وهي مطلوبة فقط لتهيئة الحاويات اللازمة. يتم استخدام وظيفة gtk_container_add في عناصر واجهة استخدام الحاوية حيث تناسب عنصر واجهة طفل واحد. يعين g_object_set خصائص إضافية ، ولا سيما عدم وجود أشرطة التمرير لعنصر الواجهة التمريرى
. يمكنك أيضًا تعيين الخصائص من خلال GValue

    GValue val = G_VALUE_INIT;
    g_value_init(&val, G_TYPE_BOOLEAN);
    g_value_set_boolean(&val, TRUE);
    gtk_container_child_set_property(GTK_CONTAINER(data->notebook), gr, "tab-expand", &val);

آلية التمرير: يتم تقسيم المقطع بالكامل على 100 ، ويتم حساب تغيير الجدول الزمني في وظيفة رد الاتصال. 100 مأخوذ من الأرقام gtk_adjustment_new (0،0،110،1،5،10) كـ 100 = 110-10.

علاوة على ذلك ، حول وضع المعايير.

لتحديد معلمات النص ، نستخدم مكتبة pango لتعيين المعلمات. يسمح لك بحساب حجم النص بالبكسل لخط معين وحجمه الطبوغرافي وتصديره إلى طبقة القاهرة.

PangoLayout* get_width_height_of_text(char *text, char *font, float size, float *w, float *h)
{
    GdkScreen *screen = gdk_screen_get_default();
    PangoContext *context = gdk_pango_context_get_for_screen (screen);
    PangoLayout *layout = pango_layout_new (context);
    if(g_utf8_validate(text,-1,0))
    {
        pango_layout_set_text(layout,text,-1);
        PangoFontDescription *desc=pango_font_description_new();
        pango_font_description_set_family(desc,font);
        pango_font_description_set_size(desc,size*1024);
        pango_layout_set_font_description (layout, desc);
        int width=0,height=0;
        pango_layout_get_size(layout, &width, &height);
        *w=(float) width/1024;
        *h=(float) height/1024;
        pango_font_description_free(desc);
    }
    else
    {
        printf("      UTF8\n");
    }
    return layout;
}

كما ترون ، يحسب البانجو الأحجام في وحداته الخاصة. أبرزت فئة منفصلة
للنص ومعلماته.

class text_layout
{
    private:
    int fontsize;
    public:
    GString *text;
    GString *font;
    PangoLayout *layout;
    int width;
    int height;
    text_layout(char *text, char *font, int fontsize);
    void change_text_font_fontsize(char *new_text, char *new_font, int new_fontsize);
    ~text_layout();
    text_layout(float num, char *font, int fontsize);
};

تشكل معلمات المخطط فئة منفصلة:

class graphic_parameters
{
    private:
     text_layout y_text=text_layout(" y","Liberation Serif", 14);
     text_layout x_text=text_layout(" x","Liberation Serif", 14);
     text_layout *number=0; ///   
     float max=0;
     float min=0;
     text_layout *max_=0;
     text_layout *min_=0;

    GtkAdjustment *adj;
    GtkWidget *scrollbar;
     float gap_x=25; ///    
     float gap_y=5; ///    

    void create_axes_and_xy_labels(void);

    public:
    cairo_t *cr;
    float *massiv=0; ///  
    int len=0; /// 
    int count_in_display=0; ///   
    float multiplier_x=6;
    int offset=0;
    float x_null=0;
    float y_null=0;
    int pos=0;///  
    float margin=16;

    int callback_width;  /// 
    int callback_height;
    int widget_width;
    int widget_height;
    int scroll_height=0;
    GtkWidget *eventbox;
    GtkWidget *scrolledwindow;
    GtkWidget *image_from_surface;
    cairo_surface_t *surface;

    graphic_parameters(int width, int height);
    ~graphic_parameters();
    void resize_graphic(int new_width, int new_height);
    void create_one_dimensional_graphic(float *massiv, int size);
    void update_graphic(int offset);
    void change_graphic_adj(void);
    void create_vertical_line(void);
};

ينضم هذا الفصل إلى فئة التطبيق الرئيسية.
class externals
{
    public:
    graphic_parameters *param;
    externals();
};

class appdata : public externals
{
    public:
    char *glade_name=(char*)"window.glade";
    GtkApplication *app;
    GtkWidget *win;
    GtkNotebook *notebook;
    GtkMenuBar *menubar;
    appdata();
};

بمعنى ، يتم إنشاء فئة الرسوم_المعلمات عند بدء تشغيل التطبيق ، وتتم تهيئة المحتوى حسب الضرورة عن طريق التحقق من NULL ، 0.

كانت الصعوبة الرئيسية هي تصحيح جميع التحولات. حدث Segfaults 3 مرات: غاب مرتين FALSE في وظائف رد الاتصال ولم يتم تعيين الاختيار للخروج من الصفيف في وظيفة redraw. Qt لديها فئة QCustomPlot الجاهزة للتخطيط ، ولديها إمكانيات أكثر بكثير.

رابط إلى جيثب


All Articles