datac
datac

Reputation: 39

call different window classes into a main window in PQt5 - python

I have a functional code running 2 procedures and display 2 windows separately. each procedure generates its own window. I would like to choose the procedure to be displayed or have both in a main window. the 2 options are of interest. I tried to define a window where i could call each items but since the generation of the individual windows (Mainwindow_1 and 2) belong to a class already defining a window i don't know how to proceed to display only one window at a time upon clicking the corresponding item.

import logging
log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler())
import sys
import random
import datetime
from datetime import datetime as dt, timedelta
import time
from time import sleep
import pandas as pd
from pymeasure.log import console_log
from pymeasure.display.Qt import QtGui
from PyQt5.QtWidgets import *

# import GUItest


from pymeasure.display.windows import ManagedWindow
from pymeasure.experiment import Procedure, Results
from pymeasure.experiment import IntegerParameter, FloatParameter, Parameter, ListParameter

class RandomProcedure_1(Procedure):

    iterations = IntegerParameter('Loop Iterations', default=10)
    delay = FloatParameter('Delay Time', units='s', default=0.2)
    seed = Parameter('Random Seed', default='10')
    mode = IntegerParameter('Measurement mode : must be 2 or 4 probes', default=2)
    # instruments = ListParameter('procedure to run ', ('RandomProcedure_1', 'RandomProcedure_2'), default='RandomProcedure_1')  # devices under test

    DATA_COLUMNS = ['Mode', 'Iteration', 'Timecode', 'Elapsed', 'Random Number']

    def startup(self):
        log.info("Setting the time of the random number generator")
        random.seed(self.seed)

    def execute(self):
        log.info("Starting the loop of %d iterations" % self.iterations)
        start = datetime.datetime.now()
        for i in range(self.iterations):
            timecode = dt.now()
            elapsed = (datetime.datetime.now() - start).total_seconds()
            data = {
                'Mode': self.mode,
                'Iteration': i,
                'Timecode': timecode,
                'Elapsed': elapsed,
                # 'instruments': self.instruments,
                'Random Number': random.randint(1, 50)
            }
            self.emit('results', data)
            log.debug("Emitting results: %s" % data)
            sleep(self.delay)
            if self.should_stop():
                log.warning("Caught the stop flag in the procedure")
                break

class RandomProcedure_2(Procedure):

    iterations = IntegerParameter('Loop Iterations', default=15)
    delay = FloatParameter('Delay Time', units='s', default=0.1)
    seed = Parameter('Random Seed', default='40')
    mode = IntegerParameter('Measurement mode : must be 2 or 4 probes', default=2)
    # instruments = ListParameter('procedure to run ', ('RandomProcedure_1', 'RandomProcedure_2'), default='RandomProcedure_1')  # devices under test

    DATA_COLUMNS = ['Mode', 'Iteration', 'Timecode', 'Elapsed', 'Random Number']

    def startup(self):
        log.info("Setting the time of the random number generator")
        random.seed(self.seed)

    def execute(self):
        log.info("Starting the loop of %d iterations" % self.iterations)
        start = datetime.datetime.now()
        for i in range(self.iterations):
            timecode = dt.now()
            elapsed = (datetime.datetime.now() - start).total_seconds()
            data = {
                'Mode': self.mode,
                'Iteration': i,
                'Timecode': timecode,
                'Elapsed': elapsed,
                # 'instruments': self.instruments,
                'Random Number': random.randint(1, 100)
            }
            self.emit('results', data)
            log.debug("Emitting results: %s" % data)
            sleep(self.delay)
            if self.should_stop():
                log.warning("Caught the stop flag in the procedure")
                break

class MainWindow_1(ManagedWindow):

    def __init__(self):
            super(MainWindow_1, self).__init__(
                procedure_class=RandomProcedure_1,
                inputs=['mode', 'iterations', 'delay'],
                displays=['mode', 'iterations', 'delay'],
                x_axis='Iteration',
                y_axis='Random Number',
                # sequencer=True,  # Added line
                # sequencer_inputs=['iterations', 'delay', 'seed', 'mode'],  # Added line
                # # inputs_in_scrollarea=True
                # sequence_file="gui_sequencer_example_sequence.txt",  # Added line, optional
            )
            self.setWindowTitle('RandomProcedure_1')
            self.count = 0

    def queue(self, *, procedure=None):
        self.count = self.count + 1
        if procedure is None:
            procedure = self.make_procedure()
        filename = '.\\test\\experiment_1\\' + str(dt.now().strftime("%m%d%Y")) + '_' + 'mode_' + str(self.count) + '.csv'  # working directory
        log.info("Constructing the Results with a data file: %s" % filename)
        results = Results(procedure, filename)
        experiment = self.new_experiment(results)
        self.manager.queue(experiment)

