GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Sat Nov 29, 2014 3:35 am

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
 Post subject: Gtkmm - Notebook question about second argument in a functio
PostPosted: Tue Oct 18, 2011 9:11 am 
Offline

Joined: Tue Oct 18, 2011 8:59 am
Posts: 4
Hello,

well it's my first post here. I am learning Gtkmm (without knowing Gtk+) and (of course) I am trying to find my way through "Programming with Gtkmm". Anyway on the example in the Notebook section it uses a connection like:
Code:
m_Notebook.signal_switch_page().connect(sigc::mem_fun(*this,
&ExampleWindow::on_notebook_switch_page) ); //where is the 2nd argument here?

void ExampleWindow::on_notebook_switch_page(GtkNotebookPage* /* page */, guint page_num)
{ std::cout << "Switched to tab with index " << page_num << std::endl; }


Nothing fancy here:
Code:
m_Notebook
is a
Code:
Gtk::Notebook


My question is where did the second argument in
Code:
on_notebook_switch_page()
come from? I mean in the signal connection obviously only a single argument passes. Is there a default second argument taking the current page or what?

Also is there a way to find the prototype of this
Code:
virtual
function. I couldn't track it down on Notebook reference.

Thanks for any help.


Top
 Profile  
 
 Post subject: Re: Gtkmm - Notebook question about second argument in a fun
PostPosted: Wed Oct 19, 2011 6:32 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 781
Location: UK
Hi and welcome,

You do not say which version of Gtkmm you are using, but by looking at the code sample it could be version 2. The way the signal signal_switch_page() is handled between versions 2 and 3 is different.

Under version 2 your call-back should look like this
Code:
void on_my_switch_page(GtkNotebookPage* page, guint page_num)

Under version 3 your call-back should look like
Code:
void on_my_switch_page(Gtk::Widget* page, guint page_num)


Note that GtkNotebookPage is deprecated and should not be used.

When connected to the signal_switch_page() signal the call-back is called every time the page in the notebook is changed. The first argument is a pointer to the widget contained in the current page, the second argument is the index number of the page. These arguments are set by GTK.

I am not sure what you mean by the prototype of "virtual". This is part of C++ and changes the way a member function of a class can be used. So if you derive a new class from and existing one that has a virtual function you can over-ride that one with yours and that would be called instead of the default one even from the base class.

This is used in Gtkmm for signals, so if you derive a class from a gtkmm widget you could connect your call-backs by over riding the default signal handlers in the class.

This is is in the reference document for gtkmm.

E.

_________________
E.


Top
 Profile  
 
 Post subject: Re: Gtkmm - Notebook question about second argument in a fun
PostPosted: Thu Oct 20, 2011 7:13 pm 
Offline

Joined: Tue Oct 18, 2011 8:59 am
Posts: 4
Thanks for the reply. I know what virtual function means. I couldn't find the prototype of these functions so as to examine if there are any default arguments like I said.

Quote:
These arguments are set by GTK

This means that arguments pass automatically by Gtk in the function when called? That's why it has access to
Code:
page_num
inside the function?

I have found other function like:
Code:
m_button2.signal_clicked().connect(sigc::bind<-1, Glib::ustring>(
sigc::mem_fun(*this, &HelloWorld::on_button_clicked), "button 2"));

where a second argument
Code:
"button 2"
is explicitly passed to function
Code:
on_button_clicked
. What's different in this case?


Top
 Profile  
 
 Post subject: Re: Gtkmm - Notebook question about second argument in a fun
PostPosted: Fri Oct 21, 2011 8:18 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 781
Location: UK
Much of gtkmm is at its web site http://www.gtkmm.org/ with links to documentation there which shows what arguments are passed for a given signal. The number and types of the arguments vary from signal to signal, so it is always good to check with the documentation.

With the signal handling library used by gtkmm you can bind extra arguments and define the value to be passed if you manually connect the signal and not over-ride it. On its own this may not sound to help full, but if you have a call-back that excepts signals from multiple buttons for example, you could use the extra argument as an identifier of the button.

