C++ Gtkmm Tutorial 6

22 June , 2014 bill C++ Programming

Introduction
In Part 6 of this Gtkmm tutorial series I will show you how to change the color and style of a button by changing the child widget of the button. I will also show you how to show and manage child windows.

Button Styles
Changing the color or style of the text on a Gtk Button is easy and can be accomplished by changing the child widget of the button. Grids and Boxes can be added to the button for more detailed styles. In this tutorial I will add a styled Gtk Label using markup as a child to the button.

Child Windows
Child windows can not be managed by Gtk and must be managed by the application. In attempting to have Gtk manage a child window will result in the following warning being displayed:

gtkmm-WARNING **: gtkmm: Attempt to call Gtk::manage() on a Gtk::Window, but a Gtk::Window has no parent container to manage its lifetime.

In this tutorial I wanted to go the extra mile and explain how to manage multiple child windows. When a window is created the handles have to be stored so they can be deleted when the child window or parent (main) window is closed.

The Code

See previous tutorials on how to set up the project in the Code::Blocks IDE.

main.cpp

#include <gtkmm.h>
#include "mywindow1.h"

int main(int argc, char *argv[])
{
    Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "com.gtkmm.tutorial6.base");

    mywindow1 window;

    return app->run(window);
}

mywindow1.h

#ifndef MYWINDOW1_H
#define MYWINDOW1_H

#include <gtkmm.h>
#include "mywindow2.h"

class mywindow1 : public Gtk::Window
{
    public:
        mywindow1();
        virtual ~mywindow1();
    protected:
    private:
        int windowcnt = 0;

    struct mypopup
    {
        int windowid;
        mywindow2 *popup;
    };
    void on_b1_click();
    void on_popup_close(mypopup *popup);
    std::map<int, mypopup*> popups;
};

#endif // MYWINDOW1_H

mywindow1.cpp

#include "mywindow1.h"

#include <iostream>
#include <sstream>

mywindow1::mywindow1()
{
    set_default_size(400, 200);
    set_title("Tutorial 6");


    Gtk::Label *b1label =Gtk::manage(new Gtk::Label);
    b1label->set_markup("<b><i><span color='blue'>Open Popup</span></i></b>");
    Gtk::Button *b1 = Gtk::manage(new Gtk::Button);
    b1->add(*b1label);
    b1->signal_clicked().connect(sigc::mem_fun(*this, &mywindow1::on_b1_click));

    add(*b1);

    show_all_children();
}

mywindow1::~mywindow1()
{
    std::map<int, mypopup*>::iterator iter;
    for (iter = popups.begin(); iter != popups.end(); iter++)
    {
        mypopup *popup = iter->second;

        std::stringstream ss;
        ss << "Deleting Window '" << iter->first << "'";
        std::cout << ss.str() << std::endl;

        delete popup->popup;
        delete popup;
    }
}

void mywindow1::on_b1_click()
{
    mypopup *popup = new mypopup;
    popup->popup = new mywindow2;
    popup->windowid = windowcnt;

    std::stringstream ss;
    ss << "Tutorial 6 - New Popup '" << windowcnt << "'";
    popup->popup->set_title(ss.str());
    popup->popup->signal_hide().connect(sigc::bind<mypopup*>(sigc::mem_fun(*this, &mywindow1::on_popup_close), popup));

    popups[windowcnt] = popup;
    windowcnt++;

    popup->popup->show();
}

void mywindow1::on_popup_close(mypopup *popup)
{
    std::stringstream ss;

    ss << "Deleting Window '" << popup->windowid << "'";
    std::cout << ss.str() << std::endl;

    popups.erase(popup->windowid);
    delete popup->popup;
    delete popup;
}

mywindow2.h

#ifndef MYWINDOW2_H
#define MYWINDOW2_H

#include <gtkmm.h>

class mywindow2 : public Gtk::Window
{
    public:
        mywindow2();
        virtual ~mywindow2();
    protected:
    private:
};

#endif // MYWINDOW2_H

mywindow2.cpp

#include "mywindow2.h"

mywindow2::mywindow2()
{
    set_default_size(400, 200);

    Gtk::Label *label = Gtk::manage(new Gtk::Label("New Popup Window"));

    add(*label);

    show_all_children();
}

