def btn_clicked(self):
        """
        slot to which connect buttons
        """
        sender = self.sender()
        self.probe_to_plot = None

        def start_button():
            """
            starts the selected script
            """
            item = self.tree_scripts.currentItem()

            # BROKEN 20170109: repeatedly erases updates to gui
            # self.expanded_items = []
            # for index in range(self.tree_scripts.topLevelItemCount()):
            #     someitem = self.tree_scripts.topLevelItem(index)
            #     if someitem.isExpanded():
            #         self.expanded_items.append(someitem.name)
            self.script_start_time = datetime.datetime.now()


            if item is not None:
                # get script and update settings from tree
                self.running_item = item
                script, path_to_script, script_item = item.get_script()

                self.update_script_from_item(script_item)

                self.log('starting {:s}'.format(script.name))

                # put script onto script thread
                print('================================================')
                print(('===== starting {:s}'.format(script.name)))
                print('================================================')
                script_thread = self.script_thread

                def move_to_worker_thread(script):

                    script.moveToThread(script_thread)

                    # move also the subscript to the worker thread
                    for subscript in list(script.scripts.values()):
                        move_to_worker_thread(subscript)

                move_to_worker_thread(script)

                script.updateProgress.connect(self.update_status) # connect update signal of script to update slot of gui
                script_thread.started.connect(script.run) # causes the script to start upon starting the thread
                script.finished.connect(script_thread.quit)  # clean up. quit thread after script is finished
                script.finished.connect(self.script_finished) # connect finished signal of script to finished slot of gui

                # start thread, i.e. script
                script_thread.start()

                self.current_script = script
                self.btn_start_script.setEnabled(False)
                # self.tabWidget.setEnabled(False)

                if isinstance(self.current_script, ScriptIterator):
                    self.btn_skip_subscript.setEnabled(True)


            else:
                self.log('User tried to run a script without one selected.')

        def stop_button():
            """
            stops the current script
            """
            if self.current_script is not None and self.current_script.is_running:
                self.current_script.stop()
            else:
                self.log('User clicked stop, but there isn\'t anything running...this is awkward. Re-enabling start button anyway.')
            self.btn_start_script.setEnabled(True)

        def skip_button():
            """
            Skips to the next script if the current script is a Iterator script
            """
            if self.current_script is not None and self.current_script.is_running and isinstance(self.current_script,
                                                                                                 ScriptIterator):
                self.current_script.skip_next()
            else:
                self.log('User clicked skip, but there isn\'t a iterator script running...this is awkward.')

        def validate_button():
            """
            validates the selected script
            """
            item = self.tree_scripts.currentItem()

            if item is not None:
                script, path_to_script, script_item = item.get_script()
                self.update_script_from_item(script_item)
                script.is_valid()
                script.plot_validate([self.matplotlibwidget_1.figure, self.matplotlibwidget_2.figure])
                self.matplotlibwidget_1.draw()
                self.matplotlibwidget_2.draw()

        def store_script_data():
            """
            updates the internal self.data_sets with selected script and updates tree self.fill_dataset_tree
            """
            item = self.tree_scripts.currentItem()
            if item is not None:
                script, path_to_script, _ = item.get_script()
                script_copy = script.duplicate()
                time_tag = script.start_time.strftime('%y%m%d-%H_%M_%S')

                self.data_sets.update({time_tag : script_copy})

                self.fill_dataset_tree(self.tree_dataset, self.data_sets)

        def save_data():
            """"
            saves the selected script (where is contained in the script itself)
            """
            indecies = self.tree_dataset.selectedIndexes()
            model = indecies[0].model()
            rows = list(set([index.row()for index in indecies]))

            for row in rows:
                time_tag = str(model.itemFromIndex(model.index(row, 0)).text())
                name_tag = str(model.itemFromIndex(model.index(row, 1)).text())
                path = self.gui_settings['data_folder']
                script = self.data_sets[time_tag]
                script.update({'tag' : name_tag, 'path': path})
                script.save_data()
                script.save_image_to_disk()
                script.save_b26()
                script.save_log()

        def delete_data():
            """
            deletes the data from the dataset
            Returns:
            """
            indecies = self.tree_dataset.selectedIndexes()
            model = indecies[0].model()
            rows = list(set([index.row()for index in indecies]))

            for row in rows:
                time_tag = str(model.itemFromIndex(model.index(row, 0)).text())
                del self.data_sets[time_tag]

                model.removeRows(row,1)

        def load_probes():
            """
            opens file dialog to load probes into gui
            """

            # if the probe has never been started it can not be disconnected so we catch that error
            try:
                self.read_probes.updateProgress.disconnect()
                self.read_probes.quit()
                # self.read_probes.stop()
            except RuntimeError:
                pass
            dialog = LoadDialogProbes(probes_old=self.probes, filename=self.gui_settings['probes_folder'])
            if dialog.exec_():
                self.gui_settings['probes_folder'] = str(dialog.txt_probe_log_path.text())
                probes = dialog.get_values()
                added_instruments = list(set(probes.keys()) - set(self.probes.keys()))
                removed_instruments = list(set(self.probes.keys()) - set(probes.keys()))
                # create instances of new probes
                self.probes, loaded_failed, self.instruments = Probe.load_and_append(
                    probe_dict=probes,
                    probes={},
                    instruments=self.instruments)
                if not loaded_failed:
                    print(('WARNING following probes could not be loaded', loaded_failed, len(loaded_failed)))


                # restart the readprobes thread
                del self.read_probes
                self.read_probes = ReadProbes(self.probes)
                self.read_probes.start()
                self.tree_probes.clear() # clear tree because the probe might have changed
                self.read_probes.updateProgress.connect(self.update_probes)
                self.tree_probes.expandAll()

        def load_instruments():
            """
            opens file dialog to load instruments into gui
            """
            if 'instrument_folder' in self.gui_settings:
                dialog = LoadDialog(elements_type="instruments", elements_old=self.instruments,
                                    filename=self.gui_settings['instrument_folder'])

            else:
                dialog = LoadDialog(elements_type="instruments", elements_old=self.instruments)

            if dialog.exec_():
                self.gui_settings['instrument_folder'] = str(dialog.txt_probe_log_path.text())
                instruments = dialog.get_values()
                added_instruments = set(instruments.keys()) - set(self.instruments.keys())
                removed_instruments = set(self.instruments.keys()) - set(instruments.keys())
                # print('added_instruments', {name: instruments[name] for name in added_instruments})

                # create instances of new instruments
                self.instruments, loaded_failed = Instrument.load_and_append(
                    {name: instruments[name] for name in added_instruments}, self.instruments)
                if len(loaded_failed)>0:
                    print(('WARNING following instrument could not be loaded', loaded_failed))
                # delete instances of new instruments/scripts that have been deselected
                for name in removed_instruments:
                    del self.instruments[name]

        def plot_data(sender):
            """
            plots the data of the selected script
            """
            if sender == self.tree_dataset:
                index = self.tree_dataset.selectedIndexes()[0]
                model = index.model()
                time_tag = str(model.itemFromIndex(model.index(index.row(), 0)).text())
                script = self.data_sets[time_tag]
                self.plot_script(script)
            elif sender == self.tree_scripts:
                item = self.tree_scripts.currentItem()
                if item is not None:
                    script, path_to_script, _ = item.get_script()
                # only plot if script has been selected but not if a parameter has been selected
                if path_to_script == []:
                    self.plot_script(script)

        def save():
            self.save_config(self.gui_settings['gui_settings'])
        if sender is self.btn_start_script:
            start_button()
        elif sender is self.btn_stop_script:
            stop_button()
        elif sender is self.btn_skip_subscript:
            skip_button()
        elif sender is self.btn_validate_script:
            validate_button()
        elif sender in (self.tree_dataset, self.tree_scripts):
            plot_data(sender)
        elif sender is self.btn_store_script_data:
            store_script_data()
        elif sender is self.btn_save_data:
            save_data()
        elif sender is self.btn_delete_data:
            delete_data()
        # elif sender is self.btn_plot_probe:
        elif sender is self.chk_probe_plot:
            if self.chk_probe_plot.isChecked():
                item = self.tree_probes.currentItem()
                if item is not None:
                    if item.name in self.probes:
                        #selected item is an instrument not a probe, maybe plot all the probes...
                        self.log('Can\'t plot, No probe selected. Select probe and try again!')
                    else:
                        instrument = item.parent().name
                        self.probe_to_plot = self.probes[instrument][item.name]
                else:
                    self.log('Can\'t plot, No probe selected. Select probe and try again!')
            else:
                self.probe_to_plot = None
        elif sender is self.btn_save_gui:
            # get filename
            filepath, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'Save gui settings to file', self.config_filepath, filter = '*.b26')

            #in case the user cancels during the prompt, check that the filepath is not an empty string
            if filepath:
                filename, file_extension = os.path.splitext(filepath)
                if file_extension != '.b26':
                    filepath = filename + ".b26"
                filepath = os.path.normpath(filepath)
                self.save_config(filepath)
                self.gui_settings['gui_settings'] = filepath
                self.refresh_tree(self.tree_gui_settings, self.gui_settings)
        elif sender is self.btn_load_gui:
            # get filename
            fname = QtWidgets.QFileDialog.getOpenFileName(self, 'Load gui settings from file',  self.gui_settings['data_folder'], filter = '*.b26')
            self.load_config(fname[0])
        elif sender is self.btn_about:
            msg = QtWidgets.QMessageBox()
            msg.setIcon(QtWidgets.QMessageBox.Information)
            msg.setText("pylabcontrol: Laboratory Equipment Control for Scientific Experiments")
            msg.setInformativeText("This software was developed by Arthur Safira, Jan Gieseler, and Aaron Kabcenell at"
                                   "Harvard University. It is licensed under the LPGL licence. For more information,"
                                   "visit the GitHub page at github.com/LISE-B26/pylabcontrol .")
            msg.setWindowTitle("About")
            # msg.setDetailedText("some stuff")
            msg.setStandardButtons(QtWidgets.QMessageBox.Ok)
            # msg.buttonClicked.connect(msgbtn)
            retval = msg.exec_()
        # elif (sender is self.btn_load_instruments) or (sender is self.btn_load_scripts):
        elif sender in (self.btn_load_instruments, self.btn_load_scripts, self.btn_load_probes):
            if sender is self.btn_load_instruments:
                load_instruments()
            elif sender is self.btn_load_scripts:
                self.load_scripts()
            elif sender is self.btn_load_probes:
                load_probes()
            # refresh trees
            self.refresh_tree(self.tree_scripts, self.scripts)
            self.refresh_tree(self.tree_settings, self.instruments)
        elif sender is self.actionSave:
            self.save_config(self.gui_settings['gui_settings'])
        elif sender is self.actionGo_to_pylabcontrol_GitHub_page:
            webbrowser.open('https://github.com/LISE-B26/pylabcontrol')
        elif sender is self.actionExport:
            export_dialog = ExportDialog()
            export_dialog.target_path.setText(self.gui_settings['scripts_folder'])
            if self.gui_settings_hidden['scripts_source_folder']:
                export_dialog.source_path.setText(self.gui_settings_hidden['scripts_source_folder'])
            if export_dialog.source_path.text():
                export_dialog.reset_avaliable(export_dialog.source_path.text())
            #exec_() blocks while export dialog is used, subsequent code will run on dialog closing
            export_dialog.exec_()
            self.gui_settings.update({'scripts_folder': export_dialog.target_path.text()})
            self.fill_treeview(self.tree_gui_settings, self.gui_settings)
            self.gui_settings_hidden.update({'scripts_source_folder': export_dialog.source_path.text()})
slot to which connect buttons