Also going back, the number and types of arguments are the same for both manually connectible and over-ridden signals. But not all signals are available to be over-ridden

E.

_________________
E.


Top
 Profile  
 
 Post subject: Re: Gtkmm - Notebook question about second argument in a fun
PostPosted: Tue Oct 25, 2011 1:23 pm 
Offline

Joined: Tue Oct 18, 2011 8:59 am
Posts: 4
Ok if that helps the code I am talking about is:
http://61.153.44.88/gtkmm/gtkmm-2.4/tutorial/html/sec-multi-item-containers.html
for the improved helloworld example, and
http://61.153.44.88/gtkmm/gtkmm-2.4/tutorial/html/sec-multi-item-containers.html#figure-notebook
for the second example


Top
 Profile  
 
 Post subject: Re: Gtkmm - Notebook question about second argument in a fun
PostPosted: Wed Oct 26, 2011 10:03 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 781
Location: UK
Hi, I can now see why you are getting confused. In these examples the programmer has called the member functions "virtual" so that they could be over ridden. But in this case they are not over ridden and do not over ride any other member function. In the new tutorial for GTKmm 3 these examples have been written with-out the use of "virtual". I think to make it clearer for beginners.

examplewindow.h
Code:
#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include <gtkmm.h>

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow();
  virtual ~ExampleWindow();

protected:
  //Signal handlers:
  virtual void on_button_quit();
  virtual void on_notebook_switch_page(GtkNotebookPage* page, guint page_num);

  //Child widgets:
  Gtk::VBox m_VBox;
  Gtk::Notebook m_Notebook;
  Gtk::Label m_Label1, m_Label2;

  Gtk::HButtonBox m_ButtonBox;
  Gtk::Button m_Button_Quit;
};

#endif //GTKMM_EXAMPLEWINDOW_H

This header defines our class "ExampleWindow" which if derived from "Gtk::Window", so it gains all the properties of a Gtk::Window plus what ever is defined in this class . There are two public member functions, the constructor and the destructor. The destructor is virtual so that at destruction time the destructor for ExampleWindow is first called then the destructor Gtk::Window.

Within the protected section there are two member functions that are our signal handlers. They are defined as virtual here, but do not need to be and do not over ride anything here. The names of these functions could be anything, but the number and types of arguments must match the signal they would be connected to. Also defined are various widgets which would be constructed before our constructor code is called.

examplewindow.cc
Code:
#include <iostream>
#include "examplewindow.h"

ExampleWindow::ExampleWindow()
: m_Label1("Contents of tab 1"),
  m_Label2("Contents of tab 2"),
  m_Button_Quit("Quit")
{
  set_title("Gtk::Notebook example");
  set_border_width(10);
  set_default_size(400, 200);


  add(m_VBox);

  //Add the Notebook, with the button underneath:
  m_Notebook.set_border_width(10);
  m_VBox.pack_start(m_Notebook);
  m_VBox.pack_start(m_ButtonBox, Gtk::PACK_SHRINK);

  m_ButtonBox.pack_start(m_Button_Quit, Gtk::PACK_SHRINK);
  m_Button_Quit.signal_clicked().connect(sigc::mem_fun(*this,
              &ExampleWindow::on_button_quit) );

  //Add the Notebook pages:
  m_Notebook.append_page(m_Label1, "First");
  m_Notebook.append_page(m_Label2, "Second");

  m_Notebook.signal_switch_page().connect(sigc::mem_fun(*this,
              &ExampleWindow::on_notebook_switch_page) );

  show_all_children();
}

ExampleWindow::~ExampleWindow()
{
}

void ExampleWindow::on_button_quit()
{
  hide();
}

void ExampleWindow::on_notebook_switch_page(GtkNotebookPage* /* page */, guint page_num)
{
  std::cout << "Switched to tab with index " << page_num << std::endl;

  //You can also use m_Notebook.get_current_page() to get this index.
}

