diff --git a/QtMeshViewer/Header/FileInterface.h b/QtMeshViewer/Header/FileInterface.h
index 4dbed752ce775c2e23b3d66f76eadb1ce31a1b49..e3b199500ef48f94b02a793c7552e05ddc21691d 100644
--- a/QtMeshViewer/Header/FileInterface.h
+++ b/QtMeshViewer/Header/FileInterface.h
@@ -1,5 +1,4 @@
 #pragma once
-#include <QObject>
 #include <QOpenGlTexture>
 #include <fstream>
 #include <QVector>
@@ -7,7 +6,6 @@
 #include <QMatrix4x4>
 #include <QQuaternion>
 #include <QRegExp>
-#include "MainWindow.h"
 
 struct BoundingBox {
 	QQuaternion rotation;
@@ -54,14 +52,12 @@ struct Material {
 	std::uint8_t dataValues[2] = { 0 };
 };
 
-class FileInterface : public QObject
+class FileInterface
 {
-	Q_OBJECT
 
 public:
-	explicit FileInterface(QString path, QObject *parent)
-		: QObject(parent)
-		, m_models(new QVector<Model*>)
+	explicit FileInterface(QString path)
+		: m_models(new QVector<Model*>)
 		, m_materials(new QVector<Material>)
 	{
 		//open file
@@ -70,10 +66,6 @@ public:
 		if (!m_file.is_open())
 			throw std::invalid_argument(std::string("ERROR: file not found: ") += path.toStdString());
 
-		MainWindow* tmp = dynamic_cast<MainWindow*>(parent->parent()->parent());
-		if(tmp != NULL)
-			connect(this, SIGNAL(sendMessage(QString, int)), tmp, SLOT(printMessage(QString, int)));
-
 		m_filepath = path.left(path.lastIndexOf(QRegExp("/|\\\\")));
 
 	};
@@ -138,6 +130,4 @@ public:
 		return defMaterial;
 	};
 
-signals:
-	void sendMessage(QString msg, int severity);
 };
\ No newline at end of file
diff --git a/QtMeshViewer/Header/GeometryEngine.h b/QtMeshViewer/Header/GeometryEngine.h
index 854241594e2685aebd76738c56bb37885e05943b..235ae9fd4555ee065ebed3ad9f9a3c4808fcdb33 100644
--- a/QtMeshViewer/Header/GeometryEngine.h
+++ b/QtMeshViewer/Header/GeometryEngine.h
@@ -46,7 +46,6 @@ public slots:
 // signals
 signals:
 	void requestResetView();
-	void sendMessage(QString message, int severity);
 	void requestUpdate();
 	void sendFileInfo(QString name, QVector<Material>* materials, int vertices, int triangle);
 };
