You are not logged in.

Dear visitor, welcome to QtForum.org. If this is your first visit here, please read the Help. It explains in detail how this page works. To use all features of this page, you should consider registering. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.

1

Monday, December 12th 2011, 9:11am

QThread inside the same object

Hello,

I have a QMainWindow widget which has a image-window in it, in which I display frames grabbed from a camera. The type of frame that is displayed, is dependent of other parameters that can be set in the QMainWindow widget, or its children. I want to have it so, that frames can be displayed and updated continiously while still being able to change the parameters (the GUI has to remain active).

So when the button "start" is pressed in the GUI widget (QMainWindow), I want to start GUI::ViewerThread(void). The problem I have is that I want to have two seperate threads in the same object (GUI), this way I can use all the variables of the GUI-object, and update them continiously in GUI::ViewerThread(void).

I tried something like this without succes:

Source code

1
2
3
4
5
6
7
void GUI::startPressed(void)
{	
QThread* viewerThread = new QThread();	
// Move ViewerThread void to new viewerThread ??? 	
connect(viewerThread, SIGNAL(started()), this, SLOT(ViewerThread(void)));
viewerThread->start();
}


The only way I was able to get it to work, was to make all my variables global, and then start the thread in a seperate object. This seems very hacky programming, so I want to do it differently.

Can anyone help me?

Thanks!

2

Monday, December 12th 2011, 10:45am

QThread needs access to all information so it can be executed in 'run' method. If the thread is now doing all the work, there should be no problem in passing all arguments into your QThread sub class.

If the gui is still using that data whilst the thread is using it as well, then that is not a good position to be in - you should make signal/slot connectins that pass data
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

3

Monday, December 12th 2011, 11:07am

First of all I should note that I am not working with a QThread sublclassing method ...

If I understand you correctly it is not possible to do what I want to do? To get this to work I need to create a second object to handle all the "viewer" tasks and then pass all variables and objects to this object? (these are ALL the variables and objects the QMainWidget has - about 50). Then I need to create signals etc. inside the GUI object to update the "viewer object" whenever a change is made to the GUI object?

This seems like a very indirect method. Especially since it is a very simple task that needs to be performed. Dissapointing.

4

Monday, December 12th 2011, 12:59pm

erm, I think the only way you can use QThread (to actually start another thread with your custom code) is to sub class it. Please show me how you are using it.

What you want to do seems very simple, and there will be a simple way to handle it. Although you mentioning data in mainwindow leaves me a bit worried. I think you should post more of your code.
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

5

Monday, December 12th 2011, 1:46pm

First of all, thank you for your replies! They are helpful. I will try to clarify my problem more.

I am not using subclassing, because I think it becomes a mess when creating subclassed QThreads, and then use these globally declared objects inside another object. The way I want to use threads was described by this article: http://codethis.wordpress.com/2011/04/04…ut-subclassing/ .
This looks very familiar as it is quite comparable to the boost threads etc.

The GUI-object I was talking about is a subclassed QMainWindow, and it contains all the variables and objects I use in my application. This is probably the problem, because of this I can't access my variables from outside the object. What I can do is create a struct called GUIContainer which contains all the variables from the GUI object and then pass that to the thread, is that a good idea?

6

Monday, December 12th 2011, 2:04pm

I am surprised that that method works -

reader->moveToThread(thread)

looks to me like it shouldn't do anything because 'thread' is on the same thread as 'reader'.

Anyhow, as I said before, I am worried by you saying you have 50 member vars in main window - you have too many responsibilites in one class, you have no encapsulation. Post your code and I can help re-arrange it so that it makes more sense and is more flexible.
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

7

Monday, December 12th 2011, 2:38pm

I can't post my code here without making it superchaotic because it's huge and divided over many many files. Can you give me some general pointers, maybe I can try to re-code my program? What did you think about the idea of using a GUIContainer object which contains all the variables?

8

Monday, December 12th 2011, 2:43pm

I think it is equally hacky. You have a big design problem from the sounds of it, and now you are facing the consequences.

can you at least post your mainwindow code?

Every little 'job' that you can identify, every 'responsibilty', should have it's own class.
http://en.wikipedia.org/wiki/Single_responsibility_principle
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

9

