diff --git a/GUI/main_window.py b/GUI/main_window.py
new file mode 100644
index 0000000000000000000000000000000000000000..53dacce61b5acbfe9de9607a2499c57e0a386eae
--- /dev/null
+++ b/GUI/main_window.py
@@ -0,0 +1,200 @@
+"""@package docstring
+B-ASIC GUI Module.
+This python file is an example of how a GUI can be implemented
+using buttons and textboxes.
+"""
+
+import sys
+
+from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QLabel, QAction,\
+QStatusBar, QMenuBar, QLineEdit, QPushButton
+from PyQt5.QtCore import Qt
+from PyQt5.QtGui import QIcon, QFont, QPainter, QPen
+
+
+class DragButton(QPushButton):
+    """How to create a dragbutton"""
+    def mousePressEvent(self, event):
+        self._mouse_press_pos = None
+        self._mouse_move_pos = None
+        if event.button() == Qt.LeftButton:
+            self._mouse_press_pos = event.globalPos()
+            self._mouse_move_pos = event.globalPos()
+
+        super(DragButton, self).mousePressEvent(event)
+
+    def mouseMoveEvent(self, event):
+        if event.buttons() == Qt.LeftButton:
+            cur_pos = self.mapToGlobal(self.pos())
+            global_pos = event.globalPos()
+            diff = global_pos - self._mouse_move_pos
+            new_pos = self.mapFromGlobal(cur_pos + diff)
+            self.move(new_pos)
+
+            self._mouse_move_pos = global_pos
+
+        super(DragButton, self).mouseMoveEvent(event)
+
+    def mouseReleaseEvent(self, event):
+        if self._mouse_press_pos is not None:
+            moved = event.globalPos() - self._mouse_press_pos
+            if moved.manhattanLength() > 3:
+                event.ignore()
+                return
+
+        super(DragButton, self).mouseReleaseEvent(event)
+
+class SubWindow(QWidget):
+    """Creates a sub window """
+    def create_window(self, window_width, window_height):
+        """Creates a window
+        """
+        parent = None
+        super(SubWindow, self).__init__(parent)
+        self.setWindowFlags(Qt.WindowStaysOnTopHint)
+        self.resize(window_width, window_height)
+
+class MainWindow(QMainWindow):
+    """Main window for the program"""
+    def __init__(self, *args, **kwargs):
+        super(MainWindow, self).__init__(*args, **kwargs)
+
+        self.setWindowTitle(" ")
+        self.setWindowIcon(QIcon('small_logo.png'))
+
+        # Menu buttons
+        test_button = QAction("Test", self)
+
+        exit_button = QAction("Exit", self)
+        exit_button.setShortcut("Ctrl+Q")
+        exit_button.triggered.connect(self.exit_app)
+
+        edit_button = QAction("Edit", self)
+        edit_button.setStatusTip("Open edit menu")
+        edit_button.triggered.connect(self.on_edit_button_click)
+
+        view_button = QAction("View", self)
+        view_button.setStatusTip("Open view menu")
+        view_button.triggered.connect(self.on_view_button_click)
+
+        menu_bar = QMenuBar()
+        menu_bar.setStyleSheet("background-color:rgb(222, 222, 222)")
+        self.setMenuBar(menu_bar)
+
+        file_menu = menu_bar.addMenu("&File")
+        file_menu.addAction(exit_button)
+        file_menu.addSeparator()
+        file_menu.addAction(test_button)
+
+        edit_menu = menu_bar.addMenu("&Edit")
+        edit_menu.addAction(edit_button)
+
+        edit_menu.addSeparator()
+
+        view_menu = menu_bar.addMenu("&View")
+        view_menu.addAction(view_button)
+
+        self.setStatusBar(QStatusBar(self))
+
+    def on_file_button_click(self):
+        print("File")
+
+    def on_edit_button_click(self):
+        print("Edit")
+
+    def on_view_button_click(self):
+        print("View")
+
+    def exit_app(self, checked):
+        QApplication.quit()
+
+    def clicked(self):
+        print("Drag button clicked")
+
+    def add_drag_buttons(self):
+        """Adds draggable buttons"""
+        addition_button = DragButton("Addition", self)
+        addition_button.move(10, 130)
+        addition_button.setFixedSize(70, 20)
+        addition_button.clicked.connect(self.create_sub_window)
+
+        addition_button2 = DragButton("Addition", self)
+        addition_button2.move(10, 130)
+        addition_button2.setFixedSize(70, 20)
+        addition_button2.clicked.connect(self.create_sub_window)
+
+        subtraction_button = DragButton("Subtraction", self)
+        subtraction_button.move(10, 170)
+        subtraction_button.setFixedSize(70, 20)
+        subtraction_button.clicked.connect(self.create_sub_window)
+
+        subtraction_button2 = DragButton("Subtraction", self)
+        subtraction_button2.move(10, 170)
+        subtraction_button2.setFixedSize(70, 20)
+        subtraction_button2.clicked.connect(self.create_sub_window)
+
+        multiplication_button = DragButton("Multiplication", self)
+        multiplication_button.move(10, 210)
+        multiplication_button.setFixedSize(70, 20)
+        multiplication_button.clicked.connect(self.create_sub_window)
+
+        multiplication_button2 = DragButton("Multiplication", self)
+        multiplication_button2.move(10, 210)
+        multiplication_button2.setFixedSize(70, 20)
+        multiplication_button2.clicked.connect(self.create_sub_window)
+
+    def paintEvent(self, e):
+        # Temporary black box for operations
+        painter = QPainter(self)
+        painter.setPen(QPen(Qt.black, 5, Qt.SolidLine))
+        painter.drawRect(0, 110, 100, 400)
+
+        # Temporary arrow resembling a signal
+        painter.setRenderHint(QPainter.Antialiasing)
+        painter.setPen(Qt.black)
+        painter.setBrush(Qt.white)
+        painter.drawLine(300, 200, 400, 200)
+        painter.drawLine(400, 200, 395, 195)
+        painter.drawLine(400, 200, 395, 205)
+
+    def create_sub_window(self):
+        """ Example of how to create a sub window
+        """
+        self.sub_window = SubWindow()
+        self.sub_window.create_window(400, 300)
+        self.sub_window.setWindowTitle("Properties")
+
+        self.sub_window.properties_label = QLabel(self.sub_window)
+        self.sub_window.properties_label.setText('Properties')
+        self.sub_window.properties_label.setFixedWidth(400)
+        self.sub_window.properties_label.setFont(QFont('SansSerif', 14, QFont.Bold))
+        self.sub_window.properties_label.setAlignment(Qt.AlignCenter)
+
+        self.sub_window.name_label = QLabel(self.sub_window)
+        self.sub_window.name_label.setText('Name:')
+        self.sub_window.name_label.move(20, 40)
+
+        self.sub_window.name_line = QLineEdit(self.sub_window)
+        self.sub_window.name_line.setPlaceholderText("Write a name here")
+        self.sub_window.name_line.move(70, 40)
+        self.sub_window.name_line.resize(100, 20)
+
+        self.sub_window.id_label = QLabel(self.sub_window)
+        self.sub_window.id_label.setText('Id:')
+        self.sub_window.id_label.move(20, 70)
+
+        self.sub_window.id_line = QLineEdit(self.sub_window)
+        self.sub_window.id_line.setPlaceholderText("Write an id here")
+        self.sub_window.id_line.move(70, 70)
+        self.sub_window.id_line.resize(100, 20)
+
+        self.sub_window.show()
+
+
+if __name__ == "__main__":
+    app = QApplication(sys.argv)
+    window = MainWindow()
+    window.add_drag_buttons()
+    window.resize(960, 720)
+    window.show()
+    app.exec_()
diff --git a/b_asic/operation.py b/b_asic/operation.py
index c75ca87b96d8794a4f3eb6ee939c446d3f02b2df..a0d0f48a1f7429ce0d393ad4e93ef24c84914f7b 100644
--- a/b_asic/operation.py
+++ b/b_asic/operation.py
@@ -348,7 +348,8 @@ class AbstractOperation(Operation, AbstractGraphComponent):
     def source(self) -> OutputPort:
         if self.output_count != 1:
             diff = "more" if self.output_count > 1 else "less"