class MainWindow_2(ManagedWindow):

    def __init__(self):

        super(MainWindow_2, self).__init__(
            procedure_class=RandomProcedure_2,
            inputs=['mode', 'iterations', 'delay'],
            displays=['mode', 'iterations', 'delay'],
            x_axis='Iteration',
            y_axis='Random Number',
            # sequencer=True,  # Added line
            # sequencer_inputs=['iterations', 'delay', 'seed', 'mode'],  # Added line
            # # inputs_in_scrollarea=True
            # sequence_file="gui_sequencer_example_sequence.txt",  # Added line, optional
        )
        self.setWindowTitle('RandomProcedure_2')
        self.count = 0

    def queue(self, *, procedure=None):
        self.count = self.count + 1
        if procedure is None:
            procedure = self.make_procedure()
        filename = '.\\test\\experiment_2\\' + str(dt.now().strftime("%m%d%Y")) + '_' + 'mode_' + str(self.count) + '.csv'  # working directory
        log.info("Constructing the Results with a data file: %s" % filename)
        results = Results(procedure, filename)
        experiment = self.new_experiment(results)
        self.manager.queue(experiment)

# in this window i would like to call only one procedure upon choosing the name on the list or have both displayed in one window
# as it is only one window 2 appears and i cannot trigger the queue experiemnts
class Window(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        layout = QGridLayout()
        self.setLayout(layout)
        self.listwidget = QListWidget()
        self.listwidget.insertItem(0, "RandomProcedure_1")
        self.listwidget.clicked.connect(self.MainWindow_1)
        self.listwidget.insertItem(1, "RandomProcedure_2")
        self.listwidget.clicked.connect(self.MainWindow_2)
        layout.addWidget(self.listwidget)
    #
    def MainWindow_1(self):
        window_1 = MainWindow_1()
        window_1.show()
        window_1.exec_()

    def MainWindow_2(self):
        window_1 = MainWindow_2()
        window_1.show()
        window_1.exec_()

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    # window_1 = MainWindow_1()
    # window_2 = MainWindow_2()
    # window_1.show()
    # window_2.show()
    screen = Window()
    screen.show()
    sys.exit(app.exec_())

Upvotes: 1

Views: 426

Answers (2)

Jimit Vaghela
Jimit Vaghela

Reputation: 758

Use void QListWidget::itemClicked(QListWidgetItem *item) The documentation states that :

this signal is emitted with the specified item when a mouse button is clicked on an item in the widget.

And that's what you are expecting specifically from your code. Don't use a two functions on a single method.

Documentation

Upvotes: 1

musicamante
musicamante

Reputation: 48479

The problem is that you connected to the clicked to two functions, so once you click any item the first connected function (MainWindow_1()) is executed and the second will not start until the first is returned (after its exec_ is returned in turn).

You should connect to a single slot and differentiate according to the parameter of the signal. Since you're using a QListWidget, you can use itemClicked(), which returns the QListWidgetItem that has been clicked, then you can run the relative window/procedure accordingly.

class Window(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        layout = QGridLayout()
        self.setLayout(layout)
        self.listwidget = QListWidget()
        self.procedureItem1 = QListWidgetItem('RandomProcedure_1')
        self.listwidget.addItem(self.procedureItem1)
        self.procedureItem1 = QListWidgetItem('RandomProcedure_2')
        self.listwidget.addItem(self.procedureItem2)
        self.listwidget.itemClicked.connect(self.startProcedure)
        layout.addWidget(self.listwidget)

    def startProcedure(self, item):
        if item == self.procedureItem1:
            window = MainWindow_1()
        elif item == self.procedureItem2:
            window = MainWindow_2()
        else:
            return
        window.show()
        window.exec_()

Note: I couldn't actually test the code above with your example, since you didn't provide a minimal, reproducible example, which means that you should always include all required code but trying to keep your example as minimal as possible. In your case, you are using imported classes we know nothing about, but, in any way, they were completely unnecessary for the scope of your question.

Upvotes: 2

Related Questions