Uma matriz do tipo float atua como entrada. O programa organiza a exibição, alongamento, rolagem do gráfico.O estilo de escrita é C com classes (sem gtkmm). Acabou não sendo perfeito, com abstrações fluidas. Em particular, as funções de retorno de chamada degradam o encapsulamento; uma parte significativa das variáveis deve ser movida para a seção pública.Basicamente, as funções de retorno de chamada podem ser colocadas em um arquivo junto com o restante das funções da classe, que chamei de graphic_parameters. No GTK, cada tipo de widget possui seus próprios sinais, alguns deles são herdados. Por exemplo, o GtkEventBox possui um sinal de "pressionar o botão", mas não possui o "evento de configuração" necessário para responder ao redimensionamento do widget, pois o GtkEventBox sempre aceita o tamanho do conteúdo. E o tamanho do conteúdo é definido manualmente. Você pode usar o contêiner GtkFrame.cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
cairo_t *cr = cairo_create(surface);
No cairo_t, são criadas linhas, rótulos que são exibidos pela função cairo_stroke. Ao criar um perfil, o cairo_stroke leva muito tempo do processador, portanto deve ser usado o mínimo possível e o tempo de execução de funções
como cairo_move_to, cairo_line_to é bastante pequeno. Após cairo_stroke, o conteúdo de cairo_t é limpo e chamar cairo_stroke (cr) novamente não produz nada. Você pode usar
cairo_stroke_preserve para salvar o conteúdo e cairo_save / cairo_restore, mas eu não os usei.
Se as dimensões forem alteradas (esticando com o mouse, o sinal configure_event_cb), para cada desenho é necessário excluir e recriar cairo_surface_t e cairo_t. Se você retroceder a programação, não será necessário recriar
cairo_set_source_rgb(cr,0.8,0.8,0.8);
cairo_paint(cr);
Em seguida, cairo_surface_t é traduzido em uma imagemvoid gtk_image_set_from_surface (GtkImage *image, cairo_surface_t *surface);
Esta imagem é então inserida da seguinte formaeventbox=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);
Eu removi os prefixos, ou seja, por exemplo, scrolledwindow é do tipo GtkScrolledWindow.Ordem de anexo brevemente imagem-> scrolledwindow-> viewport-> box-> eventbox -> (Frame)Se você remover os scrolledwindow-> viewport containers, o gráfico só aumentará, mas não diminuirá. caixa adiciona rolagem. Você pode perceber que existem 3, mas 2 deles não são usados e são necessários apenas para inicializar os contêineres necessários. Nos widgets de contêiner nos quais um widget filho se encaixa, a função gtk_container_add é usada para inserir. g_object_set define propriedades adicionais, em particular a ausência de barras de rolagem no widget scrolledwindow. Você também pode definir propriedades através do 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);
Mecanismo de rolagem: o segmento inteiro é dividido por 100 e a alteração de agendamento é calculada na função de retorno de chamada. 100 é obtido dos números gtk_adjustment_new (0,0,110,1,5,10) como 100 = 110-10.Além disso, sobre parametrização.
Para parametrizar o texto, usamos a biblioteca pango para parametrizar rótulos. Permite calcular o tamanho do texto em pixels para uma determinada fonte e seu tamanho topográfico e exportá-lo para a camada cairo.
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;
}
Como você pode ver, o pango conta os tamanhos em suas próprias unidades. Eu destaquei uma classe separadapara o texto e seus parâmetros.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);
};
Os parâmetros do gráfico formam uma classe separada: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);
};
Esta classe ingressa na classe principal do aplicativo.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();
};
Ou seja, a classe graphic_parameters é criada quando o aplicativo é iniciado e o conteúdo é inicializado conforme necessário, verificando NULL, 0.A principal dificuldade foi depurar todas as transformações. Segfaults ocorreram três vezes: duas vezes, o retorno FALSE foi perdido nas funções de retorno de chamada e não definiu a verificação de saída da matriz na função redesenhar. O Qt possui uma classe QCustomPlot pronta para plotagem, possui muito mais possibilidades.
Link para o github