-            raise TypeError(f"{self.__class__.__name__} cannot be used as an input source because it has {diff} than 1 output")
+            raise TypeError(
+                f"{self.__class__.__name__} cannot be used as an input source because it has {diff} than 1 output")
         return self.output(0)
     
     def truncate_input(self, index: int, value: Number, bits: int) -> Number:
@@ -372,4 +373,4 @@ class AbstractOperation(Operation, AbstractGraphComponent):
                     args.append(self.truncate_input(i, input_values[i], bits))
             else:
                 args.append(input_values[i])
-        return args
\ No newline at end of file
+        return args
diff --git a/b_asic/signal_flow_graph.py b/b_asic/signal_flow_graph.py
index 573fb21c3e0c80a72de06af3621d87bcef7c0d5d..950926f48212e825125a0122a272def557499b69 100644
--- a/b_asic/signal_flow_graph.py
+++ b/b_asic/signal_flow_graph.py
@@ -155,6 +155,49 @@ class SFG(AbstractOperation):
                     raise ValueError(f"Output signal #{output_index} is missing source in SFG")
                 if signal.source.operation not in self._original_components_to_new:
                     self._add_operation_connected_tree_copy(signal.source.operation)
+    
+    def __str__(self):
+        """Get a string representation of this SFG."""
+        output_string = ""
+        for component in self._components_ordered:
+            if isinstance(component, Operation):
+                for key, value in self._components_by_id.items():
+                    if value is component:
+                        output_string += "id: " + key + ", name: "
+                
+                if component.name != None:
+                    output_string += component.name + ", "
+                else:
+                    output_string += "-, "
+                
+                if component.type_name is "c":
+                    output_string += "value: " + str(component.value) + ", input: ["
+                else:
+                    output_string += "input: [" 
+
+                counter_input = 0
+                for input in component.inputs:
+                    counter_input += 1
+                    for signal in input.signals:
+                        for key, value in self._components_by_id.items():
+                            if value is signal:
+                                output_string += key + ", "
+                
+                if counter_input > 0:
+                    output_string = output_string[:-2]
+                output_string += "], output: ["
+                counter_output = 0
+                for output in component.outputs:
+                    counter_output += 1
+                    for signal in output.signals:
+                        for key, value in self._components_by_id.items():
+                            if value is signal:
+                                output_string += key + ", "
+                if counter_output > 0:
+                    output_string = output_string[:-2]
+                output_string += "]\n"
+
+        return output_string
 
     def __call__(self, *src: Optional[SignalSourceProvider], name: Name = "") -> "SFG":
         """Get a new independent SFG instance that is identical to this SFG except without any of its external connections."""