diff --git a/QtMeshViewer/Header/MshFile.h b/QtMeshViewer/Header/MshFile.h
index 39a959695bdfff74907a4b00ac4e097250dbcb45..f5c3fedb19a44bf652fe37a21e6f95d844446acb 100644
--- a/QtMeshViewer/Header/MshFile.h
+++ b/QtMeshViewer/Header/MshFile.h
@@ -20,7 +20,7 @@ enum ModelTyp {
 class MshFile : public FileInterface
 {
 public:
-	explicit MshFile(QString path, QObject *parent = Q_NULLPTR);
+	explicit MshFile(QString path);
 	virtual ~MshFile();
 
 private:
diff --git a/QtMeshViewer/Header/OglViewerWidget.h b/QtMeshViewer/Header/OglViewerWidget.h
index ed77ed1c7e511a975acaee8918837a59f2907278..4050f7ce0f027e709883dfe8dd75f653e0b98d44 100644
--- a/QtMeshViewer/Header/OglViewerWidget.h
+++ b/QtMeshViewer/Header/OglViewerWidget.h
@@ -91,7 +91,6 @@ public slots:
 
 // signals
 signals:
-	void sendMessage(QString message, int severity);
 	void loadFile(QString);
 };
 
diff --git a/QtMeshViewer/Header/OutputDevice.h b/QtMeshViewer/Header/OutputDevice.h
new file mode 100644
index 0000000000000000000000000000000000000000..3f4ee63f470e313772f5a53b5eef5ea94b85fa4e
--- /dev/null
+++ b/QtMeshViewer/Header/OutputDevice.h
@@ -0,0 +1,27 @@
+#pragma once
+#include <QObject>
+
+class OutputDevice : public QObject
+{
+	Q_OBJECT
+
+private:
+	OutputDevice(QObject *parent = Q_NULLPTR) : QObject(parent) {};
+
+public:
+	OutputDevice(OutputDevice const&) = delete;
+	void operator=(OutputDevice const&) = delete;
+
+	~OutputDevice() {};
+
+	static OutputDevice* getInstance(QObject *parent = Q_NULLPTR) {
+		static OutputDevice* instance = new OutputDevice(parent);
+		return instance;
+	};
+
+	void print(QString message, int severity) { emit sendMessage(message, severity); };
+
+signals:
+	void sendMessage(QString message, int severity);
+
+};
\ No newline at end of file
diff --git a/QtMeshViewer/Source/GeometryEngine.cpp b/QtMeshViewer/Source/GeometryEngine.cpp
index 80549ba4bf3b959faf0a5b0c32e1fc181aa8c5b6..002817e9f89a4e5c947249fac182ade9da94e080 100644
--- a/QtMeshViewer/Source/GeometryEngine.cpp
+++ b/QtMeshViewer/Source/GeometryEngine.cpp
@@ -2,6 +2,7 @@
 #include "..\Header\MshFile.h"
 #include "..\Header\OglViewerWidget.h"
 #include "..\Header\MainWindow.h"
+#include "..\Header\OutputDevice.h"
 #include <QRegExp>
 
 
@@ -154,7 +155,7 @@ void GeometryEngine::loadFile(QString filePath)
 
 	//reset view
 	emit requestResetView();
-	emit sendMessage("loading file..", 0);
+	OutputDevice::getInstance()->print("loading file..", 0);
 
 	try
 	{
@@ -163,7 +164,7 @@ void GeometryEngine::loadFile(QString filePath)
 		QVector<GLuint> indexData;
 
 		// open file and get the information
-		MshFile file(filePath, this);
+		MshFile file(filePath);
 
 		models = file.getModels();
 		m_materials = file.getMaterials();
@@ -213,13 +214,13 @@ void GeometryEngine::loadFile(QString filePath)
 		m_indexBuf.allocate(indexData.data(), indexData.size() * sizeof(GLuint));
 
 		emit requestUpdate();
-		emit sendMessage("done..", 0);
+		OutputDevice::getInstance()->print("done..", 0);
 		emit sendFileInfo(filePath.right(filePath.size() - filePath.lastIndexOf(QRegExp("/|\\\\")) - 1), m_materials, vertexData.size(), indexData.size() / 3);
 	}
 	catch (std::invalid_argument e)
 	{
 		clearData();
-		emit sendMessage(QString(e.what()), 2);
+		OutputDevice::getInstance()->print(QString(e.what()), 2);
 	}
 }
 
diff --git a/QtMeshViewer/Source/MainWindow.cpp b/QtMeshViewer/Source/MainWindow.cpp
index d09568e4b7342030f7beaa8942804fa30f80bb55..ffa2daa77860a701d695ecac6317410e7e34a186 100644
--- a/QtMeshViewer/Source/MainWindow.cpp
+++ b/QtMeshViewer/Source/MainWindow.cpp
@@ -1,6 +1,7 @@
 #include "..\Header\MainWindow.h"
 #include "..\Header\OglViewerWidget.h"
 #include "..\Header\FileInterface.h"
+#include "..\Header\OutputDevice.h"
 #include <QSurfaceFormat>
 #include <QSignalMapper>
 #include <QToolButton>
@@ -29,7 +30,7 @@ MainWindow::MainWindow(QWidget *parent)
 	setWindowTitle(WINDOW_NAME);
 	setWindowIcon(QIcon(":/images/icon.ico"));
 
