LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-05-2009, 11:30 AM   #1
jiml8
Senior Member
 
Registered: Sep 2003
Posts: 3,171

Rep: Reputation: 116Reputation: 116
passing class references in gtk (C++)


I am writing a gui using gtk and C++. This leads to an obvious need to pass object and class references to functions. Given that gtk is completely driven by its own internal signal mechanism, the obvious way to pass these class references is by putting a pointer to them in the GObject structure,which is the basic structure for all gtk widgets.

Alternatively, I have to define my objects as global so that they can be accessed from wherever, but I want to avoid that if at all possible.

So, I have done this. I have defined a class called drawing_area, which incorporates a lot of functions associated with a drawing area that I am using for graphing. In my main function, I have defined an instance of that class, called da.

Then I do this:
Code:
g_object_set_data((GObject *)button3,"testdata",(void *)&da);
This places a pointer reference to da into a location in the GObject associated with my button3, which I can later call up by the name "testdata".

At a later time, in a routine that is called when button3 is clicked, I do this:

Code:
	drawing_area* db=reinterpret_cast<drawing_area*>(g_object_get_data((GObject *)object,"testdata"));
I have tried many variants such as this one:

Code:
	drawing_area db=reinterpret_cast<drawing_area>(g_object_get_data((GObject *)object,"testdata"));
I have tried a number of other casting mechanisms as well. All return errors. In the second variant I have shown here the error is:
Quote:
commander.cc: In function 'void begin_collect_data(GtkObject*)':
commander.cc:92: error: invalid cast from type 'void*' to type 'drawing_area'
which is really no surprise because I am trying to cast a pointer to a non-pointer.

In the first variant I show here, the message is:

Quote:
commander.cc:93: error: request for member 'get_drawing_area_size' in 'db', which is of non-class type 'drawing_area*'
commander.cc:99: error: request for member 'draw_rectangle' in 'db', which is of non-class type 'drawing_area*'
What I am trying to do is fairly obvious. Can anyone tell me how to do it?

Last edited by jiml8; 01-05-2009 at 11:32 AM.
 
Old 01-05-2009, 12:22 PM   #2
David1357
Senior Member
 
Registered: Aug 2007
Location: South Carolina, U.S.A.
Distribution: Ubuntu, Fedora Core, Red Hat, SUSE, Gentoo, DSL, coLinux, uClinux
Posts: 1,302
Blog Entries: 1

Rep: Reputation: 107Reputation: 107
Quote:
Originally Posted by jiml8 View Post
What I am trying to do is fairly obvious. Can anyone tell me how to do it?
Try something like this
Code:
drawing_area* db = reinterpret_cast<drawing_area *>(g_object_get_data((GObject *)object,"testdata"));
size = db->get_drawing_area_size;
result = db->draw_rectangle(size);
You have to de-reference a pointer using "->". You did not actually pass a reference to the object in the call to "g_object_set_data", but the address of the object (AKA a pointer to the object).
 
Old 01-05-2009, 04:59 PM   #3
jiml8
Senior Member
 
Registered: Sep 2003
Posts: 3,171

Original Poster
Rep: Reputation: 116Reputation: 116
Quote:
Originally Posted by David1357 View Post
Try something like this
Code:
drawing_area* db = reinterpret_cast<drawing_area *>(g_object_get_data((GObject *)object,"testdata"));
size = db->get_drawing_area_size;
result = db->draw_rectangle(size);
You have to de-reference a pointer using "->". You did not actually pass a reference to the object in the call to "g_object_set_data", but the address of the object (AKA a pointer to the object).
D'uh!

I knew that. At least, I should have.

Oh well. Thanks for pointing it out.

I also spent an hour today tracking down a for loop that wasn't working right. That is how long it took me to spot the semicolon at the end of the line.

Time to go do something else for awhile...
 
Old 01-05-2009, 07:15 PM   #4
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
You should also ask yourself this: Why does a GObject button need access to data? There's rarely a requirement leading to that conclusion than can't be accomplished in a more graceful way, especially with C++. This might just be style and preference, but I think the procedure should own the GUI instead of the GUI owning the procedure. In other words, I find it much easier to maintain GUI/procedure interaction if the GUI is strictly an extension of the procedure and its associated data and logic. In C++, even when mixed with C, there's rarely a case (other than thread instantiation) where you can't avoid circumventing type safety.

