Wxwidgets / Wx Perl grid sizing issues - c++

Ok. I've been stuck on this for several days now and I'm at wits end here. I'm by no means an expert in Perl.
I'm writing a GUI app using WxPerl. To cut down on the noise, I've recreated a portion of the app where I'm having issues. I designed the layout in FormBuilder, then used the resulting XRC file. The XRC data is included below, save it in a file called noname.xrc.
In a nutshell, the GUI has two grids (left and right), with two buttons in the middle. For testing, there's an "add row" button at the top of the main frame, which adds a row to the left grid. I wrote an EVT_SIZE function to adjust the last column of the grid on the left to fill the remaining space, which then modifies the grid on the right in the same way to keep them equal proportions.
Issues:
1) Click the add button 20 times, then adjust the size of the main frame window. Notice how the grid all of a sudden expands and eats up the entire bottom of the frame. Click the add button a few more times and it continues eating up the bottom... I can't seem to get the height to adjust to prevent it from eating up the bottom portion. Maybe there's an obvious form setting I'm missing? Even removing the growablecols flag from the wxGridBagSizer doesn't stop this from happening.
2) An annoying visual issue, which is probably related to the proportional sizing. Basically, there's border padding on each side of the grid (5x2), which is 10. So I've subtracted 11 from the width before it is set, but ideally it should be 10. However, if it's set to 10, when resizing occurs the last column keeps growing forever...
3) If you click the "Maximize" button in the top right corner of the main frame, then click it again (it's called "Restore Down" then), to revert it back to the previous size, you'll see that the right grid never adjusts obviously, since the left grid hasn't changed size which never triggers the EVT_SIZE event... I've been brainstorming how to fix this, maybe the on size event can check the position of the right grid and determine if it's beyond the width of the main frame? Is there an easier way to get this to size properly?
Ideally, I'd like to set minimum sizes for certain grid columns, but have all the columns grow as the main window is resized. But that's probably a pipe-dream at this point.
#!/usr/bin/perl
package wxToplevelFrame;
use strict;
use warnings;
use Wx qw(:everything);
use Wx::Grid;
use Wx::XRC;
use base 'Wx::Frame';
use Data::Dumper;
use diagnostics;
# import event registration function
use Wx::Event qw(:everything);
use base qw(Wx::Panel Class::Accessor::Fast);
__PACKAGE__->mk_ro_accessors( qw(xrc) );
$| = 1;
### GUI CODE BEGINS ###
# create specialized constructor for new subclass
sub new {
my $class = shift;
my $self = $class->SUPER::new();
$self->initialize();
return $self;
}
sub initialize {
my ($self) = #_;
my $xrc_path = 'noname.xrc';
Wx::InitAllImageHandlers();
$self->{ xrc } = Wx::XmlResource->new();
$self->xrc->InitAllHandlers();
$self->xrc->Load($xrc_path);
$self->xrc->LoadFrame($self, undef, 'MyFrame1',);
# main frame close
EVT_CLOSE( $self,
sub {
my ($self) = #_;
$self->Destroy();
}
);
# LEFT GRID
my $grid_left = $self->{ grid_left } = $self->FindWindow('m_grid4');
$grid_left->CreateGrid(0, 3);
$grid_left->SetColLabelSize(25); # label height
$grid_left->SetRowLabelSize(25); # row width (far left, the numbers column basically)
$grid_left->SetColLabelValue(0, 'col_1');
$grid_left->SetColLabelValue(1, 'col_2');
$grid_left->SetColLabelValue(2, 'col_3');
$grid_left->EnableDragColSize(0);
$grid_left->EnableDragRowSize(0);
$grid_left->EnableEditing(0);
$grid_left->SetDefaultRowSize(20);
$grid_left->SetColSize( 0, 190 ); # col 1
$grid_left->SetColSize( 1, 50 ); # col 2
$grid_left->SetColSize( 2, 179 ); # col 3
# RIGHT GRID
my $grid_right = $self->{ grid_right } = $self->FindWindow('m_grid5');
$grid_right->CreateGrid(0, 3);
$grid_right->SetColLabelSize(25); # label height
$grid_right->SetRowLabelSize(25); # row width (far left, the numbers column basically)
$grid_right->SetColLabelValue(0, 'col_');
$grid_right->SetColLabelValue(1, 'col_2');
$grid_right->SetColLabelValue(2, 'col_3');
$grid_right->EnableDragColSize(0);
$grid_right->EnableDragRowSize(0);
$grid_right->EnableEditing(0);
$grid_right->SetDefaultRowSize(20);
$grid_right->SetColSize( 0, 190 ); # col 1
$grid_right->SetColSize( 1, 50 ); # col 2
$grid_right->SetColSize( 2, 179 ); # col 3
#EVT_SIZE( $grid_left, \&on_size ); # adjust grid when size changes
#EVT_SIZE( $grid_right, \&on_size ); # adjust grid when size changes
my $on_size = \&on_size;
EVT_SIZE($grid_left, callback($on_size, $self, $grid_left) );
my $button = $self->{ button } = $self->FindWindow('m_button3');
EVT_BUTTON(
$button,
$button->GetId(),
callback(my $button_sub = \&add_row, $self, $button),
);
my $gui_actions_text_ctrl = $self->FindWindow('m_textCtrl1');
my $gui_log = Wx::LogTextCtrl->new( $gui_actions_text_ctrl );
$self->{ gui_log_text_ctrl } = Wx::Log::SetActiveTarget( $gui_log );
$self->SetStatusBarPane(-1);
return;
}
sub callback {
my $coderef = shift;
my #args = #_;
#print "what is args\n";
#print Dumper \#args;
sub { $coderef->(#args) }
# callback function. when we want to pass addition args to a method call, such as an event (EVT_*), we can use this
# example:
# my $on_size_test = \&on_size_test;
# EVT_SIZE($grid_left, callback($on_size, $grid_left, $self) );
}
sub on_close {
my ($self) = #_;
$self->Destroy();
}
sub on_size {
my ($self, $grid) = #_;
print "in on_size sub\n";
# get the number of columns and the initial width which includes the far left number column (gutter column, with row indicators 1, 2, 3 ...)
my $num_cols = $grid->GetNumberCols();
my $width = $grid->GetRowLabelSize();
my $gutter_col = $width;
print "num_cols: $num_cols\n";
print "initial width: $width\n";
my $col_0;
my $col_1;
my $col_2;
# iterate over each column, get size and add it to our width
for (my $col = 0; $col < $num_cols; $col++) {
# conditionals of no importance currently, but used during testing
if ($col == 0) {
$col_0 = $grid->GetColSize($col);
print "col: $col, width col_0: $col_0\n";
} elsif ($col == 1) {
$col_1 = $grid->GetColSize($col);
print "col: $col, width col_1: $col_1\n";
} elsif ($col == 2) {
$col_2 = $grid->GetColSize($col);
print "col: $col, width col_2: $col_2\n";
}
$width += $grid->GetColSize($col);
}
print "width after iterating over each column: $width\n";
# get sizer that grid is contained in
# get width of sizer and subtract it from the total width
# the difference will be the size we set for our last column
if ($num_cols > 0) {
my $static_box_sizer = $grid->GetContainingSizer();
my $sizer = $static_box_sizer->GetSize();
my $sizer_width = $sizer->GetWidth();
print "sizer_width: $sizer_width\n";
print "we are setting width for the last column. sizer_width: $sizer_width minus the total width: $width (gutter_col: $gutter_col, col_0, col_1, col_2)\n";
my $width_diff = $sizer_width - $width + $col_2 - 11; # ideally this should be 10 for padding (5x2) on each side of sizer
# but setting it at 10 causes the col to keep expanding...
print "width_diff result of above calc: $width_diff\n";
$grid->SetColSize($num_cols - 1, $width_diff); # last column
# adjust grid right to reflect same proportions
$self->{ grid_right }->SetColSize($num_cols - 1, $width_diff); # last column
}
return;
}
sub add_row {
my ($self, $button) = #_;
$self->{ grid_left }->AppendRows(1);
my $col = 0;
foreach my $value ('testing', 100, 'Sat Aug 20 20:52:20 2016') {
my $row;
if ($col == 3) {
$self->{ grid_left }->AppendRows(1);
$row = $self->{ grid_left }->GetNumberRows() - 1; # minus one from total rows
print "col == 2\n";
print "reset\n";
print "what is row: $row\n";
$col = 0;
} else {
$row = $self->{ grid_left }->GetNumberRows() - 1;
}
print "value: $value\n";
$self->{ grid_left }->SetCellValue(
$row,
$col,
$value,
);
if ($col == 1) {
$self->{ grid_left }->SetCellAlignment(
$row,
$col,
wxALIGN_RIGHT,
wxALIGN_CENTRE,
);
} elsif ($col == 2) {
$self->{ grid_left }->SetCellAlignment(
$row,
$col,
wxALIGN_CENTRE,
wxALIGN_CENTRE,
);
}
$col++;
}
}
### GUI CODE ENDS ###
# END: wxToplevelFrame package
# create an app object
package MyApp;
use strict;
use warnings;
use base 'Wx::App';
# OnInit is called automatically when an app object is first constructed
sub OnInit {
my $self = shift;
my $toplevel_frame = wxToplevelFrame->new();
$self->SetTopWindow($toplevel_frame);
$toplevel_frame->Show(1);
}
# END: MyApp package
package main;
use strict;
use warnings;
use Data::Dumper;
$| = 1;
my $app = MyApp->new(); # instantiate our app first
$app->MainLoop();
exit;
XRC file: noname.xrc
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<resource xmlns="http://www.wxwindows.org/wxxrc" version="2.3.0.1">
<object class="wxFrame" name="MyFrame1">
<style>wxCAPTION|wxCLOSE_BOX|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU|wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL</style>
<size>998,700</size>
<title>Grid Issues</title>
<centered>1</centered>
<aui_managed>0</aui_managed>
<object class="wxPanel" name="m_panel6">
<style>wxTAB_TRAVERSAL</style>
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>1</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxFlexGridSizer">
<rows>0</rows>
<cols>6</cols>
<vgap>0</vgap>
<hgap>0</hgap>
<growablecols></growablecols>
<growablerows></growablerows>
<object class="sizeritem">
<option>0</option>
<flag>wxALL</flag>
<border>5</border>
<object class="wxButton" name="m_button3">
<label>add row</label>
<default>0</default>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>3</option>
<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>
<border>5</border>
<object class="wxGridBagSizer">
<vgap>0</vgap>
<hgap>0</hgap>
<growablecols>0,2</growablecols>
<growablerows>0</growablerows>
<object class="sizeritem">
<cellpos>0,0</cellpos>
<cellspan>1,1</cellspan>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxStaticBoxSizer">
<orient>wxHORIZONTAL</orient>
<label>left</label>
<object class="sizeritem">
<option>1</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxGrid" name="m_grid4" />
</object>
</object>
</object>
<object class="sizeritem">
<cellpos>0,1</cellpos>
<cellspan>1,1</cellspan>
<flag>wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL</flag>
<border>5</border>
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>0</option>
<flag>wxALL</flag>
<border>5</border>
<object class="wxButton" name="m_button4">
<style>wxBU_EXACTFIT</style>
<label>></label>
<default>0</default>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxALL</flag>
<border>5</border>
<object class="wxButton" name="m_button5">
<style>wxBU_EXACTFIT</style>
<label><</label>
<default>0</default>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<cellpos>0,2</cellpos>
<cellspan>1,1</cellspan>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxStaticBoxSizer">
<orient>wxHORIZONTAL</orient>
<label>right</label>
<object class="sizeritem">
<option>1</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxGrid" name="m_grid5" />
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>2</option>
<flag>wxEXPAND | wxALL</flag>
<border>5</border>
<object class="wxNotebook" name="m_notebook2">
<object class="notebookpage">
<label>a page</label>
<selected>0</selected>
<object class="wxPanel" name="m_panel2">
<style>wxTAB_TRAVERSAL</style>
<object class="wxBoxSizer">
<orient>wxHORIZONTAL</orient>
<object class="sizeritem">
<option>1</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxTextCtrl" name="m_textCtrl1">
<value></value>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="wxStatusBar" name="m_statusBar1">
<style>wxST_SIZEGRIP</style>
<fields>2</fields>
</object>
</object>
</resource>
Any help greatly appreciated,
Thanks,
-Jdun

There is too much code here to read it all carefully, but one thing that immediately seems suspicious to me is that you don't call $event->Skip() on the event in your on_size handler. The EVT_SIZE handler should almost invariably call Skip() to allow the default handling of the size event to take place, so while it might not explain all of your problems, I'd be surprised if it didn't explain at least some of them.

Related

boost::property_tree XML issue

I am fighting with getting values from the following XML structure:
<ActionMaps version="1" optionsVersion="2" rebindVersion="2" profileName="full_export">
<CustomisationUIHeader label="full_export" description="" image="">
<devices>
<keyboard instance="1"/>
<mouse instance="1"/>
</devices>
<categories>
<category label="#ui_CCSpaceFlight"/>
<category label="#ui_CGLightControllerDesc"/>
<category label="#ui_CCFPS"/>
<category label="#ui_CCEVA"/>
<category label="#ui_CGOpticalTracking"/>
<category label="#ui_CGInteraction"/>
</categories>
</CustomisationUIHeader>
<options type="keyboard" instance="1" Product="Tastatur {6F1D2B61-D5A0-11CF-BFC7-444553540000}">
<flight_move_yaw exponent="1.5"/>
</options>
<modifiers />
<actionmap name="spaceship_general">
<action name="v_close_all_doors">
<rebind input="kb1_0"/>
</action>
<action name="v_cooler_throttle_down">
<rebind input="kb1_6"/>
</action>
<action name="v_cooler_throttle_up">
<rebind input="kb1_5"/>
</action>
<action name="v_eject">
<rebind input="kb1_1"/>
</action>
...
The code I am using is
const std::string XML_PATH = std::string(fqn_file.mb_str());
boost::property_tree::ptree pt1;
boost::property_tree::read_xml( XML_PATH, pt1 );
// Traverse property tree example
BOOST_FOREACH(boost::property_tree::ptree::value_type const& node,
pt1.get_child( "ActionMaps.actionmap" ) ) {
boost::property_tree::ptree subtree = node.second;
if ( node.first == "actionmap" ) {
BOOST_FOREACH(boost::property_tree::ptree::value_type const& v,
subtree.get_child( "" ) ) {
std::string label = v.first;
if ( label != "<xmlattr>" ) {
std::string value = subtree.get<std::string>( label );
wxString m_value(value);
std::cout << label << ": " << value << std::endl;
wxString m_label(label);
wxLogMessage("DEBUG -> Label = " + m_label + " Value = " + value);
}
}
}
}
If I go for 'action' or 'label' the values are empty which seems to be normal. But how I can access name (#name) from action and input (#input) from rebind?
I expect to get e.g. the pair of values 'v_close_all_doors' and 'kb1_0'. Of course I need a second iteration for the second value but for the first I need to understand how to access these values.
I gave up with boost::property_tree as its seems to be designed to handle simple XML structures only. Made more progress using RapidXML

QLabel not responding to `setText()` at the time of calling

I am using the QT IDE to make a better looking version of my (once working) command line auto clicker.
Mind you, the clicking still works great... the functionality is not compromised.
However, the problem comes when 'updating' the text fields on the form itself.
In my code, you can see that pressing the 'Q' button, ends the loop. At this point, the text fields become updated (as they should be continuously during the loop). I'm really not sure why they aren't updating until I hit 'Q'. Is there any reason this isn't supposed to work as I think it should, or is there a way to fix it?
Thanks. See my code below. Mind you, I will only include the bits I believe are necessary. Upon request I can post more code.
CODE.cpp
bool running = 1;
float x = 1500;
float interval;
int breakCounter = 0;
float breakSeconds = 0;
int clicks = 0;
Sleep (3000);
while (running == 1)
{
float breakChance = (rand()%650+1);
if (breakChance == 100){
breakCounter++;
float breakTime = (rand()%180+1);
breakTime = (breakTime + 60) * 1000;
breakSeconds = breakSeconds + breakTime/1000;
QString a = QString::number(breakCounter);
QString b = QString::number(breakSeconds/60);
QString c = QString::number(breakTime/1000);
ui->label_6->setText(a);
ui->label_7->setText(b + " mins");
ui->label_8->setText(c);
ui->label_9->setText("N/A");
Sleep (breakTime);
} else {
float variance = (rand()%500+1);
int flip = (rand()%2+1);
if (flip == 1){
interval = x + variance;
} else {
interval = x - variance;
}
QString a = QString::number(breakCounter);
QString b = QString::number(breakSeconds/60);
QString d = QString::number(interval);
ui->label_6->setText(a);
ui->label_7->setText(b + " mins");
ui->label_8->setText("N/A");
ui->label_9->setText(d);
Sleep (interval);
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
Sleep (100);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
clicks++;
if (GetAsyncKeyState( 'Q' ))
{
running = 0;
}
}
}
CODE.ui
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Current break timer:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>N/A</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Next click time:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>N/A</string>
</property>
</widget>
</item>
</layout>
</item>
Qt's paint messages happen when the application message pump is given a chance to run. What you appear to have here is a loop that keeps your code on the stack and doesn't relinquish control back to the message pump.
If you want delays...the way to do that is with a QTimer. Say how long you want it to be until your code runs next, return out of your code, and give the message pump a chance to run while time passes.

Set Tree Store model in glade by code - GTK Glade TreeStore C++

I have read some manual of Glade and I create a GUI in which there is a TreeView which i want to populate by code. The glade file is:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkWindow" id="tree_window">
<property name="can_focus">False</property>
<property name="border_width">3</property>
<property name="title" translatable="yes">Tree Viewer</property>
<property name="default_width">400</property>
<property name="default_height">600</property>
<signal name="destroy" handler="gtk_main_quit" swapped="no"/>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkTreeView" id="treeview1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkTreeViewColumn" id="aColumn">
<property name="title" translatable="yes">A</property>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="bColumn">
<property name="title" translatable="yes">B</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
So the idea is populate the "treeview1" with a GtkTreeStore that I define in the code below:
#include <gtk/gtk.h>
enum{
A_COL=0,
B_COL
};
GtkTreeModel * fill_gtk_tree_store_from_xml_file()
{
GtkTreeStore * t_model;
t_model=gtk_tree_store_new(2,G_TYPE_UINT,G_TYPE_UINT);
GtkTreeIter toplevel,childlevel;
gtk_tree_store_append(t_model,&toplevel,NULL);
gtk_tree_store_append(t_model,&toplevel,NULL);
gtk_tree_store_append(t_model,&toplevel,NULL);
gtk_tree_store_set(t_model,&toplevel,A_COL,(guint)12,B_COL,(guint)14,-1);
gtk_tree_store_append(t_model, &childlevel, &toplevel);
gtk_tree_store_set(t_model,&childlevel,0,(guint)20,
1,(guint)22,-1);
gtk_tree_store_append(t_model, &childlevel, &toplevel);
return GTK_TREE_MODEL (t_model);
}
#include <gtk/gtk.h>
#include <stdlib.h>
int launchGUI(GtkBuilder *builder,GError *error=NULL)
{
GtkWidget *ventanaPrincipal;
if( ! gtk_builder_add_from_file( builder,"treeStore.glade", &error ) )
{
g_warning( "%s", error->message );
g_free( error );
return( 1 );
}
ventanaPrincipal = GTK_WIDGET(gtk_builder_get_object(builder, "tree_window"));
GtkTreeModel *model;
GtkWidget *view;
model=fill_gtk_tree_store_from_xml_file();
view=GTK_WIDGET(gtk_builder_get_object(builder, "treeview1"));
gtk_tree_view_set_model (GTK_TREE_VIEW (view), model);
gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
GTK_SELECTION_NONE);
gtk_signal_connect(GTK_OBJECT(ventanaPrincipal), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(ventanaPrincipal);
gtk_main();
return 0;
}
int main(int argc,char **argv)
{
GtkBuilder *gtkBuilder;
GError *error = NULL;
gtk_init(&argc, &argv);
gtkBuilder= gtk_builder_new();
launchGUI(gtkBuilder,error);
return EXIT_SUCCESS;
}
I have tried different approaches, using enum, not using enum... The empty rows appear empty (OK), but the rows that should not be empty also appear empty. When I run the code this happens:
image
I don't know what I'm doing wrong, Can anyone help me?
Your code has many construction sides. I will work down a list of those issues that attracted my particular attention.
Don't call it c++ if you stick with gtk+ and use plain c instead
You tagged your question with c++. However you don't use gtkmm but rather gtk+. Therefore you shouldn't intersperse c++ features that are not compatible with standard c.
Related to your code you shouldn't specify default function arguments. That feature is not part of the c programming language and will confuse fellow programmers who work on your code.
Declare variables where you need them and keep your function prototypes clean
Don't unnecessarily pass variables to functions that actually belongs only to the logical scope of the function itself.
For example the function
int launchGUI(GtkBuilder *builder,GError *error=NULL)
uses builder and error only locally so you shouldn't implement them as function arguments.
Furthermore you rarely need the GtkBuilder instance anywhere outside the function that initialize your user interface. So don't mess up functions with unnecessary definitions of local variables.
Check the reference manual not only for function descriptions but also for a conceptual understanding of library features
Don't apply g_free on a GError resource. Structures like GError aren't necessarily flat. Instead use a valid function. With respect to GError you should use g_error_free.
Study the conceptual overview of the GtkTreeModel widget and how to populate it. If you don't do this or study a similar description i see hard times will come upon you.
Don't use deprecated features
Check the code for deprecated features and replace them with the counterparts of the new version of the library.
For example don't use GTK_OBJECT in programs that depends on gtk+-3.0 (I conclude that from your ui definitions file). You can almost always replace gtk_object_ with g_object_ in your code.
Think about what should be defined in the ui definitions file and what should stay in the sources
GtkTreeView is one of the most complex widgets in gtk+ at least in my opinion. It is not enough to set the model of the widgets and create some columns.
At this point it is essential to pack the columns with cell renderers and link colums from your data store/model to specific properties of the particular renderers. Only this way content of the data store will be displayed directly or indirectly on the screen.
That being said you should consider what part of the tree view should be instantiated by methods of GtkBuilder and what should be defined in the code. With respect to your code you have to either get both columns or respectively get the treeview with gtk_builder_get_object or you implement the whole tree view in glade.
To show you a minimal working example of what i guess you want to achieve i decided to delete the columns in glade and just get the instantiated treeview widget in the code. Of course this example is not necessary the last word on the subject. However it displays the tree view with the content of the store on the screen.
I appended a screenshot of the working program and the code.
modfied source code:
#include <gtk/gtk.h>
#include <stdlib.h>
enum
{
A_COL = 0,
B_COL,
COL_NUMBER
};
gchar *title[] = { "Column A", "Column B" };
void
fill_gtk_tree_store (GtkTreeView * view)
{
GtkTreeStore *model;
GtkTreeIter toplevel, childlevel;
GtkTreeViewColumn *column;
GtkTreeSelection *selection;
GtkCellRenderer *renderer;
guint i;
model = gtk_tree_store_new (COL_NUMBER, G_TYPE_UINT, G_TYPE_UINT);
gtk_tree_store_append (model, &toplevel, NULL);
gtk_tree_store_append (model, &toplevel, NULL);
gtk_tree_store_append (model, &toplevel, NULL);
gtk_tree_store_set (model, &toplevel, A_COL, 12, B_COL, 14, -1);
gtk_tree_store_append (model, &childlevel, &toplevel);
gtk_tree_store_set (model, &childlevel, A_COL, 20, B_COL, 22, -1);
gtk_tree_store_append (model, &childlevel, &toplevel);
gtk_tree_view_set_model (view, GTK_TREE_MODEL (model));
selection = gtk_tree_view_get_selection(view);
gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
for (i = 0; i < COL_NUMBER; i++) {
renderer = gtk_cell_renderer_text_new ();
column =
gtk_tree_view_column_new_with_attributes (title[i], renderer,
"text", i, NULL);
gtk_tree_view_append_column (view, column);
}
}
void
launchGUI ()
{
GtkWidget *ventanaPrincipal;
GtkBuilder *builder;
GError *error = NULL;
GtkTreeView *view;
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "treeStoreMod.glade", &error);
if (error != NULL) {
g_warning ("%s", error->message);
g_error_free (error);
exit(1);
}
ventanaPrincipal =
GTK_WIDGET (gtk_builder_get_object (builder, "tree_window"));
view = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview1"));
g_object_unref(builder);
fill_gtk_tree_store (view);
g_signal_connect (G_OBJECT (ventanaPrincipal),
"destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show_all (ventanaPrincipal);
gtk_main ();
}
int
main (int argc, char **argv)
{
gtk_init (&argc, &argv);
launchGUI ();
return 0;
}
modified ui definitions file treeStoreMod.glade:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkWindow" id="tree_window">
<property name="can_focus">False</property>
<property name="border_width">3</property>
<property name="title" translatable="yes">Tree Viewer</property>
<property name="default_width">400</property>
<property name="default_height">600</property>
<signal name="destroy" handler="gtk_main_quit" swapped="no"/>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkTreeView" id="treeview1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

Error getting class type with wxIS_KIND_OF macro

I'm trying to get a wxSizer class type with wxIS_KIND_OF macro.
After few seconds my program finish without show the main window of my app.
This is the code:
wxXmlResource::Get()->LoadFrame((wxFrame*)this, (wxWindow*)NULL , wxT("MyFrame1"));
wxPanel* container = (wxPanel*)FindWindowByName("m_panel1");
if (!container){
cout << "Error loading container!" << endl << flush;
}
else{
for (unsigned int i=0; i<3; i++){
auxPanelArray[i] = new wxPanel( container, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxXmlResource::Get()->LoadPanel( auxPanelArray[i] , wxT("MyPanel6"));
wxSizer* mySizer = auxPanelArray[i]->GetSizer();
if (wxIS_KIND_OF(mySizer, wxStaticBoxSizer)){
cout << "Your sizer is a wxStaticBoxSizer" << endl << flush;
((wxStaticBoxSizer*)mySizer)->GetStaticBox()->SetLabel("My new label");
}
container->GetSizer()->Add(auxPanelArray[i]);
}
}
In my XRC, the sizer type is wxStaticBoxSizer, so wxIS_KIND_OF should detect it and enter inside the if block.
Why it doesn't work?
UPDATE
This is the XRC file:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<resource xmlns="http://www.wxwindows.org/wxxrc" version="2.3.0.1">
<object class="wxPanel" name="MyPanel6">
<style>wxTAB_TRAVERSAL</style>
<object class="wxStaticBoxSizer">
<minsize>100,100</minsize>
<orient>wxVERTICAL</orient>
<label>label</label>
<object class="sizeritem">
<option>1</option>
<flag>wxEXPAND|wxALL</flag>
<border>5</border>
<object class="wxBoxSizer">
<orient>wxHORIZONTAL</orient>
<object class="sizeritem">
<option>0</option>
<flag>wxALL</flag>
<border>5</border>
<object class="wxStaticText" name="m_staticText12">
<label>MyLabel</label>
<wrap>-1</wrap>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxALL</flag>
<border>5</border>
<object class="wxTextCtrl" name="m_textCtrl4">
<value></value>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxALL</flag>
<border>5</border>
<object class="wxButton" name="m_button8">
<label>MyButton</label>
<default>0</default>
</object>
</object>
</object>
</object>
</resource>
wxIS_KIND_OF() must, of course, work for wxStaticBoxSizer, so either the sizer is not of this type or your code is actually executing but doesn't have any effect because your standard output isn't shown anywhere -- which is the case by default in GUI applications under Windows.
I'd also advise to use wxDynamicCast() instead of wxIS_KIND_OF:
wxStaticBoxSizer* boxSizer = wxDynamicCast(mySizer, wxStaticBoxSizer);
if ( boxSizer ) {
... just use it now, no need for more casts ...
}

Reading xml through Qt

I am new to Qt and XML . Please help me on solving this . I shall be greatful to you .
Here is my XML file format
< SiteSpecific>
< SitesList>LocA;LocB;LocC< /SitesList>
< LocA>
< MaterialList>Material_A;Material_B</MaterialList>
<Material Name="Material_A">
<TemperatureList>-65;70;300;400;1000</TemperatureList>
<Density Value="0.286"/>
<PoissonRatio Value="0.27"/>
<Property tempid="01" temp="-65">
<Modulus Value="32.77E+6"/>
<Alpha Value="8.15E-6"/>
<YieldStrength Value="33.90E+3"/>
</Property>
<Property tempid="02" temp="70">
<Modulus Value="29.00E+6"/>
<Alpha Value="8.55E-6"/>
<YieldStrength Value="30.00E+3"/>
= </Property>
<Property tempid="03" temp="300">
<Modulus Value="27.50E+6"/>
<Alpha Value="9.26E-6"/>
<YieldStrength Value="22.40E+3"/>
</Property>
</Material>
</LocA>
< LocB>
< MaterialList>Material_C;Material_D</MaterialList>
<Material Name="Material_C">
<TemperatureList>-65;70;300;400;1000</TemperatureList>
<Density Value="0.286"/>
<PoissonRatio Value="0.27"/>
<Property tempid="01" temp="-65">
<Modulus Value="32.77E+6"/>
<Alpha Value="8.15E-6"/>
<YieldStrength Value="33.90E+3"/>
</Property>
<Material Name="Material_D">
<TemperatureList>-65;70;300;400;1000</TemperatureList>
<Density Value="0.286"/>
<PoissonRatio Value="0.27"/>
<Property tempid="01" temp="-65">
<Modulus Value="32.77E+6"/>
<Alpha Value="8.15E-6"/>
<YieldStrength Value="33.90E+3"/>
</Property>
</Material>
</LocB>
From the above file format i have to extract Materialist(e.g Material_A , Material_B , Material_C , Material_D) , Temperaturelist(e.g. -65,70,300,400,1000) and all the properties (Modulus , alpha and yieldstrength )based on tempid for LocA and LocB .
QDomDocument and QXmlStreamReader are the two main ways to read XML documents the "Qt way." Read the documentation for examples and instructions.
Personally, I prefer QXmlStreamReader, but it does have a learning curve.
Edit: Here's a little sample code, not compiled, to give you the general idea:
//create some struct to store your data
struct material_t
{
QString name;
QList<MatProp> properties; //a list of your temp-modulus-Alpha-Yield entries
}
QList<material_t> readLocation(QXmlStreamReader& xml)
{
QStringList matnames;
QList<material_t> matlist;
while(xml.readNextStartElement())
{
if(xml.name() == "MaterialList")
matnames = xml.readElementText().split(";");
else if(matnames.contains(xml.name().toString()))
matlist.append(readMaterial(xml)); //write your own reader that returns a material_t
else
xml.skipCurrentElement(); //you must skip every unwanted element
}
return matlist;
}
void readStuff(QXmlStreamReader& xml, QList<material_t>& mats)
{
while(xml.readNextStartElement())
{
QStringList sitelist;
if(xml.name() == "SitesList") //key in on the XML node name
{
sitelist = xml.readElementText().split(";");
} else if(sitelist.contains(xml.name().toString()))
{
mats.append(readLocation(xml));
} else //you have to skip every unwanted element
xml.skipCurrentElement();
}
}
int main()
{
QList<material_t> materialist;
QFile file("your path here");
if(file.open(QIODevice::Text | QIODevice::ReadOnly)) //the QIODevice must be open
{
QXmlStreamReader xml(&file);
readStuff(xml, materiallist);
}
//do stuff with materiallist
}