diff --git a/small_logo.png b/small_logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..689a38192b9fc4c6ed490e1e0001fd5dd264c968
Binary files /dev/null and b/small_logo.png differ
diff --git a/test/test_print_sfg.py b/test/test_print_sfg.py
new file mode 100644
index 0000000000000000000000000000000000000000..49b0950d82857f86ba652e76075b5d3cb40e1584
--- /dev/null
+++ b/test/test_print_sfg.py
@@ -0,0 +1,46 @@
+"""
+B-ASIC test suite for printing a SFG
+"""
+
+
+from b_asic.signal_flow_graph import SFG
+from b_asic.core_operations import Addition, Multiplication, Constant
+from b_asic.port import InputPort, OutputPort
+from b_asic.signal import Signal
+from b_asic.special_operations import Input, Output
+
+import pytest
+
+
+class TestPrintSfg:
+    def test_print_one_addition(self):
+        inp1 = Input("INP1")
+        inp2 = Input("INP2")
+        add1 = Addition(inp1, inp2, "ADD1")
+        out1 = Output(add1, "OUT1")
+        sfg = SFG(inputs=[inp1, inp2], outputs=[out1], name="sf1")
+
+        assert sfg.__str__() == ("id: add1, name: ADD1, input: [s1, s2], output: [s3]\nid: in1, name: INP1, input: [], output: [s1]\nid: in2, name: INP2, input: [], output: [s2]\nid: out1, name: OUT1, input: [s3], output: []\n")
+
+    def test_print_add_mul(self):
+        inp1 = Input("INP1")
+        inp2 = Input("INP2")
+        inp3 = Input("INP3")
+        add1 = Addition(inp1, inp2, "ADD1")
+        mul1 = Multiplication(add1, inp3, "MUL1")
+        out1 = Output(mul1, "OUT1")
+        sfg = SFG(inputs=[inp1, inp2, inp3], outputs=[out1], name="mac_sfg")
+
+        assert sfg.__str__() == ("id: add1, name: ADD1, input: [s1, s2], output: [s5]\nid: in1, name: INP1, input: [], output: [s1]\nid: in2, name: INP2, input: [], output: [s2]\nid: mul1, name: MUL1, input: [s5, s3], output: [s4]\nid: in3, name: INP3, input: [], output: [s3]\nid: out1, name: OUT1, input: [s4], output: []\n")
+
+    def test_print_constant(self):
+        inp1 = Input("INP1")
+        const1 = Constant(3, "CONST")
+        add1 = Addition(const1, inp1, "ADD1")
+        out1 = Output(add1, "OUT1")
+
+        sfg = SFG(inputs=[inp1], outputs=[out1], name="sfg")
+
+        assert sfg.__str__() == ("id: add1, name: ADD1, input: [s3, s1], output: [s2]\nid: c1, name: CONST, value: 3, input: [], output: [s3]\nid: in1, name: INP1, input: [], output: [s1]\nid: out1, name: OUT1, input: [s2], output: []\n")
+
+     
\ No newline at end of file