Monday, December 12th 2011, 3:02pm

Source 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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
class GUI : public QMainWindow, private Ui::KinectThresholdingCppClass
{
	Q_OBJECT

	public:
		GUI(QWidget *parent = 0, Qt::WFlags flags = 0);
		~GUI();

		/* Windows */
		QHalconWindow *qWindow;
		QVTKWidget *vtkWidget;

		/* Objects */
		Kinect *kinect;

		/* Visualisation stuff */
		PointCloud<PointXYZRGB>::ConstPtr cloud;

		/* Timers */
		QTimer *updateLogBrowserTimer;

		/* Threads */
		RGBViewerThread *rgbViewer;

	private:
		/* Imported GUI elements from the UI file */
		Ui::KinectThresholdingCppClass ui;

		/* Windows */
		GUIRobotConfig *robotConfig;
		GUIKinectAccelerometer *kinectAccelerometer;

		/* Log file */
		PJLib::Log *log;

	private slots:
		void startPressed(void);
		void UpdateSpanValues(void);
		void UpdateThresholdingChecked(void);
		void StartRobotConfig(void);
		void StartKinectAccelerometer(void);
		void ActionViewRGB(void);
		void ActionViewPoint_Cloud(void);
		void UpdateLogBrowser(void);
		void TestButtonPressed(void);
};



/* Constructor: make GUI */
GUI::GUI(QWidget *parent, Qt::WFlags flags)  : QMainWindow(parent, flags)
{
	setupUi(this);
	this->setWindowIcon(QIcon(QString("Images/robovisionIcon.png")));
	//this->setFixedSize(this->sizeHint());

	qWindow = new QHalconWindow(qWindowHub);
	qWindow->setMinimumSize(640, 480);

	/* Setup the log browser */
	this->log = new PJLib::Log("Logs\\", "Log.txt");
	logBrowser->setSearchPaths(QStringList("Logs\\"));
	logBrowser->setSource(QUrl::fromLocalFile("Log.txt"));
	this->updateLogBrowserTimer = new QTimer(this);
	this->updateLogBrowserTimer->start(500);

	/* Connect the GUI to the program action */
	QObject::connect(QButtonStart, SIGNAL(clicked()), this, SLOT(startPressed()));
	QObject::connect(qxtSpanSliderX, SIGNAL(spanChanged(int, int)), this, SLOT(UpdateSpanValues()));
	QObject::connect(qxtSpanSliderY, SIGNAL(spanChanged(int, int)), this, SLOT(UpdateSpanValues()));
	QObject::connect(qxtSpanSliderZ, SIGNAL(spanChanged(int, int)), this, SLOT(UpdateSpanValues()));
	QObject::connect(actionRobotConfig, SIGNAL(triggered()), this, SLOT(StartRobotConfig()));
	QObject::connect(actionAccelerometer, SIGNAL(triggered()), this, SLOT(StartKinectAccelerometer()));
	QObject::connect(actionViewRGB, SIGNAL(triggered()), this, SLOT(ActionViewRGB()));
	QObject::connect(actionViewPoint_Cloud, SIGNAL(triggered()), this, SLOT(ActionViewPoint_Cloud()));
	QObject::connect(testButton, SIGNAL(clicked()), this, SLOT(TestButtonPressed()));
	QObject::connect(this->updateLogBrowserTimer, SIGNAL(timeout()), this, SLOT(UpdateLogBrowser()));
	QObject::connect(this->thresholdingGroupBox, SIGNAL(toggled(bool)), this, SLOT(UpdateThresholdingChecked()));
	
	/* Set the globals */
	testWindow = qWindow->halconWindow;
	lowX = qxtSpanSliderX->lowerValue();
	highX = qxtSpanSliderX->upperValue();
	lowY = qxtSpanSliderY->lowerValue();
	highY= qxtSpanSliderY->upperValue();
	lowZ = qxtSpanSliderZ->lowerValue();
	highZ = qxtSpanSliderZ->upperValue();
	isThresholdingChecked = thresholdingGroupBox->isChecked();

	/* Initialise the kinect and create new 3D model */
	bool isKinectConnected = false;
	while(!isKinectConnected)
	{
		try
		{
			this->kinect = new Kinect(this->log);
			isKinectConnected = true;
		}
		catch (exception& ex)
		{
			QString *error = new QString();
			error->append("The kinect could not be initialised. Make sure it is connected properly (USB and Power).");
			error->append("\n\nThe error message: \n");
			error->append(ex.what());
			QMessageBox kinectErrorBox;
			kinectErrorBox.setWindowTitle("Kinect not initialised!");
			kinectErrorBox.setIcon(QMessageBox::Critical);
			kinectErrorBox.setText(*error);
			kinectErrorBox.setStandardButtons(QMessageBox::Retry | QMessageBox::Abort);
			QIcon kinectIcon = QIcon("Images/kinectIcon.png");
			kinectErrorBox.setWindowIcon(kinectIcon);

			/* Set the stylesheet */
			QFile file("PJStyleSheet.css");				// TO DO
			file.open(QFile::ReadOnly);
			QString StyleSheet = QLatin1String(file.readAll());
			kinectErrorBox.setStyleSheet(StyleSheet);

			kinectErrorBox.show();

			switch (kinectErrorBox.exec()) {
				case QMessageBox::Retry:
					break;
				case QMessageBox::Abort:
					exit(0);
					break;
				default:
					break;
			}
		}
	}
	model3D = new Model3D(kinect);

	/* Initialise threads */
	this->rgbViewer = new RGBViewerThread();
}

