Creating multiple tabs inside of a preset layout and keeping data within them. -- PyQT5 within KLayout API

87 Views Asked by At

I am attempting to generate output information in a tabbed layout using PyQT5. In the case that I have multiple devices, I would expect multiple tabs to show up in the output with information corresponding to their respective device.

Image of my current output

For some reason, I am getting a single tab, and a single button. Basically like the information is getting written over. The issue is that I do not know how to dynamically add new tabs and hold on to all of the information inside them properly upon each iteration. I will not know the number of devices or device parameters ahead of time, so I can not set this information in code. It must be dynamic.

Here is my current code:

# $description: Testing
# $show-in-menu

import pya
import json
import re, sys
from pe import generateDeviceParameters
from datetime import datetime
import os
import subprocess, os, platform
import functools

class CommandWindow( pya.QPlainTextEdit ):
    def __init__( self, parent ):
        super( CommandWindow, self ).__init__( parent )
        self.setPlaceholderText( "Command Window" )
        self.setReadOnly( True )
    
    def log( self, text ):
        now = datetime.now()
        current_time = now.strftime("%H:%M:%S")
        self.insertPlainText(f"{current_time}: {text}\n")
        self.repaint()
        
class CommandWindowButton( pya.QPushButton ):
    def __init__( self, parent ):
       super( CommandWindowButton, self ).__init__( parent )
       self.app = parent
       self.text = "Clear Command Window"
       
    def clearText( self ):
        self.app.commandWindow.setPlainText( "" )

