Re: Update progress bar without returning to main loop?
- From: Bob Caryl <bob fis-cal com>
- To: Murray Cumming <murrayc murrayc com>
- Cc: gtkmm-list gnome org
- Subject: Re: Update progress bar without returning to main loop?
- Date: Tue, 27 Sep 2005 06:58:57 -0500
Murray Cumming wrote:
I'd still like someone to create an example for gtkmm of updating a
progressbar while doing intensive processing.
The following code is a snippet from a class that does employee record
setup. The class is derived from Gtk::Window and its declaration follows:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// code begins
#ifndef __FISCAL_EMPLOYEE_
#define __FISCAL_EMPLOYEE_
#include <gtkmm.h>
#include <gtkmm/window.h>
#include <gtkmm/button.h>
#include <gtkmm/table.h>
#include <gtkmm/liststore.h>
#include <gtkmm/treeview.h>
#include "libpq-fe.h"
#include "libpq/libpq-fs.h"
#include "maskedentry.h"
#include <syslog.h>
#include <iostream>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <gdk/gdk.h>
class MonthMarks
{
public:
MonthMarks(gint y, gint m);
gint year;
gint month;
gint marked_dates[31];
};
class Employee : public Gtk::Window
{
public:
Employee(void);
~Employee(void);
gboolean connect_database(void); //
function connects to the database AFTER
bool appIsReady;
protected:
struct tm tm;
GPtrArray *marks;
gint records;
Glib::ustring menu;
Glib::ustring oldmenu;
Glib::ustring daysoff; //
ustring for xml of scheduled days off
Glib::ustring hoursoff;
// ustring for xml of hours off week template
PGconn *empdb; //
connection pointer for cashier database
gint sortcolumn;
gboolean new_record;
gboolean browse_state; //
TRUE = browsing, FALSE = editing
gboolean deleting_row; //
TRUE = deleting a row for a non-existant record
// Column record class to create a column record
class ModelColumns : public Gtk::TreeModel::ColumnRecord
{ //
for use in our treeview object
public:
ModelColumns()
{ add(m_id_text); add(m_name_text); }
Gtk::TreeModelColumn<Glib::ustring> m_id_text; //
column template for cashier ID
Gtk::TreeModelColumn<Glib::ustring> m_name_text; //
column template for cashier NAME
};
ModelColumns m_columns;
// columns for Gtk::ListStore object
Glib::RefPtr<Gtk::ListStore> list; //
our listore object for the treeview
Glib::RefPtr<Gtk::TreeSelection> table_sel;
// selection for the treeview
GPtrArray *buttons;
// array for commandline button
Gtk::Table *table; //
master format table object
Gtk::Table *personal_table;
Gtk::Notebook notebook;
// note book object for scheduling
Gtk::TreeView *tree; //
tree view to display list store
Gtk::TreeView *hour_tree; //
tree view to display hours off TreeStore
Glib::RefPtr<Gtk::TreeStore> hlist;
class HourColumns : public Gtk::TreeModel::ColumnRecord
// for use in our hours off treeview object
{
public:
HourColumns(){ add(m_day); add(m_check);add(m_day_text);}
Gtk::TreeModelColumn<Glib::ustring> m_day; //
column for day text
Gtk::TreeModelColumn<Glib::ustring> m_day_text;
Gtk::TreeModelColumn<bool> m_check; //
column for check button
};
HourColumns m_hcolumns;
Gtk::Label employee_id;
Gtk::Entry *search;
Gtk::ComboBoxText *search_type;
Gtk::Entry *lookup_entry;
Gtk::Calendar calendar;
MaskedEntry *name;
MaskedEntry *firstname;
MaskedEntry *ssn;
MaskedEntry *addr1;
MaskedEntry *addr2;
MaskedEntry *city;
MaskedEntry *state;
MaskedEntry *zip;
MaskedEntry *phone;
MaskedEntry *dob;
Gtk::ComboBoxText *profitcenter;
Gtk::Label *cashierid;
MaskedEntry *hiredate;
Gtk::ComboBoxText *job;
MaskedEntry *pass1;
MaskedEntry *pass2;
MaskedEntry *logdiv;
Gtk::ComboBoxText *paymethod;
Gtk::ComboBoxText *commtype;
Gtk::ComboBoxText *trust;
Gtk::ComboBoxText *weight;
Gtk::Button *cashedit;
Gtk::Button *menuedit;
MaskedEntry *baserate;
void setup_commandline(void);
void setup_lookup_group(void);
void setup_password(void);
void setup_personal(void);
void setup_job(void);
void set_edits_data(Glib::ustring key);
void on_button_clicked(gint i);
void set_widget_sensitivity(gint toggle);
void on_edit_cashier(void);
void on_edit_menu(void);
void on_column_clicked(gint column);
void wait_on_system(void);
void on_row_changed(void);
int update_database(gint whichone);
void delete_record(void);
bool on_entry_key_event(GdkEventKey *key);
gboolean add_record(void);
void delete_row(void);
void setup_scheduling(void);
void populate_daysoff(void);
void populate_hoursoff(void);
void get_daysoff(void);
void get_hoursoff(void);
void SetupDaysoff(xmlNode *cur);
void SetupHoursoff(xmlNode *cur);
void on_calendar_double_clicked(void);
void on_calendar_month_changed(void);
void on_child_toggled(Glib::ustring str);
void check_all_children(Gtk::TreeModel::Children& children,bool
condition);
void on_search(void);
int on_F1_pressed(Gtk::Widget *widget, GdkEventKey *keyevent); //
help display
};
#endif
// code ends
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Code that follows illustrates how I display my progress bar while
populating a Gtk::ListStore widget from a data table in a PostgreSQL
database:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// code begins
void Employee::wait_on_system(void)
{
while(Gtk::Main::instance()->events_pending())
Gtk::Main::instance()->iteration();
}
#define NUM_QUERY "select employee_id, employee_name, employee_firstname
from employee where substr(employee_id,0,%d)=\'%s\' order by employee_id"
#define NAME_QUERY "select employee_id, employee_name,
employee_firstname from employee where employee_name~*\'%s\' or
employee_firstname~*\'%s\' order by employee_id"
// function retrieves all records from employee data table that match a
search image entered by the user and insert them into a ListStore while
displaying a progress bar in a popup window.
void Employee::on_search(void)
{
gchar *buf;
Gtk::MessageDialog *db;
Gtk::Window *progress;
Glib::ustring error_str;
Glib::ustring ID;
Glib::ustring NAME;
Gtk::TreeModel::iterator iter;
Gtk::TreeModel::Row row;
PGresult *table_rows; //
row pointer for table queries
gchar *test;
progress = new Gtk::Window();
progress->set_position(Gtk::WIN_POS_CENTER_ALWAYS); //
set window position to center of the screen
progress->set_border_width(5);
progress->set_title(" Initialization Progress ");
Gtk::Label *label = manage(new Gtk::Label(""));
label->set_text(Glib::ustring("Searchng, please wait. . ."));
label->show();
Gtk::ProgressBar *pb = manage(new Gtk::ProgressBar());
Gtk::VBox *vbox = manage(new Gtk::VBox(FALSE,5));
vbox->pack_start(*label);
vbox->pack_start(*pb);
progress->add(*vbox);
progress->show_all_children();
progress->show_now();
// allow the main loop to iterate
wait_on_system();
browse_state = POPULATE_STATE;
list->clear();
if(search_type->get_active_text() == "Number")
buf = g_strdup_printf(NUM_QUERY, search->get_text().length()+1,
(char *)search->get_text().c_str());
else
buf = g_strdup_printf(NAME_QUERY, (char
*)search->get_text().c_str(), (char *)search->get_text().c_str());
// this call is asynchronus and I cannot do anything here but wait
for its return (tests show that even 10,000 records has
// retrieval times in terms of milliseconds depending upon network
traffic)
table_rows = PQexec(empdb, buf);
g_free(buf);
// if this query fails, the notify the user and go away.
if( PQresultStatus(table_rows) != PGRES_TUPLES_OK )
{
progress->hide();
delete progress;
Glib::ustring buf = PQresultErrorMessage(table_rows);
Glib::ustring error_str = "Database query failed.Reported error-> ";
error_str += buf;
db = new Gtk::MessageDialog (
*this,
error_str,
TRUE,
Gtk::MESSAGE_ERROR,
Gtk::BUTTONS_OK,
TRUE
);
Glib::RefPtr<Gdk::Pixbuf> fis_icon =
Gdk::Pixbuf::create_from_inline(-1,fisicon_inline,FALSE);
db->set_icon(fis_icon);
db->set_position(Gtk::WIN_POS_CENTER_ALWAYS); // set
window position to center of the screen
db->run();
delete db;
PQclear(table_rows);
return;
}
records = PQntuples(table_rows);
// if no tuples then report it and go away
if(!records)
{
Glib::ustring buf = PQresultErrorMessage(table_rows);
Glib::ustring error_str = "No records found for ";
error_str += search->get_text();
db = new Gtk::MessageDialog (
*this,
error_str,
TRUE,
Gtk::MESSAGE_ERROR,
Gtk::BUTTONS_OK,
TRUE
);
Glib::RefPtr<Gdk::Pixbuf> fis_icon =
Gdk::Pixbuf::create_from_inline(-1,fisicon_inline,FALSE);
db->set_icon(fis_icon);
db->set_position(Gtk::WIN_POS_CENTER_ALWAYS); // set
window position to center of the screen
db->run();
delete db;
delete progress;
PQclear(table_rows);
search->grab_focus();
return;
}
gdouble progress_fraction = (gdouble)(1.00/(gdouble)records);
// loop to populate the ListStore. Unless there are literally
thousands of records to
// display, the progress bar barely displays enough to be seen
before the loops terminates
for (gint i = 0; i < records; i++)
{
// if the id data is NULL, then we don't want this
// record.. even though the database is designed such
// that this field cannot be null.
if(!strlen(PQgetvalue(table_rows,i,0)))
continue;
test = PQgetvalue(table_rows,i,0);
// update the progress bar and wait for the main loop to display
the change
pb->set_fraction((gdouble)((gdouble)i*progress_fraction));
wait_on_system();
ID = PQgetvalue(table_rows,i,0);
NAME = PQgetvalue(table_rows,i,1);
if(!PQgetisnull(table_rows,i,2))
{
NAME += ", ";
NAME += PQgetvalue(table_rows,i,2);
}
row = *(iter = list->append());
row[m_columns.m_id_text] = ID;
row[m_columns.m_name_text] = NAME;
}
PQclear(table_rows);
progress->hide();
delete progress;
browse_state = BROWSE_STATE;
Gtk::TreeModel::Path *path = new Gtk::TreeModel::Path("0");
tree->set_cursor(*path);
delete path;
search->set_text("");
lookup_entry->grab_focus();
}
// code ends
/////////////////////////////////////////////////////////////////////////////////////////////////////////
It may be clunky, but it works well.
Bob Caryl
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]