GUI::~GUI()
{
	rgbViewer->terminate();
	this->close();
	exit(0);
}

void GUI::startPressed(void)
{
	//boost::thread workerThread(&GUI::ViewerThread); 
	//workerThread.start_thread();

	/*
	QThread* viewerThread = new QThread();
	// Move ViewerThread void to new viewerThread ??? 
	connect(viewerThread, SIGNAL(started()), this, SLOT(ViewerThread(void)));
	viewerThread->start();
	*/

	if(actionViewRGB->isChecked() && !rgbViewer->isRunning())
	{
		this->rgbViewer->start(); 
	}
	else if(actionViewPoint_Cloud->isChecked())
	{
		this->cloud.reset(new pcl::PointCloud<pcl::PointXYZRGB>);
		this->cloud = model3D->GrabPointCloud();
		/*vtkWidget = new QVTKWidget(this->qWindowHub);
		boost::shared_ptr<pcl::visualization::PCLVisualizer>viewer(new pcl::visualization::PCLVisualizer ("3D Viewer"));
		viewer->setBackgroundColor (0, 0, 0);
		viewer->addPointCloud<pcl::PointXYZRGB>(cloud);*/

		//pviz->addPointCloud<pcl::PointXYZRGB>(cloud);
		//pviz.setBackgroundColor(0, 0, 0);
		//vtkWidget->show();

		/* Visualise the point cloud */
		visualization::CloudViewer viewer("Point Cloud");
		viewer.showCloud(cloud);
		while (!viewer.wasStopped ());	
	}
	else
	{
		// Should never end up here ...
	}
}

void GUI::UpdateSpanValues(void)
{
	lowX = qxtSpanSliderX->lowerValue();
	highX = qxtSpanSliderX->upperValue();
	lowY = qxtSpanSliderY->lowerValue();
	highY= qxtSpanSliderY->upperValue();
	lowZ = qxtSpanSliderZ->lowerValue();
	highZ = qxtSpanSliderZ->upperValue();
}

void GUI::UpdateThresholdingChecked(void)
{
	isThresholdingChecked = thresholdingGroupBox->isChecked();
}

/* View actions */
void GUI::ActionViewRGB(void)
{
	/* Disable the other option */
	actionViewPoint_Cloud->setChecked(false);
}

void GUI::ActionViewPoint_Cloud(void)
{
	/* Disable the other option */
	actionViewRGB->setChecked(false);

	/* If the rgbViewer was running, stop it and clear the testWindow */
	if(rgbViewer->isRunning())
	{
		rgbViewer->terminate();
		// Clear the testWindow -> TO DO
	}

	/* Put the pointcloud window in the windowHub */
	// TO DO 
}

void GUI::UpdateLogBrowser(void)
{
	this->logBrowser->reload();
}