mywindow2::~mywindow2()
{
    //dtor
}

gtkmm_tutorial6_childwindows
The above image shows the parent window that has a button with blue styled text, 2 child windows and a terminal showing that 1 child window has been closed with the memory managed. It displays the ID of the window that was closed in the terminal.

Explaining The Code
In main.cpp there is nothing new to explain from previous tutorials.

There is nothing to really explain in mywindow2.h and mywindow2.cpp. mywindow2 just inherits a Gtk::Window and puts a label in it. Previous tutorials in this series will explain this.

mywindow1.h
The structure that holds the child window id and window itself is in this header. The child window counter is also defined in this file as well.

int windowcnt = 0;

Above is a variable that is used to identify child windows.

struct mypopup
{
    int windowid;
    mywindow2 *popup;
};

Above is a structure that defines a structure for keeping track of open child windows. The structure is needed as it is passed to the on_popup_close when a child window is closed. The mywindow2 is needed as it needs to be deleted and the windowid is needed to remove the structure from the map.

void on_b1_click();

Above defines the function that is called by the button on the parent (main) window to open a child window.

void on_popup_close(mypopup *popup);

Above defines the function that is called when a child window is closed. The mypopup structure is passed to this function when it is called.

std::map<int, mypopup*> popups;

Above is the map that is defined for holding the information (mypopup structures) of all the open child windows. This is needed for when the main window is closed and the open child windows can be deleted.

mywindow1.cpp
I will be only explaining what has not been explained in previous tutorials here.

Gtk::Label *b1label =Gtk::manage(new Gtk::Label);
b1label->set_markup("Open Popup");
Gtk::Button *b1 = Gtk::manage(new Gtk::Button);
b1->add(*b1label);
b1->signal_clicked().connect(sigc::mem_fun(*this, &mywindow1::on_b1_click));

Above creates a label and sets the markup to style the label. The label is then added to the button as a child. A signal is connected for when the button is clicked to call on_b1_click.

std::map<int, mypopup*>::iterator iter;
for (iter = popups.begin(); iter != popups.end(); iter++)
{
    mypopup *popup = iter->second;

    std::stringstream ss;
    ss << "Deleting Window '" << iter->first << "'";
    std::cout << ss.str() << std::endl;
    delete popup->popup;
    delete popup;
}

Above is a destructor that is called when the main window is closed. It uses an iterator to loop through the map (popups) then displays in the terminal what is about to be deleted then deletes the window and the structure. This is why the map is needed and the pointers to the window and structures are saved in it.

mypopup *popup = new mypopup;
popup->popup = new mywindow2;
popup->windowid = windowcnt;

Above creates a new mypopup structure as popup, creates a new mywindow2 in the structure as popup->popup, and assigns a window id from the windowcnt variable as popup->windowid.

std::stringstream ss;
ss << "Tutorial 6 - New Popup '" << windowcnt << "'"; popup->popup->set_title(ss.str());

Above uses the stringstream to create a string with the windowcnt integer appended to it. The string is then used as the new child windows title.

popup->popup->signal_hide().connect(sigc::bind<mypopup*>(sigc::mem_fun(*this, &mywindow1::on_popup_close), popup));

The above connects a signal that will call on_popup_close when the child window is closed and pass the mypopup structure to it that was created to store the window and id.

popups[windowcnt] = popup;
windowcnt++;

Above adds the mypopup structure to the popups map indexed by the windowcnt variable which is used as the window id. The windowcnt variable is then incremented.

std::stringstream ss;

ss << "Deleting Window '" << popup->windowid << "'";
std::cout << ss.str() << std::endl; popups.erase(popup->windowid);
delete popup->popup;
delete popup;

Above is what is called when an individual child window is closed. Just like the destructor the window id is displayed in the terminal and the window and structure is deleted. The difference is the structure is erased from the popups map.

To Come
I am still planning on posting a game that will use what was learnt from all tutorials in the series. This tutorial was a special request from a reader “Joe W.” who wanted to know how to display a pop up window and color the text of a button.

callback, gui, how to, linux, programming,

2 Responses to “C++ Gtkmm Tutorial 6”


Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Powered by WordPress. Designed by elogi.