You might find it cleaner and simpler to provide a global, C-friendly function to control the action of the button, backed by C++ in a way that appropriately calls the method against the active drawing_area. The button isn't there to be the action, after all; it's there because the button being pressed has meaning to the underlying logic. The GUI doesn't need to know what's going on with the program; it's merely the point of interaction between the user and the underlying system.

Even if it's the sort of program that has multiple windows at a time, and therefore a button3 in several identical GUIs, this can still generally be dealt with in the same way. You'd just need the button to pass some sort of index to the global function.
ta0kira
 
Old 01-05-2009, 09:22 PM   #5
David1357
Senior Member
 
Registered: Aug 2007
Location: South Carolina, U.S.A.
Distribution: Ubuntu, Fedora Core, Red Hat, SUSE, Gentoo, DSL, coLinux, uClinux
Posts: 1,302
Blog Entries: 1

Rep: Reputation: 107Reputation: 107
Quote:
Originally Posted by jiml8 View Post
D'uh!
No worries. We all have our public brain fades. Just read some of my answers to questions and see where I had to edit them later because I was in a rush and left something out.
 
Old 01-06-2009, 05:40 PM   #6
jiml8
Senior Member
 
Registered: Sep 2003
Posts: 3,171

Original Poster
Rep: Reputation: 116Reputation: 116
Quote:
You should also ask yourself this: Why does a GObject button need access to data?
The button doesn't need access to the data. The routine(s) that are called when the button is clicked need access to the data. But the only way I see to provide this access (unless I provide the access globally, which I really don't want to do) is to pass a pointer with the GObject. I say this because I am building the GUI with glade, and only the GObject and predefined user data is passed by gtk into the signal handler. Since I am using glade, I can't put anything useful into that user data field because the contents of that field are loaded from an xml file at runtime.
 
Old 01-06-2009, 06:20 PM   #7
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
I realized after that last post that if one structures a GUI with a parallel data interface (as I do with binary trees,) buttons associated with the corresponding objects will need to know what objects they're attached to in order to propagate their actions. This can obviously apply to your situation. Sorry about that! But (for others,) my philosophy on GUIs stands as posted previously, with this as an exception to keeping GUI components in the dark.
ta0kira

Last edited by ta0kira; 01-06-2009 at 06:21 PM.
 
Old 01-06-2009, 10:47 PM   #8
jiml8
Senior Member
 
Registered: Sep 2003
Posts: 3,171