Even before we enter the code for our constructor the default constructor for two of the labels and a button is changed so that the text is set. The rest of the code sets properties and places the widgets to create the user interface, connects the two signals and shows all the child widgets of the window.

This is the code that connects the "clicked" signal of the Gtk::Button.
Code:
  m_Button_Quit.signal_clicked().connect(sigc::mem_fun(*this,
              &ExampleWindow::on_button_quit) );

Our widget is m_Button_Quit and is a Gtk::Button. This has a member function called signal_clicked() which in turn has a member function called connect(const SlotType& slot, bool after=true). Here we ignore the second argument to connect as using the default is what is nearly always needed and saves typing. To create the "slot" the function used is sigc::mem_fun(obj, someclass::somemethod). Here the first argument is "*this" and says that our signal handler will use this class object. The second argument is the address of ExampleWindow::on_button_quit() and will be the signal handler to be called when the button is clicked on. Note that the number and types of arguments of the signal handler must match that of the signal or the compiler will give errors.

The code to connect the other signal follows a similar pattern.

To find out what arguments are passed you will need to look at the documentation.
Code:
Glib::SignalProxy0< void >    Gtk::Button::signal_clicked ()

This shows that signal_clicked does not receive any arguments and does not return any value.
Code:
Glib::SignalProxy2< void,
GtkNotebookPage*, guint >    Gtk::Notebook::signal_switch_page ()

This shows that signal_switch_page receives twos arguments - GtkNotebookPage * and guint and does not return any value.

The destructor for ExampleWindow does nothing apart from the default destruction of its members (the widgets) followed by Gtk::Window.

The signal handlers are fairly simple. void ExampleWindow::on_button_quit() is called when the button with the label "Quit" is clicked. This calls hide() which hides the window and hence exits the Gtk main loop.

The signal handler void ExampleWindow::on_notebook_switch_page(GtkNotebookPage* /* page */, guint page_num) is called when the currently selected page is changed. Here the first argument is ignored and its use is deprecated and its type and meaning changes in GTK 3. The second argument is the page number of the notebook widget that is now selected. This value is printed with a message to std::cout.

main.cc
Code:
#include <gtkmm/main.h>
#include "examplewindow.h"

int main(int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);

  ExampleWindow window;
  //Shows the window and returns when it is closed.
  Gtk::Main::run(window);

  return 0;
}

This is the main function which creates the Gtk::Main, then our window with its widgets then runs it all until the window is closed or hidden.

That's part 1 done. I do hope that helps you. This shows you one way of connecting signals under GTKmm. Signals under GTKmm is fairly complex as there is so much that you can do with them, plus the addition of connecting via over riding virtual member function. Also for those that are new to GTK in general where the arguments come from can at first be confusing, it does not matter what programming language you are using.

Part 2 - hopefully later today.
E.

_________________
E.


Top
 Profile  
 
 Post subject: Re: Gtkmm - Notebook question about second argument in a fun
PostPosted: Thu Oct 27, 2011 1:33 pm 
Offline

Joined: Tue Oct 18, 2011 8:59 am
Posts: 4
Ok thanks a lot. I mean it. I think you did a great job explaining this topic.
Seeing forward for the second part...


Top
 Profile  
 
 Post subject: Re: Gtkmm - Notebook question about second argument in a fun
PostPosted: Thu Oct 27, 2011 5:44 pm 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 781
Location: UK
Hello and welcome to part 2.

helloworld.h
Code:
#ifndef GTKMM_EXAMPLE_HELLOWORLD_H
#define GTKMM_EXAMPLE_HELLOWORLD_H

#include <gtkmm/button.h>
#include <gtkmm/box.h>
#include <gtkmm/window.h>

class HelloWorld : public Gtk::Window
{
public:
  HelloWorld();
  virtual ~HelloWorld();

protected:

  // Signal handlers:
  // Our new improved on_button_clicked(). (see below)
  virtual void on_button_clicked(Glib::ustring data);

  // Child widgets:
  Gtk::HBox m_box1;
  Gtk::Button m_button1, m_button2;
};

#endif // GTKMM_EXAMPLE_HELLOWORLD_H

Like before our class HelloWorld is derived from a Gtk::Window and follows a similar way of defining the constructor, destructor, widgets that would be placed within this window and the definition of our one and only signal handler. Again it does not need to be virtual, but this time the handler will be connected to two buttons. Also normally the signal that it will be connected to "signal_clicked()" does not take any arguments, but here there is one called Glib::ustring. In the constructor we will use a method to bind extra arguments.

helloworld.cc
Code:
#include "helloworld.h"
#include <iostream>

HelloWorld::HelloWorld()
: m_button1("Button 1"),
  m_button2("Button 2")
{
  // This just sets the title of our new window.
  set_title("Hello Buttons!");

  // sets the border width of the window.
  set_border_width(10);

  // put the box into the main window.
  add(m_box1);

  // Now when the button is clicked, we call the "on_button_clicked" function
  // with a pointer to "button 1" as it's argument
  m_button1.signal_clicked().connect(sigc::bind<Glib::ustring>(
              sigc::mem_fun(*this, &HelloWorld::on_button_clicked), "button 1"));

  // instead of gtk_container_add, we pack this button into the invisible
  // box, which has been packed into the window.
  // note that the pack_start default arguments are Gtk::EXPAND | Gtk::FILL, 0
  m_box1.pack_start(m_button1);

  // always remember this step, this tells GTK that our preparation
  // for this button is complete, and it can be displayed now.
  m_button1.show();

  // call the same signal handler with a different argument,
  // passing a pointer to "button 2" instead.
  m_button2.signal_clicked().connect(sigc::bind<-1, Glib::ustring>(
              sigc::mem_fun(*this, &HelloWorld::on_button_clicked), "button 2"));

  m_box1.pack_start(m_button2);

  // Show the widgets.
  // They will not really be shown until this Window is shown.
  m_button2.show();
  m_box1.show();
}

HelloWorld::~HelloWorld()
{
}

// Our new improved signal handler.  The data passed to this method is
// printed to stdout.
void HelloWorld::on_button_clicked(Glib::ustring data)
{
  std::cout << "Hello World - " << data << " was pressed" << std::endl;
}

Like in the note book example the constructor puts text into the buttons, places all the widgets into the window and then shows them. It also connects the signal_clicked() of both buttons to the same signal handler void HelloWorld::on_button_clicked(Glib::ustring data);
Code:
  m_button1.signal_clicked().connect(sigc::bind<Glib::ustring>(
              sigc::mem_fun(*this, &HelloWorld::on_button_clicked), "button 1"));

Here things are slightly different. By using the function sigc::bind<>() it is possible to add extra arguments to be passed to the signal handler. In this case the type of the extra argument is Glib::ustring and the value to be passed is "button 1". Note that the value passed to the signal handler will be what has been passed to the sigc::bind<>() function. Using this to add extra arguments is not used often, but can some times be use full such as when there is several similar menu items, buttons etc...

The signal handler void HelloWorld::on_button_clicked(Glib::ustring data); is called when ever one of the buttons is clicked on. Because we have used bind to add the extra arguments, when m_button1 is clicked "button 1" is passed to the handler and m_button2 is clicked "button 2" is passed.

main.cc
Code:
#include <gtkmm/main.h>
#include "helloworld.h"

int main (int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);

  HelloWorld helloworld;
  //Shows the window and returns when it is closed.
  Gtk::Main::run(helloworld);

  return 0;
}

This is almost exactly the same as the note book example, but works with the HelloWorld class instead.

Hope this explains the extra arguments to the signal handler. Also again no signal was over-ridden.

E.

_________________
E.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: Google [Bot] and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group