only for RuBoard - do not distribute or recompile |
Listing 12.8 is the source for barline_utils.c , the code functions that are called from callbacks.c (for the third report) to create the bar/line chart.
#include <gtk/gtk.h> #include <mysql.h> /* stdlib.h is needed for the atoi/atof call. */ #include <stdlib.h> #include "support.h" #define SERVER "einstein" #define LOGIN "kbi_user" #define PASS "dengissa" #define DB "kbi" #define BASELINE_CHART 350 //the number of pixels from the top //of the drawingarea to the "baseline" //of the bars in the bar graph #define BASELINE_MONTHS 370 //the number of pixels down to draw //the month names #define SCALE_DENOMINATOR 1235 //the division factor to scale the bars //and lines to the drawingarea #define BAR_WIDTH 25 //width in pixels of the bars GtkWidget *frm_barline; MYSQL *conx; MYSQL_RES *result_set; MYSQL_ROW row; gchar *sql; gchar *month_names[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; gint month_bar_amounts[12]; //the values the bar chart should show gint month_line_amounts[12]; //the values for the line chart gint month_indents[12]; //number of pixels from the left to //print the month names void draw_bar(gint bar_left, gint bar_width, gint bar_height, gchar *bar_color); GdkGC *get_gc(gchar *in_color) { /* This function will return a graphics context in the * color as specified by the in_color parameter. */ GdkGC *gc; GdkColor my_color; gc = gdk_gc_new(GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->window); if (!gdk_color_parse(in_color, &my_color)) { g_print("Unable to parse %s.\n", in_color); gtk_statusbar_push(GTK_STATUSBAR(lookup_widget(frm_barline, "statusbar1")), 1, "Unable to parse color.\n"); return 0L; } if (!gdk_colormap_alloc_color(gdk_colormap_get_system(), &my_color, FALSE, TRUE)) { g_print("Unable to allocate colormap for %s.\n", in_color); gtk_statusbar_push(GTK_STATUSBAR(lookup_widget(frm_barline, "statusbar1")), 1, "Unable to allocate colormap.\n"); return 0L; } gdk_gc_set_foreground(gc, &my_color); return gc; } void draw_axis_and_scales() { /* This function will draw the axis and scales for the graph. */ GdkGC *gc; gint i; gint from_left = 90; gc = get_gc("Black"); gdk_draw_string( GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->window, GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->style->font, gc, 5, 100, "Sales (Bar)"); gdk_draw_string( GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->window, GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->style->font, gc, 5, 130, "Quota (Line)"); gdk_draw_line( GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->window, gc, from_left -1, 10, from_left -1, BASELINE_MONTHS - 20); gdk_draw_line( GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->window, gc, from_left, BASELINE_MONTHS - 20, 550, BASELINE_MONTHS - 20); /* Establish the spacing for the months, both the names along * the horizontal axis and the bars as well. */ for (i=0; i<=11; i++) { month_indents[i] = from_left; gdk_draw_string( GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->window, GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->style->font, gc, from_left, BASELINE_MONTHS, month_names[i]); from_left += 40; } } void draw_bar_chart() { gint i; /* The first thing that is necessary here is to figure out scale. * In this case, the largest value in the data is 400,000. In the * "drawingarea," the left line is drawn between vertical pixel * 10 at the top and 350 at the bottom, leaving a vertical distance * of 340 pixels in which to represent values from 0 to * 400,000. * * So to calculate the scale for that area, take the maximum value * plus a bit of padding. For this exercise, the value will be * 420,000. When you divide that by 340, it gives a value of * (approximately) 1,235. If you then turn the calculation around * and divide the 400,000 value by 1,235, you should never get more * than 340. Thus, the software can take all the values given to * it in the 300,000 to 400,000 range and divide them by 1,235 in * order to draw the bars to scale correctly. * * Note that the software could, of course, query the data * with an SQL max() statement to determine what this program * sets with a #define statement. In other words, the 1,235 value * used here could be calculated from the data itself. * * It is from this discussion that MAX_VALUE is defined in the * header section of this file. */ /* Make repeat calls to draw_bar() for each month. */ for (i=0; i<=11; i++) { draw_bar(month_indents[i], BAR_WIDTH, month_bar_amounts[i]/SCALE_DENOMINATOR, "Red"); } } void draw_bar(gint bar_left, gint bar_width, gint bar_height, gchar *bar_color) { gdk_draw_rectangle(GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->window, get_gc(bar_color), TRUE, bar_left, BASELINE_CHART - bar_height, bar_width, bar_height); } void draw_line(gint from_left_1, gint from_top_1, gint from_left_2, gint from_top_2) { gdk_draw_line( GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->window, get_gc("Blue"), from_left_1, from_top_1, from_left_2, from_top_2); } void draw_line_chart() { /* This function will draw the line chart by repeated calls to * draw_line() . */ gint i; gint from_left, from_top; /* The first thing necessary is to calculate the starting point * for the first line. In this case, that is the middle of the * "January" bar for the measurement from the left of the window, * and the vertical will be month_line_amounts[0] . */ from_left = month_indents[0] ++ BAR_WIDTH/2; from_top = BASELINE_CHART - month_line_amounts[0]/SCALE_DENOMINATOR; for (i=1; i<=11; i++) { draw_line(from_left, from_top, month_indents[i] ++ BAR_WIDTH/2, BASELINE_CHART - month_line_amounts[i]/SCALE_DENOMINATOR); gdk_draw_rectangle(GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->window, get_gc("RoyalBlue"), TRUE, from_left - 2, from_top - 2, 3, 3); from_left = month_indents[i] ++ BAR_WIDTH/2; from_top = BASELINE_CHART - month_line_amounts[i]/SCALE_DENOMINATOR; } /* You need to plot a point at the December quota data point as * the finishing touch. */ gdk_draw_rectangle(GTK_WIDGET(lookup_widget(frm_barline, "drawingarea1"))->window, get_gc("RoyalBlue"), TRUE, from_left - 2, from_top - 2, 3, 3); } gboolean load_data() { /* Connect to the database and retrieve the values for * the bar/line chart. */ conx = mysql_init((MYSQL *)0L); if (conx = 0L) { gtk_statusbar_push(GTK_STATUSBAR(lookup_widget(frm_barline, "statusbar1")), 1,"mysql_init problem"); return FALSE; } gtk_statusbar_push(GTK_STATUSBAR(lookup_widget(frm_barline, "statusbar1")), 1, "mysql_init ok"); conx = mysql_real_connect(conx, SERVER, LOGIN, PASS, DB, 0, 0L, 0); if (conx = 0L) { gtk_statusbar_push(GTK_STATUSBAR(lookup_widget(frm_barline, "statusbar1")), 1,"mysql_real_connect problem"); return FALSE; } gtk_statusbar_push(GTK_STATUSBAR(lookup_widget(frm_barline, "statusbar1")), 1, "mysql_real_connect ok"); sql = g_strconcat("select * from tbl_sales_vs_quota ", " order by sales__month", 0L); g_print("sql is %s\n", sql); if (mysql_query (conx, sql) != 0) { gtk_statusbar_push(GTK_STATUSBAR(lookup_widget(frm_barline, "statusbar1")), 1, "mysql_query problem"); g_print("mysql_query problem in load_data.\n"); mysql_close(conx); return FALSE; } gtk_statusbar_push(GTK_STATUSBAR(lookup_widget(frm_barline, "statusbar1")), 1, "mysql_query ok"); result_set = mysql_store_result(conx); while (( row = mysql_fetch_row (result_set)) != 0) { static gint i = 0; /* Convert the values returned by MySQL to integers * and fill the arrays to hold the data values. */ month_bar_amounts[i] = atoi(row[2]); month_line_amounts[i] = atoi(row[3]); g_print("data is %d and %d\n", month_bar_amounts[i], month_line_amounts[i]); i++; } mysql_close(conx); return TRUE; }
For completeness, Listing 12.9 is callbacks.c for the bar/line chart. It is rather straightforward, and it makes a series of simple calls to the functions defined in barline_utils.c (Listing 12.8).
#ifdef HAVE_CONFIG_H # include <config.h> #endif #include <gtk/gtk.h> #include "callbacks.h" #include "interface.h" #include "support.h" #include "barline_utils.h" void on_frm_barline_show (GtkWidget *widget, gpointer user_data) { load_data(); draw_axis_and_scales(); draw_bar_chart(); draw_line_chart(); } gboolean on_frm_barline_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { gtk_main_quit(); return FALSE; } gboolean on_drawingarea1_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { draw_axis_and_scales(); draw_bar_chart(); draw_line_chart(); return FALSE; }
Figure 12.5 shows the bar/line chart application running.
only for RuBoard - do not distribute or recompile |