-	printMessage("MeshViewer by Anakin", 0);
+	connect(OutputDevice::getInstance(this), &OutputDevice::sendMessage, this, &MainWindow::printMessage);
 
 	// setup opengl things
 	QSurfaceFormat format;
@@ -49,6 +50,8 @@ MainWindow::MainWindow(QWidget *parent)
 	QFile styleSheet(":/files/StyleSheet.txt");
 	styleSheet.open(QIODevice::ReadOnly);
 	this->setStyleSheet(styleSheet.readAll());
+
+	printMessage("MeshViewer by Anakin", 0);
 }
 
 MainWindow::~MainWindow()
@@ -67,7 +70,6 @@ void MainWindow::setupWidgets()
 	// Ogl Viewer
 	OglViewerWidget* viewer = new OglViewerWidget(this);
 	setCentralWidget(viewer);
-	connect(viewer, &OglViewerWidget::sendMessage, this, &MainWindow::printMessage);
 
 	// open file
 	QToolButton *openFile = new QToolButton(this);
diff --git a/QtMeshViewer/Source/MshFile.cpp b/QtMeshViewer/Source/MshFile.cpp
index 970d1cd0c63bda2e433dc02f7480d9832c6bd56b..3e13bfb88f2d0b123d8a93152c1b4f8c1493d3d2 100644
--- a/QtMeshViewer/Source/MshFile.cpp
+++ b/QtMeshViewer/Source/MshFile.cpp
@@ -1,5 +1,6 @@
 #include "..\Header\MshFile.h"
 #include "..\Header\tga.h"
+#include "..\Header\OutputDevice.h"
 #include <QColor>
 
 // helper function to save data from file to any variable type
@@ -9,8 +10,8 @@
 /////////////////////////////////////////////////////////////////////////
 // public constructor/destructor
 
-MshFile::MshFile(QString path, QObject * parent)
-	: FileInterface(path, parent)
+MshFile::MshFile(QString path)
+	: FileInterface(path)
 {
 	import();
 }
@@ -89,7 +90,7 @@ void MshFile::loadChunks(std::list<ChunkHeader*>& destination, std::streampos st
 		// out of file. Maybe a size information is corrupted
 		if (!m_file.good())
 		{
-			emit sendMessage("WARNING: corrupted file. Trying to continue..", 1);
+			OutputDevice::getInstance()->print("WARNING: corrupted file. Trying to continue..", 1);
 			m_file.clear();
 			break;
 		}
@@ -506,7 +507,7 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
 
 			if (tmp_size < (unsigned) new_segment->vertices.size())
 			{
-				emit sendMessage("WARNING: too less normals " + QString::number(tmp_size) + " < " + QString::number(new_segment->vertices.size()), 1);
+				OutputDevice::getInstance()->print("WARNING: too less normals " + QString::number(tmp_size) + " < " + QString::number(new_segment->vertices.size()), 1);
 
 				for (unsigned int i = new_segment->vertices.size(); i != tmp_size; i--)
 					for (unsigned int j = 0; j < 3; j++)
@@ -514,7 +515,7 @@ void MshFile::analyseSegmChunks(Model * dataDestination, std::list<ChunkHeader*>
 			}
 			else if (tmp_size > (unsigned) new_segment->vertices.size())
 			{
-				emit sendMessage("WARNING: too many normals " + QString::number(tmp_size) + " > " + QString::number(new_segment->vertices.size()), 1);
+				OutputDevice::getInstance()->print("WARNING: too many normals " + QString::number(tmp_size) + " > " + QString::number(new_segment->vertices.size()), 1);
 				tmp_size = new_segment->vertices.size();
 			}
 
@@ -698,7 +699,7 @@ void MshFile::readUV(Segment * dataDestination, std::streampos position)
 
 	if (tmp_size < (unsigned) dataDestination->vertices.size())
 	{
-		emit sendMessage("WARNING: too less UVs " + QString::number(tmp_size) + " < " + QString::number(dataDestination->vertices.size()),1);
+		OutputDevice::getInstance()->print("WARNING: too less UVs " + QString::number(tmp_size) + " < " + QString::number(dataDestination->vertices.size()),1);
 
 		for (unsigned int i = dataDestination->vertices.size(); i != tmp_size; i--)
 			for (unsigned int j = 0; j < 2; j++)
@@ -706,7 +707,7 @@ void MshFile::readUV(Segment * dataDestination, std::streampos position)
 	}
 	else if (tmp_size > (unsigned) dataDestination->vertices.size())
 	{
-		emit sendMessage("WARNING: too many UVs " + QString::number(tmp_size) + " > " + QString::number(dataDestination->vertices.size()), 1);
+		OutputDevice::getInstance()->print("WARNING: too many UVs " + QString::number(tmp_size) + " > " + QString::number(dataDestination->vertices.size()), 1);
 		tmp_size = dataDestination->vertices.size();
 	}
 
@@ -722,7 +723,7 @@ void MshFile::loadTexture(QOpenGLTexture *& destination, QString filepath, QStri
 
 	if (!loadSuccess)
 	{
-		emit sendMessage("WARNING: texture not found or corrupted: " + filename, 1);
+		OutputDevice::getInstance()->print("WARNING: texture not found or corrupted: " + filename, 1);
 		
 		img = QImage(1, 1, QImage::Format_RGB32);
 		img.fill(QColor(m_materials->back().diffuseColor[0] * 255, m_materials->back().diffuseColor[1] * 255, m_materials->back().diffuseColor[2] * 255));
diff --git a/QtMeshViewer/Source/OglViewerWidget.cpp b/QtMeshViewer/Source/OglViewerWidget.cpp
index 705d7bec141c1188937cd79142c171feb23a2e7a..588066d713e3c337ddee148bd4f3f93aa45dd9ca 100644
--- a/QtMeshViewer/Source/OglViewerWidget.cpp
+++ b/QtMeshViewer/Source/OglViewerWidget.cpp
@@ -1,5 +1,5 @@
 #include "..\Header\OglViewerWidget.h"
-
+#include "..\Header\OutputDevice.h"
 #include <QMouseEvent>
 #include <QDropEvent>
 #include <QMimeData>
@@ -65,7 +65,6 @@ void OglViewerWidget::setConnections()
 	connect(m_dataEngine, &GeometryEngine::requestResetView, this, &OglViewerWidget::resetView);
 	connect(parentWidget(), SIGNAL(loadFile(QString)), m_dataEngine, SLOT(loadFile(QString)));
 	connect(this, SIGNAL(loadFile(QString)), m_dataEngine, SLOT(loadFile(QString)));
-	connect(m_dataEngine, SIGNAL(sendMessage(QString, int)), parentWidget(), SLOT(printMessage(QString, int)));
 	connect(m_dataEngine, SIGNAL(requestUpdate()), this, SLOT(update()));
 	connect(m_dataEngine, SIGNAL(sendFileInfo(QString, QVector<Material>*, int, int)), parentWidget(), SLOT(setFileInfo(QString, QVector<Material>*, int, int)));
 }
@@ -308,12 +307,12 @@ void OglViewerWidget::keyPressEvent(QKeyEvent *e)
 	{
 		m_zSpeed -= 0.1;
 		m_zSpeed < 0.09 ? m_zSpeed = 0 : NULL;
-		emit sendMessage(QString("Zoom speed = %1%").arg(m_zSpeed * 100), 0);
+		OutputDevice::getInstance()->print(QString("Zoom speed = %1%").arg(m_zSpeed * 100), 0);
 	}
 	else if (e->key() == Qt::Key_Plus)
 	{
 		m_zSpeed += 0.1;
-		emit sendMessage(QString("Zoom speed = %1%").arg(m_zSpeed * 100), 0);
+		OutputDevice::getInstance()->print(QString("Zoom speed = %1%").arg(m_zSpeed * 100), 0);
 	}
 }