class MyApp( pya.QDialog ):
  def __init__( self, parent ):
    super( MyApp, self ).__init__( parent )
    
    # Change title
    self.windowTitle = 'Automated Parameter Extraction'
    self.resize( 1250, 500 )
    
    # Set application font
    self.font = pya.QFont("Arial", 10)
    self.setFont(self.font)
    
    # Create a vertical layout for the main widget
    self.layout = pya.QGridLayout()
    self.setLayout(self.layout)

    # Create the first panel
    self.first_panel = pya.QWidget()
    self.first_layout = pya.QVBoxLayout()
    self.first_panel.setLayout(self.first_layout)

    # Create and connect the combo box to switch between pages
    self.deviceCombo = pya.QComboBox()
    self.deviceCombo.addItems( ["Multiple Devices (Config File)"] )
    self.deviceCombo.activated = self.switchPage
    self.first_layout.addWidget( self.deviceCombo )

    # Create the inputs related to a single device
    self.createPages()
    self.first_layout.addWidget( self.deviceGroupBox )
    
    # Create command window
    self.commandWindow = CommandWindow( self )
    self.first_layout.addWidget( self.commandWindow )
    self.cwClearButton = CommandWindowButton( self )
    self.cwClearButton.clicked = self.cwClearButton.clearText
    self.first_layout.addWidget( self.cwClearButton )
    
    # Add first panel to the main layout
    self.layout.addWidget(self.first_panel, 0, 0, 1, 1)
    
    # Create the second panel (scroll layout)
    self.second_panel = pya.QWidget()
    self.second_layout = pya.QVBoxLayout()
    self.second_panel.setLayout( self.second_layout )

    # Create a scroll area
    self.scroll_area = pya.QScrollArea()
    self.scroll_widget = pya.QWidget()
    self.scroll_layout = pya.QVBoxLayout()
    self.scroll_widget.setLayout( self.scroll_layout )
    self.scroll_area.setWidgetResizable(True)
    self.scroll_area.setWidget( self.scroll_widget )

    # Add scroll area to the second layout
    self.second_layout.addWidget( self.scroll_area )

    # Analysis button
    self.ok = pya.QPushButton( "Run Extraction" )
    self.ok.clicked = self.runPE
    self.second_layout.addWidget( self.ok )
    
    # Add second panel to the main layout
    self.layout.addWidget(self.second_panel, 0, 1, 1, 1)

  def createPages( self ):
  
    # Initialize
    self.deviceGroupBox = pya.QGroupBox( 'Extraction Information' )
    self.stackedLayout = pya.QStackedLayout()
    self.deviceGroupBox.setLayout( self.stackedLayout )
    
    self.page1 = pya.QWidget()
    self.page1_layout = pya.QGridLayout()
    
    self.edit1_pane = pya.QWidget()
    self.edit1_layout = pya.QVBoxLayout()
    self.edit1_pane.setLayout( self.edit1_layout )
    
    self.button1_pane = pya.QWidget()
    self.button1_layout = pya.QVBoxLayout()
    self.button1_pane.setLayout( self.button1_layout )
    
    # Create output location edit field
    self.outputLocation = pya.QLineEdit( self )
    self.button1 = pya.QPushButton()
    self.edit1_layout.addWidget( self.outputLocation )
    self.button1_layout.addWidget( self.button1 )
    
    # Create top cell choice edit field
    self.topCell = pya.QLineEdit( self )
    self.button2 = pya.QPushButton()
    self.edit1_layout.addWidget( self.topCell )
    self.button1_layout.addWidget( self.button2 )
    
    # Create unit cell choice edit field
    self.unitCell = pya.QLineEdit( self )
    self.button3 = pya.QPushButton()
    self.edit1_layout.addWidget( self.unitCell )
    self.button1_layout.addWidget( self.button3 )
    
    # Create edge cell choice edit field
    self.edgeCell = pya.QLineEdit( self )
    self.button4 = pya.QPushButton()
    self.edit1_layout.addWidget( self.edgeCell )
    self.button1_layout.addWidget( self.button4 )
    
    # Reformat
    self.page1_layout.addWidget( self.edit1_pane, 0, 0, 1, 1 )
    self.page1_layout.addWidget( self.button1_pane, 0, 1, 1, 1 )
    
    self.page1.setLayout( self.page1_layout )
    self.stackedLayout.addWidget( self.page1 )
    
    # Initialize
    self.page2 = pya.QWidget()
    self.page2_layout = pya.QGridLayout()
    
    self.edit2_pane = pya.QWidget()
    self.edit2_layout = pya.QVBoxLayout()
    self.edit2_pane.setLayout( self.edit2_layout )
    
    self.button2_pane = pya.QWidget()
    self.button2_layout = pya.QVBoxLayout()
    self.button2_pane.setLayout( self.button2_layout )
    
    # Create input files location edit field
    self.inFiles = pya.QLineEdit( self )
    self.button5 = pya.QPushButton()
    self.edit2_layout.addWidget( self.inFiles )
    self.button2_layout.addWidget( self.button5 )
    
    # Create config file location edit field
    self.configFile = pya.QLineEdit( self )
    self.button6 = pya.QPushButton()
    self.edit2_layout.addWidget( self.configFile )
    self.button2_layout.addWidget( self.button6 )
    
    # Reformat
    self.page2_layout.addWidget( self.edit2_pane, 0, 0, 1, 1 )
    self.page2_layout.addWidget( self.button2_pane, 0, 1, 1, 1 )
    
    self.page2.setLayout( self.page2_layout )
    self.stackedLayout.addWidget( self.page2 )
    
  def switchPage( self ):
    self.stackedLayout.setCurrentIndex(self.deviceCombo.currentIndex)
    
  def runPE( self ):
    self.multipleDevice()
    
  def multipleDevice( self ):
    
    # Create tab widget within croll layout
    self.tab_widget = pya.QTabWidget()
    self.scroll_layout.addWidget( self.tab_widget )
    tab = []
    tab_layout = []
    
    data_for_tabs = dict()
    data_for_tabs["Device1"] = dict()
    data_for_tabs["Device1"]["Parameter1"] = dict()
    data_for_tabs["Device1"]["Parameter1"]["x"] = 1.2
    data_for_tabs["Device1"]["Parameter1"]["y"] = 1.5
    data_for_tabs["Device1"]["Parameter2"] = dict()
    data_for_tabs["Device1"]["Parameter2"]["x"] = 1.4
    data_for_tabs["Device1"]["Parameter2"]["y"] = 1.3
    
    data_for_tabs["Device2"] = dict()
    data_for_tabs["Device2"]["Parameter1"] = dict()
    data_for_tabs["Device2"]["Parameter1"]["x"] = 2.2
    data_for_tabs["Device2"]["Parameter1"]["y"] = 2.5
    data_for_tabs["Device2"]["Parameter2"] = dict()
    data_for_tabs["Device2"]["Parameter2"]["x"] = 2.4
    data_for_tabs["Device2"]["Parameter2"]["y"] = 2.3

    # First generate tabs
    tabNumber = 0
    for key in data_for_tabs.keys():
        
        # Create tab
        tab.append( pya.QWidget() )
        tab_layout.append( pya.QVBoxLayout() )
        tab[tabNumber].setLayout( tab_layout[tabNumber] )
        self.tab_widget.addTab( tab[tabNumber], key )
        self.tab = tab[tabNumber]
        self.tab_layout = tab_layout[tabNumber]
        
        self.runExtraction( data_for_tabs[key], self.tab, self.tab_layout )
        tabNumber += 1
        
  def runExtraction( self, data, tab, tab_layout ):
    row = 0
    for key, value in data.items():
        outGroupBox = pya.QGroupBox( key )
        self.out_layout = pya.QHBoxLayout()
        for pkey, pval in value.items():
            txtlbl = pya.QLabel( tab )
            txtlbl.setText(f"{pkey} = ")
            txt = pya.QLineEdit( tab )
            txt.setText(f"{pval}")
            txt.setReadOnly( True )
            
            self.out_layout.addWidget( txtlbl )
            self.out_layout.addWidget( txt )
            
        self.button = pya.QPushButton()
        self.button.text = f"{key}"
        self.out_layout.addWidget( self.button )
        
        # Reformat
        outGroupBox.setLayout( self.out_layout )
        outGroupBox.update()
        setattr( self, "outGroupBox" + str(row), outGroupBox )
        tab_layout.addWidget( getattr( self, "outGroupBox" + str(row) ) )
        row += 1
        
    # Add stretch so everything sits at the top
    tab_layout.addStretch()
        
  
# Create the app instance and run the event loop
peDialog = MyApp( pya.Application.instance().main_window() )
peDialog.show()

Please feel free to leave comments or provide any help. My guess is that I will need to create some sort of class for the tabbed layout, but I am not sure.

I have tried using a variation of setattr and getattr in order to dynamically create tab widgets and layouts for each tab and device parameter. For some reason this causes the app to not see anything however.

I am hoping to see multiple tabs with their respective device. And then each tab should have the information given from that device.

0

There are 0 best solutions below