/* Configuration screens */
void GUI::StartRobotConfig(void)
{
	robotConfig = new GUIRobotConfig(this, this->kinect, testWindow);
	robotConfig->show();
}

void GUI::StartKinectAccelerometer(void)
{
	kinectAccelerometer = new GUIKinectAccelerometer(this->kinect, this);
	kinectAccelerometer->show();
}

/* Test buttons */
void GUI::TestButtonPressed(void)
{
	PointCloud<PointXYZRGB>::ConstPtr cloud; 
	try
	{
		cloud = model3D->PointCloudFromMultipleImagesWithRobot();
		
		/* Visualise the point cloud */
		visualization::CloudViewer viewer("Point Cloud");		// TO DO: learn to use the PCLVisualiser
		viewer.showCloud(cloud);
		while (!viewer.wasStopped ());

		/*boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
		viewer->setBackgroundColor (0, 0, 0);
		viewer->addPointCloud(cloud, "Point Cloud");
		viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
		viewer->addCoordinateSystem (1.0);
		viewer->initCameraParameters ();*/
	}
	catch (exception& ex)
	{
		QString errorMessage;
		errorMessage.append("ERROR: ");
		errorMessage.append(ex.what());
		QMessageBox::critical(0, "Error", errorMessage);
	}	
}


Also I do not have a programming background but would like to learn as much as possible about it in the coming months. Discussions like this are very helpfull for me. Thanks alot!

This post has been edited 2 times, last edit by "Pieter-Jan5000" (Dec 12th 2011, 3:12pm)


10

Monday, December 12th 2011, 3:30pm

your mainwindow should probably not know about any other widgets. Bare essentials should go in mainwindow, like making file menu or toolbars. Then you place your own widgets into mainwindow's central widget, or docked widget areas.

You should probably have not many slots in mainwindow. Timers, threads, visualisation I would remove (as members from mainwindow). Not sure what Kinect is. I very much doubt the need for globals in your code.

/* Windows */
GUIRobotConfig *robotConfig;
GUIKinectAccelerometer *kinectAccelerometer;

If these are separate windows, they probably shouldn't be here. If they are widgets, then maybe.

All you signals are connected to mainwindow - mainwindow is looking after multiple 'changes'. You should be creating separate classes to look after these changes, and this is where the signals should be connected to.
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

11

Monday, December 12th 2011, 3:39pm

here is an example of some of my older code. It is a simple image viewer app.

There is a directory tree for selecting a location to browse.
There is a browser for showing thumbnails.
There is an editor that lets you put simple drawings on an image
There is a reporter that lets you build simple documents that include some images you have chosen (including your drawings)

A lot of this functionality you cannot see at all in the mainwindow:

Source 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
#include "ImageViewer.h"

#include <string>
#include <QTreeView>
#include <QFileDialog>

//#includes

ImageViewer::ImageViewer( std::string const & path, QWidget *parent, Qt::WFlags flags )
: QMainWindow(parent, flags), m_model(NULL)
{
  Init();

  SlotConfigure( path.c_str() );
}

ImageViewer::ImageViewer( QWidget *parent, Qt::WFlags flags )
: QMainWindow(parent, flags), m_model(NULL)
{
  Init();
}

void
ImageViewer::Init()
{
  ui.setupUi(this);

  resize(600,400);

  ResizeableGraphicsView* v = new ResizeableGraphicsView;
  m_browser = new CBrowser( v, m_reporter, this );

  this->centralWidget()->layout()->addWidget( v );

  connect(ui.treeView,
          SIGNAL(doubleClicked ( const QModelIndex &)),
          this,
          SLOT(SlotDoubleClicked ( const QModelIndex &)));

  connect( ui.action_Configure,
           SIGNAL(triggered()),
           this,
           SLOT(SlotConfigure())
           );

  connect( ui.actionSave_Report,
           SIGNAL(triggered()),
           &m_reporter,
           SLOT(SaveReport())
           );

  connect( ui.actionPrint_Report,
           SIGNAL(triggered()),
           &m_reporter,
           SLOT(PrintReport())
           );
}

ImageViewer::~ImageViewer()
{
}

void
ImageViewer::SlotDoubleClicked( const QModelIndex & modelIndex )
{
  TreeItem* item = static_cast<TreeItem*>(modelIndex.internalPointer());

  const int FULL_PATH = 1;

  QString dir = item->data(FULL_PATH).toString();

  m_browser->Browse( dir );
}

void
ImageViewer::SlotConfigure()
{
  QString dir = QFileDialog::getExistingDirectory(this, "Select Directory",
                                                  "c:\\",
                                                  QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);

  SlotConfigure( dir );
}

void
ImageViewer::SlotConfigure( QString const & path )
{
  if(path != "")
  {
    ImageFileModel* oldModel = m_model;
    m_model = new ImageFileModel( path, this );

    ui.treeView->setModel(m_model);
  
    if(oldModel)
    {
      oldModel->setParent(0);
      delete oldModel;
    }

    CConfigController::Instance().().Path = path.toStdString();
    CConfigController::Instance().Save();
  }
}


Apart from creating the browser and a couple of connections (ie some initialisation stuff - not connecting to its own slots), it is only concerned with dealing with new file paths to browse (slotconfigure, slotdoubleclicked). Contrast this with lots of slots that do very different things in your code.

Ultimately, where I am trying to help you head towards, is to get to a point where you can pass just one class to a QThread, and for that class to be relatively simple.

Maybe we can shortcut this a bit - what is it that you actually want to happen in the othre thread?
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

This post has been edited 4 times, last edit by "Amleto" (Dec 12th 2011, 3:50pm)


12

Monday, December 12th 2011, 4:06pm

Allright. It seems that I have alot of redesigning to do. I am trying to understand your code etc. this might take a while though.

To answer your question:

The thread I want to create first grabs an image from the camera (kinect object). Then, wheter the "thresholding" checkbox on the main GUI is checked, it thresholds the image with values that are also set in the main GUI with trackbars. It keeps doing this until the program is closed so that there is a live stream of the camera. I hope I explained it OK.

13

Monday, December 12th 2011, 4:17pm

Don't worry too much about understanding the code - it is not complete afterall! It is just an example to show that there shouldn't be much in a mainwindow.


OK, so in your code you have some 'live configuration' going on, a picture grab, and a picture manipulation, and a display of the picture. These seem like natural 'jobs' to split your code up in to.

The aggregation of these things - some manager or updater would treat all of these jobs as black boxes, but just connect the inputs and outputs.

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
class Updater
{
Q_OBJECT
private:
Config* cfg; // weak reference to config - widgets should probalby be made from mainwindow
PicGrabber grabber; // our own grabber - not needed anywhere else
PicManip manipulator;

QTimer timer;

signals:
void signalNewImage(QPixmap/QImage/ whatever)
};


A couple of arge need to passed, like update frequency, and where to grab the image from (this would just be passed into the grabber).

But now you can see that all you would need to pass into a thread would be Updater, and it barely does anything for itself.

edit: slightly better would be to have slots for updated config, and this would just pass through the information to the pic manipulator. Then Updater wouldnt need to know about Config at all.
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

14

Monday, December 12th 2011, 4:23pm

Sorry I lost you there.

If I made a "updater" object for the frame I would need to pass these variables:
- Kinect object (this is the camera)
- bool isThresholding (to know wheter it should threshold the image) (checkbox on the QMainWindow)
- int lowX, highX, lowY, highY, lowZ, highZ (trackbars on the QMainWindow)

How do I pass al these variables from the QMainWindow to the Updater object, and keep them live after creating the object? If the user modifies a value, the change has to be visible imidiently.

Sorry, It's really confusing stuff for me! hehe

15

Monday, December 12th 2011, 4:42pm

you missed out this bit:
OK, so in your code you have some 'live configuration' going on, a picture grab, and a picture manipulation, and a display of the picture. These seem like natural 'jobs' to split your code up in to.

You should (imo) create classes for these jobs.

The configuration class would look after updates from the trackbars and checkbox.
The grabber class would need to know about Kinect. Maybe Kinect is good enough already for this job.

An Updater class could have slots that are connected to the config class - so the updater always gets the new values. Alternatively you could give the updater a handle to the config class, so that it could pull the current values whenever it needs.
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

16

Monday, December 12th 2011, 4:51pm

Aha! Cool.

Yeah the Kinect class is pretty solid, it has Kinect->grabFrame() method's etc. inside. I'm not 100% sure if I see the puzzle fit, but it starts to make sense.

So the signals from the trackbars, checkboxes etc. result in a change of the "config" object, right? This could be realised with a void UpdateConfig() I assume. I will have to mutex lock this thing I assume. The thread will the continiously read from the config object with the correct values.

Allright ... good stuff. Worth trying! Thanks so much!

17

Monday, December 12th 2011, 5:29pm

The signals should push a value to a slot that updates the exact value. It shouldn't need to be mutexed.

class config_class
{
slot: void config_class_slot_for_checkbox(bool);
bool m_b;
};


checkbox_signal(bool) -> config_class_slot_for_checkbox(bool b) -> update m_b;

if you have more than two or three config variables, then I would wrap them in a struct.

If we take the config class to be in the main thread, and we add signals to the class as a 'public interface' for config changes, then we connect those signals to the updater, which would pass the values into e.g. the manipulator class.

So we make the config class the authority on what the true config is, and everything that wants config info should connect to the config class.


gui config signal -> config class slot -> config update -> config signal -> <- rest of system should connect here.

You could do one signal per hi/low/x/y/z, or you could always send out the full config in a struct.
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

This post has been edited 1 times, last edit by "Amleto" (Dec 12th 2011, 5:38pm)


18

Monday, December 12th 2011, 7:14pm

I was able to get it to work! Thanks so much!

These are my classes:

Source 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
class ViewerConfig : public QObject
{
	Q_OBJECT 

	public:
ViewerConfig(){};
int lowX;
int highX;
int lowY;
int highY;
int lowZ;
int highZ;
bool isThresholdingChecked;
bool isContinuousChecked;

	public slots:
void UpdateContinuousStatus(bool checkBoxStatus);
void UpdateThresholdingStatus(bool checkBoxStatus);
void UpdateThresholdRangeX(int lowX, int highX);
void UpdateThresholdRangeY(int lowY, int highY);
void UpdateThresholdRangeZ(int lowZ, int highZ);
};

class Viewer : public QObject
{
	Q_OBJECT 

	private:
/* Window to display things */
HWindow *hWindow;

/* Object that grab frames */
Kinect *kinect;

/* Information about how the frame needs to be grabbed */
ViewerConfig *viewerConfig;

/* Images */
HImage image; // Image from the RGB camera
HImage imageX; // Image with X-coördinate information
HImage imageY; // Image with Y-coördinate information
HImage imageZ; // Image with Z-coördinate information
HRegion thresholdX; // Thresholded X-image
HRegion thresholdY; // Thresholded Y-image
HRegion thresholdZ; // Thresholded Z-image
HRegion threshold3D;	// Combination of XYZ thresholds
HImage imageFinal;

bool isWindowInitialised;

void InitialiseWindow(void);
HImage GetFrame(void);

	public:
Viewer::Viewer(HWindow *hWindow, Kinect *kinect, ViewerConfig *viewerConfig);

	public slots:
void Start(void);
};


I routed the signals like this:

Source code

1
2
3
4
QObject::connect(this->qxtSpanSliderX, SIGNAL(spanChanged(int, int)), this->viewerConfig, SLOT(UpdateThresholdRangeX(int, int)));
	QObject::connect(this->qxtSpanSliderY, SIGNAL(spanChanged(int, int)), this->viewerConfig, SLOT(UpdateThresholdRangeY(int, int)));
	QObject::connect(this->qxtSpanSliderZ, SIGNAL(spanChanged(int, int)), this->viewerConfig, SLOT(UpdateThresholdRangeZ(int, int)));
	QObject::connect(this->thresholdingGroupBox, SIGNAL(toggled(bool)), this->viewerConfig, SLOT(UpdateThresholdingStatus(bool)));


And I created my thread like this:

Source code

1
2
3
4
5
6
7
8
9
void GUI::startPressed(void)
{
	QThread *thread;
	thread = new QThread;
	this->viewer->moveToThread(thread);

	QObject::connect(thread, SIGNAL(started()), this->viewer, SLOT(Start()));
	thread->start();
}


Thanks again!

19

Monday, December 12th 2011, 8:00pm

Gald it's working. I think it is much better now.
If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.