InputDialog with multiple input fields

edited July 2013 in General

Hi, I do

defaultVal = 5
value = RBA::InputDialog.get_int("Input", "Input an integer", defaultVal)

Now I would like to input more than one parameter on the same input dialog - is this possible or do I have to have multiple input dialogs popping up one after the other?

Thanks!

Comments

  • edited November -1

    Hi David,

    that is basically possible, but you'll need to code it in Qt/Ruby. That requires that the Qt binding was enabled upon building KLayout (the binary packages are Qt enabled). Some documentation about the Qt binding can be found here: http://klayout.de/doc/programming/qt_binding.html.

    Regards,

    Matthias

  • edited October 2013

    Matthias,

    I found the way to have also radio buttons (see below), but if I want to add in that input box several variables (text or numbers) input, than I am stacked. See variable below : I don't know how to enter a variable.

    Thank you for your help, Best regards,

    Laurent

    # Run the script with
    #   klayout -rm new_script.rbm ...
    # or put the script as "new_script.rbm" into the installation path (on Unix for version <=0.21:
    # set $KLAYOUTPATH to the installation folder).
    #
    
    include RBA
    
    $new_script = MenuAction.new( "New window", "" ) do 
        app = RBA::Application.instance
        mw = app.main_window
    
        dialog = QDialog::new(Application.instance.main_window)
        dialog.windowTitle = "My Dialog          "
    
        layout = QVBoxLayout::new(dialog)
        dialog.setLayout(layout)
    
        # variable = QInputDialog::getText(dialog, "Enter Name", "User name:", QLineEdit_EchoMode::Normal, "")
        # variable = QLineEdit.new(dialog)
        # variable.text = "\variable\n"
    
        radio1 = QRadioButton.new(dialog)
        layout.addWidget(radio1)
        radio1.text = "Radio 1"
        radio2 = QRadioButton.new(dialog)
        layout.addWidget(radio2)
        radio2.text = "Radio 2"
        radio2.setChecked(true)
        radio3 = QRadioButton.new(dialog)
        layout.addWidget(radio3)
        radio3.text = "Radio 3"
        radio4 = QRadioButton.new(dialog)
        layout.addWidget(radio4)
        radio4.text = "Radio 4"
    
        button1 = QPushButton.new(dialog)
        layout.addWidget(button1)
        button1.text = "Click there"
        button1.clicked do 
            QMessageBox::information(dialog, "Message", "Button there was clicked!")
        end
    
    
        button2 = QPushButton.new(dialog)
        layout.addWidget(button2)
        button2.text = "Click here"
        button2.clicked do 
            radio = 0;
            if (radio1.isChecked()) 
                radio = 1 
            end
            if (radio2.isChecked()) 
                radio = 2 
            end
            if (radio3.isChecked()) 
                radio = 3
            end
            if (radio4.isChecked())
                radio = 4
            end
            QMessageBox::information(dialog, "Message", "Radio #{radio} was clicked!")
        end
    
        dialog.exec
    end
    
    app = RBA::Application.instance
    mw = app.main_window
    
    menu = mw.menu
    menu.insert_separator("tools_menu.end", "name")
    menu.insert_item("tools_menu.end", "new_script", $new_script)
    
  • edited November -1
    Matthias,

    It would also be nice to understand how to use the QComboBox.
    I am confused on where to put the choice list versus the dialog.

    Thanks, Regards,
    Laurent
  • edited October 2013

    Hi Laurent,

    You can use the QComboBox in place of the four QRadioButton objects. So you need just one widget instead of four. The most important methods available for a QComboBox are

    • addItem(string) to add a new item to the combo box
    • currentItem=(index) to select one item (index = 0..n-1)
    • currentItem to get the index of the selected item

    Is that answering your question?

    Matthias

  • edited October 2013

    Fine Matthias,

    Now, I can have a multi-inputs window. I join here a theorical example with:

    • several variables input

    • radio buttons

    • check buttons

    • combo box (list selection input)

    • action push button

    Maybe, there is a better solution for the OK and CANCEL buutons, but I did not find them.

    Save the following script in the same directory as klayout exec file as : multi_input.rbm

    It will appear in tools menu as : Multiple inputs

    Let's try and modify as you need !

    Rgds,

    Laurent

    # Run the script with
    #   klayout -rm multi_input.rbm ...
    # or put the script as "multi_input.rbm" into the installation path (on Unix for version <=0.21:
    # set $KLAYOUTPATH to the installation folder).
    #
    
    include RBA
    
    $multi_input = MenuAction.new( "Multiple inputs", "" ) do 
    
            app = RBA::Application.instance
            mw = app.main_window
            radio = 2
            check = ""
    
            dialog = QDialog.new(Application.instance.main_window)
            dialog.windowTitle = "Dialog miscellaneous inputs"
    
            layout = QVBoxLayout::new(dialog)
            dialog.setLayout(layout)
    
    # variable text input :
            label = QLabel.new(dialog)
            layout.addWidget(label)
            label.text = "1st variable description"
            variable = QLineEdit.new(dialog)
            layout.addWidget(variable)
    
            label = QLabel.new(dialog)
            layout.addWidget(label)
            label.text = "\n2nd variable description"
            variable2 = QLineEdit.new(dialog)
            layout.addWidget(variable2)
            variable2.text = "name 2"
    
    # push button to launch an action
            button1 = QPushButton.new(dialog)
            layout.addWidget(button1)
            button1.text = "Click there"
            button1.clicked do 
                    QMessageBox::information(dialog, "Message", "Button there was clicked!")
            end
    
    # radio buttons
            radio1 = QRadioButton.new(dialog)
            layout.addWidget(radio1)
            radio1.text = "Radio 1"
            radio2 = QRadioButton.new(dialog)
            layout.addWidget(radio2)
            radio2.text = "Radio 2"
            radio2.setChecked(true)
            radio3 = QRadioButton.new(dialog)
            layout.addWidget(radio3)
            radio3.text = "Radio 3"
            radio4 = QRadioButton.new(dialog)
            layout.addWidget(radio4)
            radio4.text = "Radio 4"
    
    # combo box = item selected within a list
            combo = QComboBox.new(dialog)
            combo.addItem("item 1")
            combo.addItem("item 2")
            combo.addItem("item 3")
            layout.addWidget(combo)
    
    # items checked list
            check1 = QCheckBox.new(dialog)
            layout.addWidget(check1)
            check1.text = "check 1"
            check2 = QCheckBox.new(dialog)
            layout.addWidget(check2)
            check2.text = "check 2"
            check3 = QCheckBox.new(dialog)
            layout.addWidget(check3)
            check3.text = "check 3"
    
    # separation line
            label = QLabel.new(dialog)
            layout.addWidget(label)
            label.text = "\n"
    
    # OK button
            buttonOK = QPushButton.new(dialog)
            layout.addWidget(buttonOK)
            buttonOK.text = " OK "
            buttonOK.clicked do 
                    dialog.accept()
            end
    
        dialog.exec
    
    
    # after all those inputs : your programm starts here :
        if (radio1.isChecked()) 
                radio = 1 
        end
        if (radio2.isChecked()) 
                radio = 2 
        end
        if (radio3.isChecked()) 
                radio = 3
        end
        if (radio4.isChecked())
                radio = 4
        end
        if (check1.isChecked()) 
                check = "1"
        end
        if (check2.isChecked()) 
                check = "#{check} 2"
        end
        if (check3.isChecked()) 
                check = "#{check} 3"
        end
        confirm = RBA::MessageBox.info("MULTIPLE INPUTS","Variable 1 : #{variable.text}\nVariable 2 : and #{variable2.text}\nRadio #{radio} was clicked\nCombo #{combo.currentText()} was selected\nCheck buttons #{check} were checked", RBA::MessageBox.b_ok + RBA::MessageBox.b_cancel)
        if confirm == RBA::MessageBox.b_cancel
            raise "Operation aborted"
        end
    
    
    end
    
    app = RBA::Application.instance
    mw = app.main_window
    
    menu = mw.menu
    menu.insert_separator("tools_menu.end", "name")
    menu.insert_item("tools_menu.end", "multi_input", $multi_input)
    
  • edited October 2013

    Hi Laurent,

    your sample is actually fine. In particular the Ok button handling is the way KLayout's Qt binding suggests. You could also bind the conventional Qt signals to slots using QObject#connect, but there is not substantial advantage of one method to another.

    Let met make a few remarks:

    • The whole affair is easier when you use Qt designer files. You will not need to code the dialogs then. Most code is generated by QFormBuilder. The "Qt binding" documentation tells you how.
    • RBA::MessageBox is a relict from times when there was no QMessageBox. I'd recommend to use QMessageBox.

    Regards,

    Matthias

  • edited November -1

    Matthias,

    How to use QDialog with Python ? My macro hangs on :

    dialog = QDialog.new(Application.instance.main_window)
    

    Thanks, Merry Christmas,

    Laurent

  • edited December 2014

    Hi Laurent,

    The correct Python statement is:

    from pya import *
    dialog = QDialog(Application.instance().main_window())
    

    (note the brackets). You don't need "new" - it works too but that is not "pythonic".

    If you want to show the dialog you have to use "exec_" instead of "exec" since that is a reserved word in Python:

    dialog.exec_()
    

    BTW: there is no specific advantage of Python over Ruby. It's just provided to widen the user community since not everybody is familiar with Ruby and there is a somewhat broader choice of libraries for Python. But on the other hand, Python is in general slower than Ruby and still Ruby is my personal favourite.

    Matthias

  • edited March 2015

    Matthias,

    I'm having trouble extending the above example (the ruby example earlier) to a QTreeView.

    In particular I can't tell how to get data back (i.e. get the selected rows) from QTreeView. The difference is, in the previous examples in this thread there was a clearly defined object (like "textbox1") which had a clearly defined method (".text") to get what is inside of it. But in QTreeView there appears to be no such method. There is a .selectedRows(arg) method but it doesn't seem to be for that purpose, as you have to tell it the argument that I actually want to extract!

    include RBA
    dialog = QDialog.new(Application.instance.main_window)
    dialog.windowTitle = "Title"
    layout = QVBoxLayout.new(dialog)
    
    # Set up the QTreeView
    tree = QTreeView.new(dialog)
    layout.addWidget(tree)
    model = QFileSystemModel.new
    tree.setModel(model)
    tree.hideColumn(1);tree.hideColumn(2);tree.hideColumn(3) # Hide all but the first ("Name") column
    model.setNameFilters(['*.rb','*.lym','*.lydrc'])
    selMode = tree.setSelectionMode(QAbstractItemView_SelectionMode::MultiSelection) #QAbstractItemView_SelectionMode::MultiSelection
    
    # OK button and its action
    okButton = QPushButton.new(dialog)
    layout.addWidget(okButton)
    okButton.text = "OK"
    okButton.clicked do
      print model.selectedRows() # Doesn't work; needs an index as the argument -- but how do you get that in the first place? Tried googling but it is not clear.
      dialog.accept
    end
    
    dialog.exec
    

    I know similar functionality to the above can be done using RBA::FileDialog, but the code you see is just a simplified version; I'd like to include more functionality in the future.

    Thanks,

    David

  • edited November -1

    Hi David,

    QTreeView and QFileSystemModel are part of QT's model/view framework. In order to use that you'll have to become familiar with that (see for example http://qt-project.org/doc/qt-4.8/model-view-programming.html.

    I have no experience with QFileSystemModel myself but following the general scheme of the model/view framework, you should be able to get the selected files with a code similar to this

    tree.selectionModel.selectedIndexes.each do |index|
      path = model.filePath(index)
      ...
    end
    

    But I have not tested that myself.

    Best regards,

    Matthias

  • edited March 2015

    Aha!

    Strange thing, and I know why I couldn't find it now.

    Your website documentation does indeed list "selectionModel" under "Public methods" of QTreeView. BUT in the Macro IDE when I click the "?" button and search for QTreeView and scroll down, "selectionModel" is not listed!

    This is strange -- the MacroIDE's docs do include the one just above where it should be ("selectAll") and the one just below where it should be ("setAllColumnsShowFocus") but not the one I was looking for! Very bizarre. In case you don't believe me :-) here is the raw text, pasted from the Macro IDE's "?" function, showing the one above and below it but not "selectionModel" itself:

    [virtual]    void    selectAll                                  Virtual method void QTreeView::selectAll()
    
                 void    setAllColumnsShowFocus    (bool enable)    Method void QTreeView::setAllColumnsShowFocus(bool enable)
    

    I am using KL 0.23.3.

    If I'd found it, I would have found the class QItemSelectionModel and its method selectedIndexes...

    Anyway, no big deal. I should have searched in the online docs, I just didn't realize there might be a difference.

    At first I thought maybe this method is not included in the Qt included with my KL version, which would explain why it's not in the MacroIDE's docs. However it is indeed working as you said, so there are no problems, and "selectionModel" must indeed be listed.

    Here is the code for others' future reference

    include RBA
    dialog = QDialog.new(Application.instance.main_window)
    dialog.windowTitle = "Title"
    layout = QVBoxLayout.new(dialog)
    
    # Set up the QTreeView
    tree = QTreeView.new(dialog)
    layout.addWidget(tree)
    model = QFileSystemModel.new
    tree.setModel(model)
    tree.hideColumn(1);tree.hideColumn(2);tree.hideColumn(3) # Hide all but the first ("Name") column
    model.setNameFilters(['*.rb','*.lym','*.lydrc'])
    selMode = tree.setSelectionMode(QAbstractItemView_SelectionMode::MultiSelection) #QAbstractItemView_SelectionMode::MultiSelection
    
    # OK button and its action
    okButton = QPushButton.new(dialog)
    layout.addWidget(okButton)
    okButton.text = "OK"
    okButton.clicked do
      dialog.accept
    end
    
    dialog.exec
    
    tree.selectionModel.selectedIndexes.each { |i|
      print model.filePath(i) + "\n"
    }
    
  • edited March 2015

    Hi David,

    Oh yes .. the Qt part of the documentation is a mess.

    The reason is that this method is defined by the base class, QAbstractItemView. You'll find it there.

    The Qt documentation was intended as a cross-reference. It's generated automatically from the Qt headers and I did not extract the documentation too (it was difficult enough to parse the signature of the methods ...).

    My reasoning was that people would look in the original Qt documentation and then translate the C++ idea to Ruby/Python. The documentation provided was meant to give hints how to do that translation, not more.

    Matthias

  • edited March 2015

    Ah. Got it.

    No problem, it is easy to look at the Qt docs online anyway. And I should have looked to see what was in the base class (or printed it with "print object.methods").

    Thanks again,

    David

  • Hello,

    I just started to look into the QDialog magic. The last script from Laurent is very interesting. I've got two questions though:

    1) How to add a "Cancel" button, and how to put it on the same line as the "OK" button?
    2) How to add two separated radio button lists (to be able to select one item of each list)?

    Cheers,

    Tomas

  • Hello,

    I dug a bit deeper in the Qt designer and it works all nicely but I still cannot make the cancel button to work (the rest of the script is still run). See the code below. I also attached the .ui file. Any idea how to get it working?

    Here is what I did so far:

    1) Installed https://build-system.fman.io/qt-designer-download: it is very small (only 31Mb) as it only contains the Qt designer.

    2) Watched these tutorials (until the Python stuff):


    3) KLayout script based on https://www.klayout.de/doc-qt5/programming/qt_binding.html:

    Note that I had to remove ".to_i" on line "ui_file.open(QIODevice::ReadOnly.to_i)" to make it work...

    module MyMacro
    
      include RBA
    
    
      ui_file = QFile::new(QFileInfo::new($0).dir.filePath("qt_ui_test.ui"))
      ui_file.open(QIODevice::ReadOnly)
      dialog = QFormBuilder::new.load(ui_file, Application::instance.main_window)
      ui_file.close
    
      dialog.exec
    
    
      if (dialog::radioButton.isChecked()) 
    
          checked_option = "Radio button option 1 is checked..."
    
      end
    
      if (dialog::radioButton_2.isChecked())
    
          checked_option = "Radio button option 2 is checked..."
    
      end 
    
    
          puts "Testing..."
          puts
          puts  "Var1 = " + dialog::lineEdit.text
          puts
          puts  "Var2 = " +  dialog::lineEdit_2.text
          puts
          puts  "Var3 = " +  dialog::lineEdit_4.text
          puts
          puts  "Var4 = " +  dialog::lineEdit_5.text
          puts
          puts checked_option
    
          if dialog::checkBox.isChecked()
    
              puts
              puts "Checkbox is checked..."
    
          end # if
    
    
    end # MyMacro
    

    4) As mentioned before, the "Cancel" button does not have any canceling effect???

    Cheers,

    Tomas

  • edited November 2021

    In order to see the "cancel effect" you have to check the return value of "dialog.exec". It is an integer and equal to 0 if you pressed "Cancel" and 1 if you pressed "Ok".

    And thanks for the note about the "to_i". I'll remove that from the doc.

    Matthias

  • Hi Matthias,

    It works fine now... Many thanks!!!

    Cheers,

    Tomas

Sign In or Register to comment.