Windows Azure Cloud Storage ermöglicht es Ihnen bereits ab 0,10€ pro GB/Monat die Vorteile der Cloud zu nutzen.
Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   
Advanced Developers Conference     
Bücher-Shop mit Amazon (Buchkategorien)C++ : Referenzen zu C++ : C++ Builder : Visual C++ : C# : Java : Spieleprogrammierung : Systemprogrammierung Linux : Software-Entwicklung : .NET : Compilertechnik : Algorithmen & Datenstrukturen : Objektorientierung : Entwurfsmuster : UML : eXtreme Programming : Scrum : Projektmanagement : Software-Testing : Datenbanken : Tom DeMarco : Dilbert : User Friendly
C/C++ Forum :: FAQ - GUIs ::  gtkmm Beispiel Programm Pt. 3 ( Multithreaded )     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
evilissimo
Chefkoch

Benutzerprofil
Anmeldungsdatum: 11.11.2003
Beiträge: 2281
Beitrag evilissimo Chefkoch 19:27:42 23.06.2005   Titel:   gtkmm Beispiel Programm Pt. 3 ( Multithreaded )            Zitieren

mywindow.hpp
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#ifndef GUARD_MY_WINDOW_HPP_INCLUDED
#define
GUARD_MY_WINDOW_HPP_INCLUDED 1

#include
<boost/noncopyable.hpp>
#include
<gtkmm.h>


class MyWindow : public Gtk::Window, boost::noncopyable
{
  public:
    MyWindow();
    virtual ~MyWindow();

    // on_button_click wird ausgeführt wenn der User den Button auf unserem
    // Fenster anklickt

    void on_button_click();

    // Diese Methode wird als seperater Thread gestartet
    // Sie sorgt dann für die Animation des ProgressBar ohne die ganze Anwendung
    // zu blockieren

    void thread_worker();

  /* Das machen wir mit boost::noncopyable
  private: // Nicht kopierbar!
    MyWindow( MyWindow const & );
    MyWindow const & operator=( MyWindow const & );
  */

  private: // Deklaration der Variablen

    // Diese Variable brauchen wir um das Ende des zweiten Threads
    // zu veranlassen

    bool             m_end_thread;
   
    // Ich denke das ich mir zu diesen Widgets die Kommentare sparen kann
    // da diese bereits in den Examples I und II bereits benutzt worden ist

    Gtk::VBox        m_vbox;
    Gtk::Button      m_button;
    Gtk::Label       m_label;
 
    // ProgressBar zeigt an wie weit ein Prozess bereits ist
    // Ausserdem hat sie die pulse eigenschaft, die anzeigt das etwas getan
    // wird. Diese Pulse eigenschaft werden wir jetz einmal benutzen da
    // sie imho die interessantere ist ;)

    Gtk::ProgressBar m_pbar;
   
   
    // Da wir eine Multi Threaded Anwendung schreiben müssen wird eine
    // Möglichkeit finden wie wir problemlos auf Daten/Funktionen/Methoden
    // in einem anderen Thread zugreifen kann. Dies kann man dann via
    // einem Glib::Dispatcher realisieren.

    Glib::Dispatcher m_dispatcher;

    // Speichert den Zeiger auf den Thread ( zum beenden )
    Glib::Thread *   m_thread;
};

#endif
//GUARD_MY_WINDOW_HPP_INCLUDED
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#ifndef GUARD_MY_WINDOW_HPP_INCLUDED
#define
GUARD_MY_WINDOW_HPP_INCLUDED 1

#include
<boost/noncopyable.hpp>
#include
<gtkmm.h>


class MyWindow : public Gtk::Window, boost::noncopyable
{
public:
MyWindow();
virtual ~MyWindow();

// on_button_click wird ausgeführt wenn der User den Button auf unserem
// Fenster anklickt

void on_button_click();

// Diese Methode wird als seperater Thread gestartet
// Sie sorgt dann für die Animation des ProgressBar ohne die ganze Anwendung
// zu blockieren

void thread_worker();

/* Das machen wir mit boost::noncopyable
private: // Nicht kopierbar!
MyWindow( MyWindow const & );
MyWindow const & operator=( MyWindow const & );
*/

private: // Deklaration der Variablen

// Diese Variable brauchen wir um das Ende des zweiten Threads
// zu veranlassen

bool m_end_thread;

// Ich denke das ich mir zu diesen Widgets die Kommentare sparen kann
// da diese bereits in den Examples I und II bereits benutzt worden ist

Gtk::VBox m_vbox;
Gtk::Button m_button;
Gtk::Label m_label;

// ProgressBar zeigt an wie weit ein Prozess bereits ist
// Ausserdem hat sie die pulse eigenschaft, die anzeigt das etwas getan
// wird. Diese Pulse eigenschaft werden wir jetz einmal benutzen da
// sie imho die interessantere ist ;)

Gtk::ProgressBar m_pbar;


// Da wir eine Multi Threaded Anwendung schreiben müssen wird eine
// Möglichkeit finden wie wir problemlos auf Daten/Funktionen/Methoden
// in einem anderen Thread zugreifen kann. Dies kann man dann via
// einem Glib::Dispatcher realisieren.

Glib::Dispatcher m_dispatcher;

// Speichert den Zeiger auf den Thread ( zum beenden )
Glib::Thread * m_thread;
};

#endif
//GUARD_MY_WINDOW_HPP_INCLUDED
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#ifndef GUARD_MY_WINDOW_HPP_INCLUDED
#define
GUARD_MY_WINDOW_HPP_INCLUDED 1

#include
<boost/noncopyable.hpp>
#include
<gtkmm.h>


class MyWindow : public Gtk::Window, boost::noncopyable
{
  public:
    MyWindow();
    virtual ~MyWindow();

    // on_button_click wird ausgeführt wenn der User den Button auf unserem
    // Fenster anklickt

    void on_button_click();

    // Diese Methode wird als seperater Thread gestartet
    // Sie sorgt dann für die Animation des ProgressBar ohne die ganze Anwendung
    // zu blockieren

    void thread_worker();

  /* Das machen wir mit boost::noncopyable
  private: // Nicht kopierbar!
    MyWindow( MyWindow const & );
    MyWindow const & operator=( MyWindow const & );
  */

  private: // Deklaration der Variablen

    // Diese Variable brauchen wir um das Ende des zweiten Threads
    // zu veranlassen

    bool             m_end_thread;
   
    // Ich denke das ich mir zu diesen Widgets die Kommentare sparen kann
    // da diese bereits in den Examples I und II bereits benutzt worden ist

    Gtk::VBox        m_vbox;
    Gtk::Button      m_button;
    Gtk::Label       m_label;
 
    // ProgressBar zeigt an wie weit ein Prozess bereits ist
    // Ausserdem hat sie die pulse eigenschaft, die anzeigt das etwas getan
    // wird. Diese Pulse eigenschaft werden wir jetz einmal benutzen da
    // sie imho die interessantere ist ;)

    Gtk::ProgressBar m_pbar;
   
   
    // Da wir eine Multi Threaded Anwendung schreiben müssen wird eine
    // Möglichkeit finden wie wir problemlos auf Daten/Funktionen/Methoden
    // in einem anderen Thread zugreifen kann. Dies kann man dann via
    // einem Glib::Dispatcher realisieren.

    Glib::Dispatcher m_dispatcher;

    // Speichert den Zeiger auf den Thread ( zum beenden )
    Glib::Thread *   m_thread;
};

#endif
//GUARD_MY_WINDOW_HPP_INCLUDED



mywindow.cpp
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <boost/lexical_cast.hpp>
#include
"mywindow.hpp"

Glib::StaticMutex mutex = GLIBMM_STATIC_MUTEX_INIT;
 
MyWindow::MyWindow()
: m_end_thread(false), // Der Thread soll laufen
  m_vbox(false,10),    // Gtk::VBox soll die Elemente nicht homogen anlegen
                       // und 10 Pixel platz zwischen den einzelnen Elementen lassen

  m_button(Glib::locale_to_utf8("Click mich")) // Button text setzen
{
  add(m_vbox); // Hier verbinden wir das Gtk::VBox mit dem Fenster

  m_vbox.set_border_width(10); // Randbreite des Gtk::VBox auf 10 Pixel setzen

  m_vbox.pack_start(m_label);  // Verbinden des Gtk::Label mit dem Gtk::VBox
  m_vbox.pack_start(m_pbar);   // Verbinden des Gtk::ProgressBar mit dem Gtk::VBox                
  m_vbox.pack_start(m_button); // Verbinden des Gtk::Button mit dem Gtk::VBox                

  m_pbar.set_pulse_step(0.05f); // Schrittgröße für pulse() setzen / 0.0 - 1.0
 
  // Dem Button die Methode, die er beim clicked Signal ausführen soll, als
  // Funktor übergeben

  m_button.signal_clicked().connect(sigc::mem_fun(*this,&MyWindow::on_button_click));

  // Hier wird die Methode die der Dispatcher beim aufruf ausführen soll
  // als Funktor übergeben

  m_dispatcher.connect( sigc::mem_fun( m_pbar , &Gtk::ProgressBar::pulse ));

  // Hier starten wir den 2. Thread (der erste ist der Hauptthread!) der für
  // uns die ProgressBar - Arbeit erledigen wird.
  // Hierzu übergeben wir die thread_worker Methode als Funktor.
  // das 'true' sagt dem Thread das er joinable sein soll!
  // Was auch anhand des Pointers der auf den Thread zeigt und zurückgegeben
  // wird überprüft werden.

  m_thread = Glib::Thread::create( sigc::mem_fun(*this,&MyWindow::thread_worker),true);

  // Nun lassen wir alle Elemente des Fensters anzeigen.
  show_all();
}

MyWindow::~MyWindow()
{
  // Ein Anonymouer Scope innerhalb einer Funktion/Methode hat den
  // Zweck das darin erstellte Objekte beim verlassen zerstört werden
  // wir haben hier ein Mutex::Lock objekt erstellt das bei erstellung
  // das lock setzt und bei der Zerstörung wieder unlockt

  {
    Glib::Mutex::Lock lock(mutex);                    
    if(m_end_thread)       // Wenn der Thread noch läuft
       m_end_thread = true; // sagen wir dem Thread das er beenden soll
  }
  if(m_thread->joinable())
    m_thread->join();
}

void MyWindow::on_button_click()
{
   static unsigned long count_clicked = 0;
   // Hier konvertieren wir den Wert von count_clicked und incrementieren in sogleich
   // und übergeben dann den Wert als Glib::ustring an unser Label weiter
   // Somit haben wir dann einen Click counter ;)

   m_label.set_text(boost::lexical_cast<Glib::ustring>(count_clicked++));
}