Original Poster
Rep: Reputation: 116Reputation: 116
When working with gtk, it seems to me that structuring the GUI in parallel with the data is pretty much required for any but the simplest of GUIs. The architecture of gtk motivates that; it is single threaded and event driven. So it works best if you process the signal quickly, pass off the required data/signals/whatever else to the appropriate routine (in a separate thread if it doesn't run very quickly), then return so that gtk will be able to process the next event. And without the capability to pass objects around, you'd be using a lot of globals. I have seen a lot of complaints that "gtk is slow" but this, it seems to me, is because the architecture of the slow program isn't parallel. My gtk interface is quite responsive, but it is fully parallel. It is also very busy.

In my particular case, I find myself having to have a parallel thread that accesses gtk, along with the thread that handles the gui because I am implementing a spectrum analyzer display that needs to collect data and display it in real time - while still handling other button clicks/mouse tracking, etc. Thus, the gtk gui has a real-time animation running in it and I have to run a separate thread to update that animation. This carried with it some implications that I haven't encountered before with gtk.

It is working now, and I am very pleased with it. Gtk is not limiting my system; network bandwidth is because I am shipping the data that is to be displayed across the network (which could be anything but most commonly will be the internet) at 64KB per sample.

Last edited by jiml8; 01-06-2009 at 10:48 PM.
 
Old 01-07-2009, 12:31 AM   #9
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Maybe you should just export the display and limit explicit network traffic to process-control messages. Or pre-process the display data and transfer that over the network. It sounds like the display program doesn't need the data itself; just its analysis. You should be able to do that unless the source machine would be unduly bogged down by processing data for display, then you could make it a subscription-based service where all connected clients receive the next frame as it's processed. The actual display bitmap wouldn't be transferred, nor the raw data; just, e.g. the histogram data pairs, to be rendered for display by the receiver. This would also allow you to export a feed to PNGs, etc.

As far as having a second thread; that's a great idea with lengthy processes. One of the most irritating things as an end user is to initiate a process, only to change one's mind to cancel it, but having the GUI frozen because it's in the same thread as the process.
ta0kira
 
Old 01-07-2009, 12:42 AM   #10
jiml8
Senior Member
 
Registered: Sep 2003
Posts: 3,171

Original Poster
Rep: Reputation: 116Reputation: 116
The machine generating the data is doing real time processing and I want it to run as fast as possible. In fact, the architecture there is such that servicing the spectrum analyzer display on the client is given a low priority and, should the workload get high enough, the client will lose frames. Because of that, I have explicitly refused to do any pre-processing for the display on that box. The data sent to the spectrum analyzer is sent as a straight dump of 4 byte reals, and it is then processed into pixel positions.

The GUI is a command and control program for this real-time system; I need the spectrum analyzer display to see what the system is seeing
 
Old 01-07-2009, 01:09 AM   #11
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Well, since you're still indulging me, have you compared the costs of pre-processing vs. writing millions of bytes to a network port? It sounds like you're at least grouping them, which should minimize (TCP?) frames, but you might find that even a very minor amount of pre-processing could greatly reduce the data transferred, and it might be done in a way that saves both clock cycles on the RT machine (because of reduced network transfer) and bandwidth. While a LAN is fairly reliable, you probably have some level of transmission retry over the internet due to errors.

Another suggestion (as if you can just go redesigning things, etc. ,) more of a question, is that if this machine is so important, why is it directly connected to the internet? It would probably be safer and faster to connect it to some sort of data-analysis machine (some cheap piece of crap) that does nothing but receive data, pre-process it, and forward it over the network. You might even set said piece of crap on top of the other machine and connect them with a serial port or USB. Important people don't deal with other people; they have less important people to do that sort of thing...
ta0kira

Last edited by ta0kira; 01-07-2009 at 01:13 AM.
 
Old 01-07-2009, 10:02 AM   #12
jiml8
Senior Member
 
Registered: Sep 2003
Posts: 3,171

Original Poster
Rep: Reputation: 116Reputation: 116
LOL. The spectrum analyzer display won't be running all the time - only when an operator needs to look at what the system is seeing either for manual calibration purposes or for diagnostic purposes. I am looking for ways to reduce the amount of data transferred. This project is going to go on for quite awhile; efficiencies may suggest themselves.

I want to ship the actual data and not pixel-processed data because, among other things, we might choose to save this data for further analysis. Just depends.

As for why this guy is connected directly to the internet, it is because he is part of the internet. This guy will be the mother (mixed metaphors...lol) of all wireless routers. He is a satellite communications node, and will be monitoring and switching signals among N satellites and M wired and wireless (data link) data connections, mostly in remote locations of the globe.

I am actually building out the hub of this system, while also designing and implementing some hardware and software that implements a patented protocol that will increase efficiency of satellite bandwidth usage. I'm doing most of the software and integration; an associate and I are doing some custom hardware with a DSP in it, and my client owns and maintains the sites.

Right now, my associate and I are doing the core engineering and physics tasks, including proof of concept. When we are satisfied that this all works - when all the major systems engineering is done (and it almost is done), the project will become a fairly routine software engineering job. At that point, I may hire a team to expedite the development and move into the role of project manager.

The gui lets me look at and control, one at a time, any of a number of different satellite monitoring stations to see what they see and adjust what they look at and how they look at it.

It is really a very cool project.

Last edited by jiml8; 01-07-2009 at 10:21 AM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
c++ template class constructors and references PatrickNew Programming 5 06-17-2008 07:52 AM
Problem with passing a class address to a thread nalsrayatko Programming 2 11-25-2007 11:59 AM
passing a class member function to pthread_create. dmail Programming 1 07-29-2006 11:15 AM
Undefined references to vtable in class constructor? RavenOfOdin Programming 2 03-01-2006 05:46 PM
C++ / Passing a variable by reference to a class member function. sepulture Programming 12 11-15-2005 10:23 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:13 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration