Question

I'm pretty new to JRuby and Java Swing GUI development. I am trying to get user inputs through a GUI and use it in later parts of the program. I am able to generate the GUI but do not know how to capture the states of the checkboxes or dropdown.

Below is a simplified example. 1. How do I exit out of the GUI but still continue with the program? 2. Is there a way to capture the GUI data only after user selects OK button?

Thank you.

# Menu Title: GUI - Get user input
include Java

import java.awt.event.ActionListener
import javax.swing.JButton
import javax.swing.JCheckBox
import javax.swing.JFrame
import javax.swing.JPanel
import javax.swing.JLabel
import javax.swing.JComboBox
import javax.swing.JDialog

class Example < JFrame

    def initialize
    # header title
        super("Test Settings")

        self.initUI
    end

    def initUI
       # define components
       panel = JPanel.new
       panel.setLayout(nil)
       self.getContentPane.add(panel)

       cb_itemA     = JCheckBox.new("Check item A", true)
       cb_itemB     = JCheckBox.new("Check item B", false)

       lbl_dropdown     = JLabel.new("Traversal: ")
       jCombo_dropdown  = JComboBox.new()
       jCombo_dropdown.addItem("Choice 1")
       jCombo_dropdown.addItem("Choice 2")
       jCombo_dropdown.setSelectedIndex(1)  # default choice is #2

       okButton = JButton.new("OK")
       cancelButton = JButton.new("Cancel")

       # hard-code positions
       cb_itemA.setBounds(10, 10, 150, 20)
       cb_itemB.setBounds(10, 30, 150, 20)
       lbl_dropdown.setBounds(10, 50, 150, 20)
       jCombo_dropdown.setBounds(10, 70, 150, 20)

       okButton.setBounds(10, 110, 80, 25 )
       cancelButton.setBounds(100, 110, 80, 25)

       panel.add(cb_itemA);         panel.add(cb_itemB)
       panel.add(lbl_dropdown); panel.add(jCombo_dropdown)
       panel.add(okButton);     panel.add(cancelButton)

       # == ACTION LISTENERS ==
       actionTaken = ClickAction.new()

       cb_itemA.addActionListener(actionTaken)
       cb_itemB.addActionListener(actionTaken)
       jCombo_dropdown.addActionListener(actionTaken)   
       okButton.addActionListener(actionTaken)  # proceed to next code
       cancelButton.addActionListener( actionTaken )    # exit script

       # == WINDOW SETTINGS ==
       win_width  = 200
       win_height = 180
       self.setSize(win_width, win_height)
       self.setLocationRelativeTo(nil)
       self.setVisible(true)
       self.setDefaultCloseOperation(JFrame::DISPOSE_ON_CLOSE)
    end

    # centralized action handler
    class ClickAction
      include java.awt.event.ActionListener

      def actionPerformed(evt)

         if evt.getActionCommand() == "Check item A"
            javax.swing.JOptionPane.showMessageDialog(nil, "item A checked")
         elsif evt.getActionCommand() == "Check item B"
            javax.swing.JOptionPane.showMessageDialog(nil, "item B checked")
         elsif evt.getActionCommand() == "Cancel"
            # how to exit GUI from here?
         elsif evt.getActionCommand() == "OK"
            # how to exit GUI from here?
         end
      end
    end
end

# --------------

Example.new

# <use user input selection here>
Was it helpful?

Solution

I'm thinking you really want to use a JDialog to gather input so it blocks further execution of your program. The following will take collect input, then you grab the data. While not necessary, I prefer splitting the data from the model it's not exactly MVC or MVP, but you get the idea.

include Java

import java.awt.event.ActionListener
import javax.swing.JButton
import javax.swing.JCheckBox
import javax.swing.JFrame
import javax.swing.JPanel
import javax.swing.JLabel
import javax.swing.JComboBox
import javax.swing.JDialog

class View < JDialog
  attr_accessor :presenter

  def initialize
    @frame = JFrame.new
    super @frame, true
    initUI
  end

  def initUI
     # define components
     setLayout(nil)

     @cb_itemA     = JCheckBox.new("Check item A", true)
     @cb_itemB     = JCheckBox.new("Check item B", false)

     lbl_dropdown     = JLabel.new("Traversal: ")
     @jCombo_dropdown  = JComboBox.new()
     @jCombo_dropdown.addItem("Choice 1")
     @jCombo_dropdown.addItem("Choice 2")
     @jCombo_dropdown.setSelectedIndex(1)  # default choice is #2

     okButton = JButton.new("OK")
     cancelButton = JButton.new("Cancel")

     # hard-code positions
     @cb_itemA.setBounds(10, 10, 150, 20)
     @cb_itemB.setBounds(10, 30, 150, 20)
     lbl_dropdown.setBounds(10, 50, 150, 20)
     @jCombo_dropdown.setBounds(10, 70, 150, 20)

     okButton.setBounds(10, 110, 80, 25 )
     cancelButton.setBounds(100, 110, 80, 25)

     add(@cb_itemA)         
     add(@cb_itemB)
     add(lbl_dropdown)
     add(@jCombo_dropdown)
     add(okButton)
     add(cancelButton)

     # == ACTION LISTENERS ==
     @cb_itemA.addActionListener do |e|
       @presenter.check_item_a item_a 
     end

     @cb_itemB.addActionListener do |e|
       @presenter.check_item_b item_b 
     end

     @jCombo_dropdown.addActionListener do |e|
       @presenter.combo_box_selected combo 
     end

     okButton.addActionListener do |e|
       @presenter.ok
     end

     cancelButton.addActionListener do |e|
       @presenter.cancel
     end

     # == WINDOW SETTINGS ==
     win_width  = 200
     win_height = 180
     self.setSize(win_width, win_height)
     self.setLocationRelativeTo(nil)
     self.setDefaultCloseOperation(JFrame::DISPOSE_ON_CLOSE)
  end

  def item_a
    @cb_itemA.selected?
  end

  def item_b
    @cb_itemB.selected?
  end

  def combo
    @jCombo_dropdown.selected_item.to_s
  end

  def close
    set_visible(false)
    @frame.dispose
    dispose
  end
end

class Presenter
  attr_accessor :data

  def initialize(view)
    # set view to presenter and vice versa
    @view = view
    @view.presenter = self

    #get initial state, it would be better to set the state of view from
    # the data and not the other way around
    @data = {:item_a => @view.item_a,
             :item_b => @view.item_b,
             :combo =>  @view.combo}
  end

  def show_view
    @view.show
  end

  def close_view
    @view.close
  end

  def check_item_a selected
    puts "checked item a"
    @data[:item_a] = selected 
  end


  def check_item_b selected
    puts "checked item b"
    @data[:item_b] = selected 
  end

  def combo_box_selected selected
    puts "combo box selected"
    @data[:combo] = selected 
  end

  def cancel
    puts "canceled"
    @view.close
  end

  def ok
    puts "ok"
    @view.close
  end
end


>> view = View.new
>> presenter = Presenter.new(view)
>> presenter.show_view     #gui gets displayed to user
checked item b
ok
=> nil
>> presenter.data
=> {:item_a=>true, :item_b=>true, :combo=>"Choice 2"}
>> 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top