void MyWindow::thread_worker()
{
  while(1)
  {
    Glib::usleep(50000);  // 50.000 Mikrosekunden warten
   
    m_dispatcher();       // Threadsafer Aufruf der pulse()-Methode

    // Dies ist ein anonymer scope [Erklärung siehe Destruktor Defintion]

    {
      Glib::Mutex::Lock lock(mutex);
      if(m_end_thread)      // Müssen wir beenden?
        return;
    }// Ende des anonymen scopes, das den effekt hat das das mutex wir unlocked wird
  }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <boost/lexical_cast.hpp>
#include
"mywindow.hpp"

Glib::StaticMutex mutex = GLIBMM_STATIC_MUTEX_INIT;

MyWindow::MyWindow()
: m_end_thread(false), // Der Thread soll laufen
m_vbox(false,10), // Gtk::VBox soll die Elemente nicht homogen anlegen
// und 10 Pixel platz zwischen den einzelnen Elementen lassen

m_button(Glib::locale_to_utf8("Click mich")) // Button text setzen
{
add(m_vbox); // Hier verbinden wir das Gtk::VBox mit dem Fenster

m_vbox.set_border_width(10); // Randbreite des Gtk::VBox auf 10 Pixel setzen

m_vbox.pack_start(m_label); // Verbinden des Gtk::Label mit dem Gtk::VBox
m_vbox.pack_start(m_pbar); // Verbinden des Gtk::ProgressBar mit dem Gtk::VBox
m_vbox.pack_start(m_button); // Verbinden des Gtk::Button mit dem Gtk::VBox

m_pbar.set_pulse_step(0.05f); // Schrittgröße für pulse() setzen / 0.0 - 1.0

// Dem Button die Methode, die er beim clicked Signal ausführen soll, als
// Funktor übergeben

m_button.signal_clicked().connect(sigc::mem_fun(*this,&MyWindow::on_button_click));

// Hier wird die Methode die der Dispatcher beim aufruf ausführen soll
// als Funktor übergeben

m_dispatcher.connect( sigc::mem_fun( m_pbar , &Gtk::ProgressBar::pulse ));

// Hier starten wir den 2. Thread (der erste ist der Hauptthread!) der für
// uns die ProgressBar - Arbeit erledigen wird.
// Hierzu übergeben wir die thread_worker Methode als Funktor.
// das 'true' sagt dem Thread das er joinable sein soll!
// Was auch anhand des Pointers der auf den Thread zeigt und zurückgegeben
// wird überprüft werden.

m_thread = Glib::Thread::create( sigc::mem_fun(*this,&MyWindow::thread_worker),true);

// Nun lassen wir alle Elemente des Fensters anzeigen.
show_all();
}

MyWindow::~MyWindow()
{
// Ein Anonymouer Scope innerhalb einer Funktion/Methode hat den
// Zweck das darin erstellte Objekte beim verlassen zerstört werden
// wir haben hier ein Mutex::Lock objekt erstellt das bei erstellung
// das lock setzt und bei der Zerstörung wieder unlockt

{
Glib::Mutex::Lock lock(mutex);
if(m_end_thread) // Wenn der Thread noch läuft
m_end_thread = true; // sagen wir dem Thread das er beenden soll
}
if(m_thread->joinable())
m_thread->join();
}

void MyWindow::on_button_click()
{
static unsigned long count_clicked = 0;
// Hier konvertieren wir den Wert von count_clicked und incrementieren in sogleich
// und übergeben dann den Wert als Glib::ustring an unser Label weiter
// Somit haben wir dann einen Click counter ;)

m_label.set_text(boost::lexical_cast<Glib::ustring>(count_clicked++));
}

void MyWindow::thread_worker()
{
while(1)
{
Glib::usleep(50000); // 50.000 Mikrosekunden warten

m_dispatcher(); // Threadsafer Aufruf der pulse()-Methode

// Dies ist ein anonymer scope [Erklärung siehe Destruktor Defintion]

{
Glib::Mutex::Lock lock(mutex);
if(m_end_thread) // Müssen wir beenden?
return;
}// Ende des anonymen scopes, das den effekt hat das das mutex wir unlocked wird
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <boost/lexical_cast.hpp>
#include
"mywindow.hpp"

Glib::StaticMutex mutex = GLIBMM_STATIC_MUTEX_INIT;
 
MyWindow::MyWindow()
: m_end_thread(false), // Der Thread soll laufen
  m_vbox(false,10),    // Gtk::VBox soll die Elemente nicht homogen anlegen
                       // und 10 Pixel platz zwischen den einzelnen Elementen lassen

  m_button(Glib::locale_to_utf8("Click mich")) // Button text setzen
{
  add(m_vbox); // Hier verbinden wir das Gtk::VBox mit dem Fenster

  m_vbox.set_border_width(10); // Randbreite des Gtk::VBox auf 10 Pixel setzen

  m_vbox.pack_start(m_label);  // Verbinden des Gtk::Label mit dem Gtk::VBox
  m_vbox.pack_start(m_pbar);   // Verbinden des Gtk::ProgressBar mit dem Gtk::VBox                
  m_vbox.pack_start(m_button); // Verbinden des Gtk::Button mit dem Gtk::VBox                

  m_pbar.set_pulse_step(0.05f); // Schrittgröße für pulse() setzen / 0.0 - 1.0
 
  // Dem Button die Methode, die er beim clicked Signal ausführen soll, als
  // Funktor übergeben

  m_button.signal_clicked().connect(sigc::mem_fun(*this,&MyWindow::on_button_click));

  // Hier wird die Methode die der Dispatcher beim aufruf ausführen soll
  // als Funktor übergeben

  m_dispatcher.connect( sigc::mem_fun( m_pbar , &Gtk::ProgressBar::pulse ));

  // Hier starten wir den 2. Thread (der erste ist der Hauptthread!) der für
  // uns die ProgressBar - Arbeit erledigen wird.
  // Hierzu übergeben wir die thread_worker Methode als Funktor.
  // das 'true' sagt dem Thread das er joinable sein soll!
  // Was auch anhand des Pointers der auf den Thread zeigt und zurückgegeben
  // wird überprüft werden.

  m_thread = Glib::Thread::create( sigc::mem_fun(*this,&MyWindow::thread_worker),true);

  // Nun lassen wir alle Elemente des Fensters anzeigen.
  show_all();
}

MyWindow::~MyWindow()
{
  // Ein Anonymouer Scope innerhalb einer Funktion/Methode hat den
  // Zweck das darin erstellte Objekte beim verlassen zerstört werden
  // wir haben hier ein Mutex::Lock objekt erstellt das bei erstellung
  // das lock setzt und bei der Zerstörung wieder unlockt

  {
    Glib::Mutex::Lock lock(mutex);                    
    if(m_end_thread)       // Wenn der Thread noch läuft
       m_end_thread = true; // sagen wir dem Thread das er beenden soll
  }
  if(m_thread->joinable())
    m_thread->join();
}

void MyWindow::on_button_click()
{
   static unsigned long count_clicked = 0;
   // Hier konvertieren wir den Wert von count_clicked und incrementieren in sogleich
   // und übergeben dann den Wert als Glib::ustring an unser Label weiter
   // Somit haben wir dann einen Click counter ;)

   m_label.set_text(boost::lexical_cast<Glib::ustring>(count_clicked++));
}

void MyWindow::thread_worker()
{
  while(1)
  {
    Glib::usleep(50000);  // 50.000 Mikrosekunden warten
   
    m_dispatcher();       // Threadsafer Aufruf der pulse()-Methode

    // Dies ist ein anonymer scope [Erklärung siehe Destruktor Defintion]

    {
      Glib::Mutex::Lock lock(mutex);
      if(m_end_thread)      // Müssen wir beenden?
        return;
    }// Ende des anonymen scopes, das den effekt hat das das mutex wir unlocked wird
  }
}





Dies mal hat sich etwas an der Eintritts-Funktion geändert:


main.cpp
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main(int argc, char**argv)
{
  // Die einzige Änderung hier ist dieser Aufruf:
  Glib::thread_init();
  // Mit dem Glib::thread_init aufruf wird dafür gesorgt das
  // das Gtk+/Glib Subsystem darauf vorbereitet wird das wir
  // mehrere Threads benutzen.


  Gtk::Main main_obj(argc,argv);

  MyWindow window_obj;

  main_obj.run(window_obj);

  return EXIT_SUCCESS;  
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main(int argc, char**argv)
{
// Die einzige Änderung hier ist dieser Aufruf:
Glib::thread_init();
// Mit dem Glib::thread_init aufruf wird dafür gesorgt das
// das Gtk+/Glib Subsystem darauf vorbereitet wird das wir
// mehrere Threads benutzen.


Gtk::Main main_obj(argc,argv);

MyWindow window_obj;

main_obj.run(window_obj);

return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main(int argc, char**argv)
{
  // Die einzige Änderung hier ist dieser Aufruf:
  Glib::thread_init();
  // Mit dem Glib::thread_init aufruf wird dafür gesorgt das
  // das Gtk+/Glib Subsystem darauf vorbereitet wird das wir
  // mehrere Threads benutzen.


  Gtk::Main main_obj(argc,argv);

  MyWindow window_obj;

  main_obj.run(window_obj);

  return EXIT_SUCCESS;  
}

_________________
evilissimo - R.I.P. dmr
< Moderator im C++/CLI Forum und im C++ Forum >
About Singletons: "Anyway, if our experts can make this mistake, you have made it and you don't even know about it."


Zuletzt bearbeitet von evilissimo am 16:31:21 26.06.2005, insgesamt 3-mal bearbeitet
Werbeunterbrechung
evilissimo
Chefkoch

Benutzerprofil
Anmeldungsdatum: 11.11.2003
Beiträge: 2281
Beitrag evilissimo Chefkoch 20:00:52 23.06.2005   Titel:   Und noch einmal am Stück            Zitieren

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <boost/noncopyable.hpp>
#include
<boost/lexical_cast.hpp>
#include
<gtkmm.h>


class MyWindow : public Gtk::Window, boost::noncopyable
{
  public:
    MyWindow();
    virtual ~MyWindow();

    // on_button_click wird ausgeführt wenn der User den Button auf unserem
    // Fenster anklickt

    void on_button_click();

    // Diese Methode wird als seperater Thread gestartet
    // Sie sorgt dann für die Animation des ProgressBar ohne die ganze Anwendung
    // zu blockieren

    void thread_worker();

  /* Das machen wir mit boost::noncopyable
  private: // Nicht kopierbar!
    MyWindow( MyWindow const & );
    MyWindow const & operator=( MyWindow const & );
  */

  private: // Deklaration der Variablen

    // Diese Variable brauchen wir um das Ende des zweiten Threads
    // zu veranlassen

    bool             m_end_thread;
   
    // Ich denke das ich mir zu diesen Widgets die Kommentare sparen kann
    // da diese bereits in den Examples I und II bereits benutzt worden ist

    Gtk::VBox        m_vbox;
    Gtk::Button      m_button;
    Gtk::Label       m_label;
 
    // ProgressBar zeigt an wie weit ein Prozess bereits ist
    // Ausserdem hat sie die pulse eigenschaft, die anzeigt das etwas getan
    // wird. Diese Pulse eigenschaft werden wir jetz einmal benutzen da
    // sie imho die interessantere ist ;)

    Gtk::ProgressBar m_pbar;
   
   
    // Da wir eine Multi Threaded Anwendung schreiben müssen wird eine
    // Möglichkeit finden wie wir problemlos auf Daten/Funktionen/Methoden
    // in einem anderen Thread zugreifen kann. Dies kann man dann via
    // einem Glib::Dispatcher realisieren.

    Glib::Dispatcher m_dispatcher;

    // Speichert den Zeiger auf den Thread ( zum beenden )
    Glib::Thread * m_thread;

};

Glib::StaticMutex mutex = GLIBMM_STATIC_MUTEX_INIT;
 
MyWindow::MyWindow()
: m_end_thread(false), // Der Thread soll laufen
  m_vbox(false,10),    // Gtk::VBox soll die Elemente nicht homogen anlegen
                       // und 10 Pixel platz zwischen den einzelnen Elementen lassen

  m_button(Glib::locale_to_utf8("Click mich")) // Button text setzen
{
  add(m_vbox); // Hier verbinden wir das Gtk::VBox mit dem Fenster

  m_vbox.set_border_width(10); // Randbreite des Gtk::VBox auf 10 Pixel setzen

  m_vbox.pack_start(m_label);  // Verbinden des Gtk::Label mit dem Gtk::VBox
  m_vbox.pack_start(m_pbar);   // Verbinden des Gtk::ProgressBar mit dem Gtk::VBox                
  m_vbox.pack_start(m_button); // Verbinden des Gtk::Button mit dem Gtk::VBox                

  m_pbar.set_pulse_step(0.05f); // Schrittgröße für pulse() setzen / 0.0 - 1.0
 
  // Dem Button die Methode, die er beim clicked Signal ausführen soll, als
  // Funktor übergeben

  m_button.signal_clicked().connect(sigc::mem_fun(*this,&MyWindow::on_button_click));

  // Hier wird die Methode die der Dispatcher beim aufruf ausführen soll
  // als Funktor übergeben

  m_dispatcher.connect( sigc::mem_fun( m_pbar , &Gtk::ProgressBar::pulse ));

// Hier starten wir den 2. Thread (der erste ist der Hauptthread!) der für
  // uns die ProgressBar - Arbeit erledigen wird.
  // Hierzu übergeben wir die thread_worker Methode als Funktor.
  // das 'true' sagt dem Thread das er joinable sein soll!
  // Was auch anhand des Pointers der auf den Thread zeigt und zurückgegeben
  // wird überprüft werden.

  m_thread = Glib::Thread::create( sigc::mem_fun(*this,&MyWindow::thread_worker),true);

  // Nun lassen wir alle Elemente des Fensters anzeigen.
  show_all();
}

MyWindow::~MyWindow()
{
  // Ein Anonymouer Scope innerhalb einer Funktion/Methode hat den
  // Zweck das darin erstellte Objekte beim verlassen zerstört werden
  // wir haben hier ein Mutex::Lock objekt erstellt das bei erstellung
  // das lock setzt und bei der Zerstörung wieder unlockt

  {
    Glib::Mutex::Lock lock(mutex);                    
    if(m_end_thread)       // Wenn der Thread noch läuft
       m_end_thread = true; // sagen wir dem Thread das er beenden soll
  }
  if(m_thread->joinable())
    m_thread->join();
}

void MyWindow::on_button_click()
{
   static unsigned long count_clicked = 0;
   // Hier konvertieren wir den Wert von count_clicked und incrementieren in sogleich
   // und übergeben dann den Wert als Glib::ustring an unser Label weiter
   // Somit haben wir dann einen Click counter ;)

   m_label.set_text(boost::lexical_cast<Glib::ustring>(count_clicked++));
}

void MyWindow::thread_worker()
{
  while(1)
  {
    Glib::usleep(50000);  // 50.000 Mikrosekunden warten
   
    m_dispatcher();       // Threadsafer Aufruf der pulse()-Methode

    // Dies ist ein anonymer scope [Erklärung siehe Destruktor Defintion]

    {
      Glib::Mutex::Lock lock(mutex);
      if(m_end_thread)      // Müssen wir beenden?
        return;
    }// Ende des anonymen scopes, das den effekt hat das das mutex wir unlocked wird
  }
}






int main(int argc, char**argv)
{
  // Die einzige Änderung hier ist dieser Aufruf:
  Glib::thread_init();
  // Mit dem Glib::thread_init aufruf wird dafür gesorgt das
  // das Gtk+/Glib Subsystem darauf vorbereitet wird das wir
  // mehrere Threads benutzen.


  Gtk::Main main_obj(argc,argv);

  MyWindow window_obj;

  main_obj.run(window_obj);

  return EXIT_SUCCESS;  
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <boost/noncopyable.hpp>
#include
<boost/lexical_cast.hpp>
#include
<gtkmm.h>


class MyWindow : public Gtk::Window, boost::noncopyable
{
public:
MyWindow();
virtual ~MyWindow();

// on_button_click wird ausgeführt wenn der User den Button auf unserem
// Fenster anklickt

void on_button_click();

// Diese Methode wird als seperater Thread gestartet
// Sie sorgt dann für die Animation des ProgressBar ohne die ganze Anwendung
// zu blockieren

void thread_worker();

/* Das machen wir mit boost::noncopyable
private: // Nicht kopierbar!
MyWindow( MyWindow const & );
MyWindow const & operator=( MyWindow const & );
*/

private: // Deklaration der Variablen

// Diese Variable brauchen wir um das Ende des zweiten Threads
// zu veranlassen

bool m_end_thread;

// Ich denke das ich mir zu diesen Widgets die Kommentare sparen kann
// da diese bereits in den Examples I und II bereits benutzt worden ist

Gtk::VBox m_vbox;
Gtk::Button m_button;
Gtk::Label m_label;

// ProgressBar zeigt an wie weit ein Prozess bereits ist
// Ausserdem hat sie die pulse eigenschaft, die anzeigt das etwas getan
// wird. Diese Pulse eigenschaft werden wir jetz einmal benutzen da
// sie imho die interessantere ist ;)

Gtk::ProgressBar m_pbar;


// Da wir eine Multi Threaded Anwendung schreiben müssen wird eine
// Möglichkeit finden wie wir problemlos auf Daten/Funktionen/Methoden
// in einem anderen Thread zugreifen kann. Dies kann man dann via
// einem Glib::Dispatcher realisieren.

Glib::Dispatcher m_dispatcher;

// Speichert den Zeiger auf den Thread ( zum beenden )
Glib::Thread * m_thread;

};

Glib::StaticMutex mutex = GLIBMM_STATIC_MUTEX_INIT;

MyWindow::MyWindow()
: m_end_thread(false), // Der Thread soll laufen
m_vbox(false,10), // Gtk::VBox soll die Elemente nicht homogen anlegen
// und 10 Pixel platz zwischen den einzelnen Elementen lassen

m_button(Glib::locale_to_utf8("Click mich")) // Button text setzen
{
add(m_vbox); // Hier verbinden wir das Gtk::VBox mit dem Fenster

m_vbox.set_border_width(10); // Randbreite des Gtk::VBox auf 10 Pixel setzen

m_vbox.pack_start(m_label); // Verbinden des Gtk::Label mit dem Gtk::VBox
m_vbox.pack_start(m_pbar); // Verbinden des Gtk::ProgressBar mit dem Gtk::VBox
m_vbox.pack_start(m_button); // Verbinden des Gtk::Button mit dem Gtk::VBox

m_pbar.set_pulse_step(0.05f); // Schrittgröße für pulse() setzen / 0.0 - 1.0

// Dem Button die Methode, die er beim clicked Signal ausführen soll, als
// Funktor übergeben

m_button.signal_clicked().connect(sigc::mem_fun(*this,&MyWindow::on_button_click));

// Hier wird die Methode die der Dispatcher beim aufruf ausführen soll
// als Funktor übergeben

m_dispatcher.connect( sigc::mem_fun( m_pbar , &Gtk::ProgressBar::pulse ));

// Hier starten wir den 2. Thread (der erste ist der Hauptthread!) der für
// uns die ProgressBar - Arbeit erledigen wird.
// Hierzu übergeben wir die thread_worker Methode als Funktor.
// das 'true' sagt dem Thread das er joinable sein soll!
// Was auch anhand des Pointers der auf den Thread zeigt und zurückgegeben
// wird überprüft werden.

m_thread = Glib::Thread::create( sigc::mem_fun(*this,&MyWindow::thread_worker),true);

// Nun lassen wir alle Elemente des Fensters anzeigen.
show_all();
}

MyWindow::~MyWindow()
{
// Ein Anonymouer Scope innerhalb einer Funktion/Methode hat den
// Zweck das darin erstellte Objekte beim verlassen zerstört werden
// wir haben hier ein Mutex::Lock objekt erstellt das bei erstellung
// das lock setzt und bei der Zerstörung wieder unlockt

{
Glib::Mutex::Lock lock(mutex);
if(m_end_thread) // Wenn der Thread noch läuft
m_end_thread = true; // sagen wir dem Thread das er beenden soll
}
if(m_thread->joinable())
m_thread->join();
}

void MyWindow::on_button_click()
{
static unsigned long count_clicked = 0;
// Hier konvertieren wir den Wert von count_clicked und incrementieren in sogleich
// und übergeben dann den Wert als Glib::ustring an unser Label weiter
// Somit haben wir dann einen Click counter ;)

m_label.set_text(boost::lexical_cast<Glib::ustring>(count_clicked++));
}

void MyWindow::thread_worker()
{
while(1)
{
Glib::usleep(50000); // 50.000 Mikrosekunden warten

m_dispatcher(); // Threadsafer Aufruf der pulse()-Methode

// Dies ist ein anonymer scope [Erklärung siehe Destruktor Defintion]

{
Glib::Mutex::Lock lock(mutex);
if(m_end_thread) // Müssen wir beenden?
return;
}// Ende des anonymen scopes, das den effekt hat das das mutex wir unlocked wird
}
}






int main(int argc, char**argv)
{
// Die einzige Änderung hier ist dieser Aufruf:
Glib::thread_init();
// Mit dem Glib::thread_init aufruf wird dafür gesorgt das
// das Gtk+/Glib Subsystem darauf vorbereitet wird das wir
// mehrere Threads benutzen.


Gtk::Main main_obj(argc,argv);

MyWindow window_obj;

main_obj.run(window_obj);

return EXIT_SUCCESS;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <boost/noncopyable.hpp>
#include
<boost/lexical_cast.hpp>
#include
<gtkmm.h>


class MyWindow : public Gtk::Window, boost::noncopyable
{
  public:
    MyWindow();
    virtual ~MyWindow();

    // on_button_click wird ausgeführt wenn der User den Button auf unserem
    // Fenster anklickt

    void on_button_click();

    // Diese Methode wird als seperater Thread gestartet
    // Sie sorgt dann für die Animation des ProgressBar ohne die ganze Anwendung
    // zu blockieren

    void thread_worker();

  /* Das machen wir mit boost::noncopyable
  private: // Nicht kopierbar!
    MyWindow( MyWindow const & );
    MyWindow const & operator=( MyWindow const & );
  */

  private: // Deklaration der Variablen

    // Diese Variable brauchen wir um das Ende des zweiten Threads
    // zu veranlassen

    bool             m_end_thread;
   
    // Ich denke das ich mir zu diesen Widgets die Kommentare sparen kann
    // da diese bereits in den Examples I und II bereits benutzt worden ist

    Gtk::VBox        m_vbox;
    Gtk::Button      m_button;
    Gtk::Label       m_label;
 
    // ProgressBar zeigt an wie weit ein Prozess bereits ist
    // Ausserdem hat sie die pulse eigenschaft, die anzeigt das etwas getan
    // wird. Diese Pulse eigenschaft werden wir jetz einmal benutzen da
    // sie imho die interessantere ist ;)

    Gtk::ProgressBar m_pbar;
   
   
    // Da wir eine Multi Threaded Anwendung schreiben müssen wird eine
    // Möglichkeit finden wie wir problemlos auf Daten/Funktionen/Methoden
    // in einem anderen Thread zugreifen kann. Dies kann man dann via
    // einem Glib::Dispatcher realisieren.

    Glib::Dispatcher m_dispatcher;

    // Speichert den Zeiger auf den Thread ( zum beenden )
    Glib::Thread * m_thread;

};

Glib::StaticMutex mutex = GLIBMM_STATIC_MUTEX_INIT;
 
MyWindow::MyWindow()
: m_end_thread(false), // Der Thread soll laufen
  m_vbox(false,10),    // Gtk::VBox soll die Elemente nicht homogen anlegen
                       // und 10 Pixel platz zwischen den einzelnen Elementen lassen

  m_button(Glib::locale_to_utf8("Click mich")) // Button text setzen
{
  add(m_vbox); // Hier verbinden wir das Gtk::VBox mit dem Fenster

  m_vbox.set_border_width(10); // Randbreite des Gtk::VBox auf 10 Pixel setzen

  m_vbox.pack_start(m_label);  // Verbinden des Gtk::Label mit dem Gtk::VBox
  m_vbox.pack_start(m_pbar);   // Verbinden des Gtk::ProgressBar mit dem Gtk::VBox                
  m_vbox.pack_start(m_button); // Verbinden des Gtk::Button mit dem Gtk::VBox                

  m_pbar.set_pulse_step(0.05f); // Schrittgröße für pulse() setzen / 0.0 - 1.0
 
  // Dem Button die Methode, die er beim clicked Signal ausführen soll, als
  // Funktor übergeben

  m_button.signal_clicked().connect(sigc::mem_fun(*this,&MyWindow::on_button_click));

  // Hier wird die Methode die der Dispatcher beim aufruf ausführen soll
  // als Funktor übergeben

  m_dispatcher.connect( sigc::mem_fun( m_pbar , &Gtk::ProgressBar::pulse ));

// Hier starten wir den 2. Thread (der erste ist der Hauptthread!) der für
  // uns die ProgressBar - Arbeit erledigen wird.
  // Hierzu übergeben wir die thread_worker Methode als Funktor.
  // das 'true' sagt dem Thread das er joinable sein soll!
  // Was auch anhand des Pointers der auf den Thread zeigt und zurückgegeben
  // wird überprüft werden.

  m_thread = Glib::Thread::create( sigc::mem_fun(*this,&MyWindow::thread_worker),true);

  // Nun lassen wir alle Elemente des Fensters anzeigen.
  show_all();
}

MyWindow::~MyWindow()
{
  // Ein Anonymouer Scope innerhalb einer Funktion/Methode hat den
  // Zweck das darin erstellte Objekte beim verlassen zerstört werden
  // wir haben hier ein Mutex::Lock objekt erstellt das bei erstellung
  // das lock setzt und bei der Zerstörung wieder unlockt

  {
    Glib::Mutex::Lock lock(mutex);                    
    if(m_end_thread)       // Wenn der Thread noch läuft
       m_end_thread = true; // sagen wir dem Thread das er beenden soll
  }
  if(m_thread->joinable())
    m_thread->join();
}

void MyWindow::on_button_click()
{
   static unsigned long count_clicked = 0;
   // Hier konvertieren wir den Wert von count_clicked und incrementieren in sogleich
   // und übergeben dann den Wert als Glib::ustring an unser Label weiter
   // Somit haben wir dann einen Click counter ;)

   m_label.set_text(boost::lexical_cast<Glib::ustring>(count_clicked++));
}

void MyWindow::thread_worker()
{
  while(1)
  {
    Glib::usleep(50000);  // 50.000 Mikrosekunden warten
   
    m_dispatcher();       // Threadsafer Aufruf der pulse()-Methode

    // Dies ist ein anonymer scope [Erklärung siehe Destruktor Defintion]

    {
      Glib::Mutex::Lock lock(mutex);
      if(m_end_thread)      // Müssen wir beenden?
        return;
    }// Ende des anonymen scopes, das den effekt hat das das mutex wir unlocked wird
  }
}






int main(int argc, char**argv)
{
  // Die einzige Änderung hier ist dieser Aufruf:
  Glib::thread_init();
  // Mit dem Glib::thread_init aufruf wird dafür gesorgt das
  // das Gtk+/Glib Subsystem darauf vorbereitet wird das wir
  // mehrere Threads benutzen.


  Gtk::Main main_obj(argc,argv);

  MyWindow window_obj;

  main_obj.run(window_obj);

  return EXIT_SUCCESS;  
}

_________________
evilissimo - R.I.P. dmr
< Moderator im C++/CLI Forum und im C++ Forum >
About Singletons: "Anyway, if our experts can make this mistake, you have made it and you don't even know about it."


Zuletzt bearbeitet von evilissimo am 16:30:55 26.06.2005, insgesamt 1-mal bearbeitet
nachtrag
Unregistrierter




Beitrag nachtrag Unregistrierter 22:02:04 23.06.2005   Titel:              Zitieren

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
 * Glib::Dispatcher example -- cross thread signalling
 * by Daniel Elstner
 *
 * Copyright (c) 2005  Free Software Foundation
 */


#include
<sigc++/class_slot.h>
#include
<glibmm.h>
#include
<gtkmm/box.h>
#include
<gtkmm/button.h>
#include
<gtkmm/buttonbox.h>
#include
<gtkmm/main.h>
#include
<gtkmm/progressbar.h>
#include
<gtkmm/stock.h>
#include
<gtkmm/window.h>

#include
<algorithm>
#include
<functional>
#include
<list>


namespace
{

class ThreadProgress : public Gtk::ProgressBar
{
public:
  ThreadProgress();
  virtual ~ThreadProgress();

  void launch();
  SigC::Signal0<void>& signal_finished();

private:
  unsigned int        progress_;
  Glib::Dispatcher    signal_increment_;
  SigC::Signal0<void> signal_finished_;

  void progress_increment();
  void thread_function();
};

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

  void launch_threads();

protected:
  virtual bool on_delete_event(GdkEventAny* event);

private:
  std::list<ThreadProgress*>  progress_bars_;
  Gtk::Button*                close_button_;

  void on_progress_finished(ThreadProgress* progress);
};


ThreadProgress::ThreadProgress()
:
  progress_ (0)
{
  // Connect to the cross-thread signal.
  signal_increment_.connect(SigC::slot(*this, &ThreadProgress::progress_increment));
}

ThreadProgress::~ThreadProgress()
{}

void ThreadProgress::launch()
{
  // Create a non-joinable thread -- it's deleted automatically on thread exit.
  Glib::Thread::create(SigC::slot_class(*this, &ThreadProgress::thread_function), false);
}

SigC::Signal0<void>& ThreadProgress::signal_finished()
{
  return signal_finished_;
}

void ThreadProgress::progress_increment()
{
  // Use an integer because floating point arithmetic is inaccurate --
  // we want to finish *exactly* after the 1000th increment.

  ++progress_;

  const double fraction = double(progress_) / 1000.0;
  set_fraction(std::min(fraction, 1.0));

  if(progress_ >= 1000)
    signal_finished_();
}

void ThreadProgress::thread_function()
{
  Glib::Rand rand;
  int usecs = 5000;

  for(int i = 0; i < 1000; ++i)
  {
    usecs = rand.get_int_range(std::max(0, usecs - 1000 - i), std::min(20000, usecs + 1000 + i));
    Glib::usleep(usecs);

    // Tell the GUI thread to increment the progress bar value.
    signal_increment_();
  }
}


MainWindow::MainWindow()
:
  close_button_ (0)
{
  set_title("Thread Dispatcher Example");

  Gtk::VBox *const vbox = new Gtk::VBox(false, 10);
  add(*Gtk::manage(vbox));
  vbox->set_border_width(10);

  for(int i = 0; i < 5; ++i)
  {
    ThreadProgress *const progress = new ThreadProgress();
    vbox->pack_start(*Gtk::manage(progress), Gtk::PACK_SHRINK);
    progress_bars_.push_back(progress);

    progress->signal_finished().connect(
        SigC::bind(SigC::slot(*this, &MainWindow::on_progress_finished), progress));
  }

  Gtk::ButtonBox *const button_box = new Gtk::HButtonBox();
  vbox->pack_end(*Gtk::manage(button_box), Gtk::PACK_SHRINK);

  close_button_ = new Gtk::Button(Gtk::Stock::CLOSE);
  button_box->pack_start(*Gtk::manage(close_button_), Gtk::PACK_SHRINK);
  close_button_->set_flags(Gtk::CAN_DEFAULT);
  close_button_->grab_default();
  close_button_->set_sensitive(false);
  close_button_->signal_clicked().connect(SigC::slot(*this, &Gtk::Widget::hide));

  show_all_children();
  set_default_size(300, -1);
}

MainWindow::~MainWindow()
{}

void MainWindow::launch_threads()
{
  std::for_each(
      progress_bars_.begin(), progress_bars_.end(),
      std::mem_fun(&ThreadProgress::launch));
}

bool MainWindow::on_delete_event(GdkEventAny*)
{
  // Don't allow closing the window before all threads finished.
  return !progress_bars_.empty();
}

void MainWindow::on_progress_finished(ThreadProgress* progress)
{
  progress_bars_.remove(progress);

  // Enable the close button when all threads finished.
  if(progress_bars_.empty())
    close_button_->set_sensitive(true);
}

} // anonymous namespace


int main(int argc, char** argv)
{
  Glib::thread_init();
  Gtk::Main main_instance (&argc, &argv);

  MainWindow window;

  // Install a one-shot idle handler to launch the threads
  // right after the main window has been displayed.

  Glib::signal_idle().connect(
      SigC::bind_return(SigC::slot(window, &MainWindow::launch_threads), false));

  Gtk::Main::run(window);

  return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
* Glib::Dispatcher example -- cross thread signalling
* by Daniel Elstner
*
* Copyright (c) 2005 Free Software Foundation
*/


#include
<sigc++/class_slot.h>
#include
<glibmm.h>
#include
<gtkmm/box.h>
#include
<gtkmm/button.h>
#include
<gtkmm/buttonbox.h>
#include
<gtkmm/main.h>
#include
<gtkmm/progressbar.h>
#include
<gtkmm/stock.h>
#include
<gtkmm/window.h>

#include
<algorithm>
#include
<functional>
#include
<list>


namespace
{

class ThreadProgress : public Gtk::ProgressBar
{
public:
ThreadProgress();
virtual ~ThreadProgress();

void launch();
SigC::Signal0<void>& signal_finished();

private:
unsigned int progress_;
Glib::Dispatcher signal_increment_;
SigC::Signal0<void> signal_finished_;

void progress_increment();
void thread_function();
};

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

void launch_threads();

protected:
virtual bool on_delete_event(GdkEventAny* event);

private:
std::list<ThreadProgress*> progress_bars_;
Gtk::Button* close_button_;

void on_progress_finished(ThreadProgress* progress);
};


ThreadProgress::ThreadProgress()
:
progress_ (0)
{
// Connect to the cross-thread signal.
signal_increment_.connect(SigC::slot(*this, &ThreadProgress::progress_increment));
}

ThreadProgress::~ThreadProgress()
{}

void ThreadProgress::launch()
{
// Create a non-joinable thread -- it's deleted automatically on thread exit.
Glib::Thread::create(SigC::slot_class(*this, &ThreadProgress::thread_function), false);
}

SigC::Signal0<void>& ThreadProgress::signal_finished()
{
return signal_finished_;
}

void ThreadProgress::progress_increment()
{
// Use an integer because floating point arithmetic is inaccurate --
// we want to finish *exactly* after the 1000th increment.

++progress_;

const double fraction = double(progress_) / 1000.0;
set_fraction(std::min(fraction, 1.0));

if(progress_ >= 1000)
signal_finished_();
}

void ThreadProgress::thread_function()
{
Glib::Rand rand;
int usecs = 5000;

for(int i = 0; i < 1000; ++i)
{
usecs = rand.get_int_range(std::max(0, usecs - 1000 - i), std::min(20000, usecs + 1000 + i));
Glib::usleep(usecs);

// Tell the GUI thread to increment the progress bar value.
signal_increment_();
}
}


MainWindow::MainWindow()
:
close_button_ (0)
{
set_title("Thread Dispatcher Example");

Gtk::VBox *const vbox = new Gtk::VBox(false, 10);
add(*Gtk::manage(vbox));
vbox->set_border_width(10);

for(int i = 0; i < 5; ++i)
{
ThreadProgress *const progress = new ThreadProgress();
vbox->pack_start(*Gtk::manage(progress), Gtk::PACK_SHRINK);
progress_bars_.push_back(progress);

progress->signal_finished().connect(
SigC::bind(SigC::slot(*this, &MainWindow::on_progress_finished), progress));
}

Gtk::ButtonBox *const button_box = new Gtk::HButtonBox();
vbox->pack_end(*Gtk::manage(button_box), Gtk::PACK_SHRINK);

close_button_ = new Gtk::Button(Gtk::Stock::CLOSE);
button_box->pack_start(*Gtk::manage(close_button_), Gtk::PACK_SHRINK);
close_button_->set_flags(Gtk::CAN_DEFAULT);
close_button_->grab_default();
close_button_->set_sensitive(false);
close_button_->signal_clicked().connect(SigC::slot(*this, &Gtk::Widget::hide));

show_all_children();
set_default_size(300, -1);
}

MainWindow::~MainWindow()
{}

void MainWindow::launch_threads()
{
std::for_each(
progress_bars_.begin(), progress_bars_.end(),
std::mem_fun(&ThreadProgress::launch));
}

bool MainWindow::on_delete_event(GdkEventAny*)
{
// Don't allow closing the window before all threads finished.
return !progress_bars_.empty();
}

void MainWindow::on_progress_finished(ThreadProgress* progress)
{
progress_bars_.remove(progress);

// Enable the close button when all threads finished.
if(progress_bars_.empty())
close_button_->set_sensitive(true);
}

} // anonymous namespace


int main(int argc, char** argv)
{
Glib::thread_init();
Gtk::Main main_instance (&argc, &argv);

MainWindow window;

// Install a one-shot idle handler to launch the threads
// right after the main window has been displayed.

Glib::signal_idle().connect(
SigC::bind_return(SigC::slot(window, &MainWindow::launch_threads), false));

Gtk::Main::run(window);

return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
 * Glib::Dispatcher example -- cross thread signalling
 * by Daniel Elstner
 *
 * Copyright (c) 2005  Free Software Foundation
 */


#include
<sigc++/class_slot.h>
#include
<glibmm.h>
#include
<gtkmm/box.h>
#include
<gtkmm/button.h>
#include
<gtkmm/buttonbox.h>
#include
<gtkmm/main.h>
#include
<gtkmm/progressbar.h>
#include
<gtkmm/stock.h>
#include
<gtkmm/window.h>

#include
<algorithm>
#include
<functional>
#include
<list>


namespace
{

class ThreadProgress : public Gtk::ProgressBar
{
public:
  ThreadProgress();
  virtual ~ThreadProgress();

  void launch();
  SigC::Signal0<void>& signal_finished();

private:
  unsigned int        progress_;
  Glib::Dispatcher    signal_increment_;
  SigC::Signal0<void> signal_finished_;

  void progress_increment();
  void thread_function();
};

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

  void launch_threads();

protected:
  virtual bool on_delete_event(GdkEventAny* event);

private:
  std::list<ThreadProgress*>  progress_bars_;
  Gtk::Button*                close_button_;

  void on_progress_finished(ThreadProgress* progress);
};


ThreadProgress::ThreadProgress()
:
  progress_ (0)
{
  // Connect to the cross-thread signal.
  signal_increment_.connect(SigC::slot(*this, &ThreadProgress::progress_increment));
}

ThreadProgress::~ThreadProgress()
{}

void ThreadProgress::launch()
{
  // Create a non-joinable thread -- it's deleted automatically on thread exit.
  Glib::Thread::create(SigC::slot_class(*this, &ThreadProgress::thread_function), false);
}

SigC::Signal0<void>& ThreadProgress::signal_finished()
{
  return signal_finished_;
}

void ThreadProgress::progress_increment()
{
  // Use an integer because floating point arithmetic is inaccurate --
  // we want to finish *exactly* after the 1000th increment.

  ++progress_;

  const double fraction = double(progress_) / 1000.0;
  set_fraction(std::min(fraction, 1.0));

  if(progress_ >= 1000)
    signal_finished_();
}

void ThreadProgress::thread_function()
{
  Glib::Rand rand;
  int usecs = 5000;

  for(int i = 0; i < 1000; ++i)
  {
    usecs = rand.get_int_range(std::max(0, usecs - 1000 - i), std::min(20000, usecs + 1000 + i));
    Glib::usleep(usecs);

    // Tell the GUI thread to increment the progress bar value.
    signal_increment_();
  }
}


MainWindow::MainWindow()
:
  close_button_ (0)
{
  set_title("Thread Dispatcher Example");

  Gtk::VBox *const vbox = new Gtk::VBox(false, 10);
  add(*Gtk::manage(vbox));
  vbox->set_border_width(10);

  for(int i = 0; i < 5; ++i)
  {
    ThreadProgress *const progress = new ThreadProgress();
    vbox->pack_start(*Gtk::manage(progress), Gtk::PACK_SHRINK);
    progress_bars_.push_back(progress);

    progress->signal_finished().connect(
        SigC::bind(SigC::slot(*this, &MainWindow::on_progress_finished), progress));
  }

  Gtk::ButtonBox *const button_box = new Gtk::HButtonBox();
  vbox->pack_end(*Gtk::manage(button_box), Gtk::PACK_SHRINK);

  close_button_ = new Gtk::Button(Gtk::Stock::CLOSE);
  button_box->pack_start(*Gtk::manage(close_button_), Gtk::PACK_SHRINK);
  close_button_->set_flags(Gtk::CAN_DEFAULT);
  close_button_->grab_default();
  close_button_->set_sensitive(false);
  close_button_->signal_clicked().connect(SigC::slot(*this, &Gtk::Widget::hide));

  show_all_children();
  set_default_size(300, -1);
}

MainWindow::~MainWindow()
{}

void MainWindow::launch_threads()
{
  std::for_each(
      progress_bars_.begin(), progress_bars_.end(),
      std::mem_fun(&ThreadProgress::launch));
}

bool MainWindow::on_delete_event(GdkEventAny*)
{
  // Don't allow closing the window before all threads finished.
  return !progress_bars_.empty();
}

void MainWindow::on_progress_finished(ThreadProgress* progress)
{
  progress_bars_.remove(progress);

  // Enable the close button when all threads finished.
  if(progress_bars_.empty())
    close_button_->set_sensitive(true);
}

} // anonymous namespace


int main(int argc, char** argv)
{
  Glib::thread_init();
  Gtk::Main main_instance (&argc, &argv);

  MainWindow window;

  // Install a one-shot idle handler to launch the threads
  // right after the main window has been displayed.

  Glib::signal_idle().connect(
      SigC::bind_return(SigC::slot(window, &MainWindow::launch_threads), false));

  Gtk::Main::run(window);

  return 0;
}


Zuletzt bearbeitet von evilissimo am 22:34:20 23.06.2005, insgesamt 1-mal bearbeitet
evilissimo
Chefkoch

Benutzerprofil
Anmeldungsdatum: 11.11.2003
Beiträge: 2281
Beitrag evilissimo Chefkoch 22:40:52 23.06.2005   Titel:              Zitieren

@nachtrag:

Das Beispiel ist nicht von mir. Es ist von Daniel Elstner und etwas anders als meines.

Ich hab es bewusst ähnlich gemacht, da ich es für ein gutes Beispiel gehalten habe.
In den aktuellen Versionen haben die in den glibmm verzeichnissen aber nur noch non-gtkmm Beispiele, d.h. reine glibmm sources.

Ausserdem hab ich meine Version stark vereinfacht. Und ausreichend kommentiert (hoffe ich) Sollten noch fragen auftreten meldet euch einfach. Und postet nicht irgendwas.

MfG

_________________
evilissimo - R.I.P. dmr
< Moderator im C++/CLI Forum und im C++ Forum >
About Singletons: "Anyway, if our experts can make this mistake, you have made it and you don't even know about it."
C/C++ Forum :: FAQ - GUIs ::  gtkmm Beispiel Programm Pt. 3 ( Multithreaded )   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können keine Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum nicht antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info, www.c-sar.de, www.c-plusplus.net und www.baeckmann.de enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.