• 追加された行はこの色です。
  • 削除された行はこの色です。
---
keywords: [Kotlin, Swing, Java]
description: KotlinでのSwingの使用方法に関するメモなど
author: aterai
pubdate: 2017-05-31
---
#contents

* 概要 [#summary]
`Kotlin`で`Swing`を使用する場合のサンプルです。

* 実行環境 [#s42e991c]
 $ sdk install kotlin
 $ kotlinc -version
 info: Kotlin Compiler version 1.1.2-2
 $ kotlinc hello.kt -include-runtime -d hello.jar && "$JAVA_HOME/bin/java" -jar hello.jar

* Swing + Kotlin サンプル [#swing]
** JTable [#JTable]
- メモ
-- `Class<?>`は`Class<Any>`か`Class<Object>`
-- `Object#getClass()`は`javaClass`
-- オーバーライドの方法、`@Override`は`override`
-- 二次元配列
-- `apply`

#twocolumn
`Java`
#code{{
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;

public class JTableExample {
  public JComponent makeUI() {
    String[] cn = {"String", "Integer", "Boolean"};
    Object[][] data = {
      {"aaa", 12, true}, {"bbb", 5, false},
      {"CCC", 92, true}, {"DDD", 0, false}
    };
    TableModel m = new DefaultTableModel(data, cn) {
      @Override public Class<?> getColumnClass(int col) {
        return getValueAt(0, col).getClass();
      }
    };
    JTable table = new JTable(m);
    table.setAutoCreateRowSorter(true);

    JPanel p = new JPanel(new BorderLayout());
    p.add(new JScrollPane(table));
    return p;
  }
  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      f.add(new JTableExample().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}
}}
#twocolumn
`Kotlin`
#code{{
import java.awt.*
import javax.swing.*
import javax.swing.table.*

fun makeUI(): JComponent {
  val cn = arrayOf("String", "Integer", "Boolean")
  val data = arrayOf(
      arrayOf("aaa", 12, true), arrayOf("bbb", 5, false),
      arrayOf("CCC", 92, true), arrayOf("DDD", 0, false))
  val m = object : DefaultTableModel(data, cn) {
    override fun getColumnClass(col : Int) : Class<Any> {
      return getValueAt(0, col).javaClass
    }
  }
  val table = JTable(m).apply {
    autoCreateRowSorter = true
  }
  return JPanel(BorderLayout(5, 5)).apply {
    setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5))
    add(JScrollPane(table))
  }
}
fun main(args : Array<String>) {
  EventQueue.invokeLater {
    JFrame("kotlin swing").apply {
      defaultCloseOperation = JFrame.EXIT_ON_CLOSE
      add(makeUI())
      size = Dimension(320, 240)
      setLocationRelativeTo(null)
      setVisible(true)
    }
  }
}
}}
#twocolumn

** JTree [#JTree]
#twocolumn
`Java`
#code{{
import java.awt.*;
import java.util.*;
import javax.swing.*;

public class JTreeExample {
  public JComponent makeUI() {
    JTree tree = new JTree();

    JButton b1 = new JButton("expand");
    b1.addActionListener(e -> expandAll(tree));

    JButton b2 = new JButton("collapse");
    b2.addActionListener(e -> collapseAll(tree));

    JPanel pp = new JPanel(new GridLayout(1, 0, 5, 5));
    Arrays.asList(b1, b2).forEach(pp::add);
    JPanel p = new JPanel(new BorderLayout(5, 5));
    p.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    p.add(new JScrollPane(tree));
    p.add(pp, BorderLayout.SOUTH);
    return p;
  }
  protected static void expandAll(JTree tree) {
    int row = 0;
    while (row < tree.getRowCount()) {
      tree.expandRow(row);
      row++;
    }
  }
  protected static void collapseAll(JTree tree) {
    int row = tree.getRowCount() - 1;
    while (row >= 0) {
      tree.collapseRow(row);
      row--;
    }
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      f.add(new JTreeExample().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}
}}
#twocolumn
`Kotlin`
#code{{
import java.awt.*
import javax.swing.*

fun makeUI(): JComponent {
  val tree = JTree()
  val p = JPanel(GridLayout(1, 0, 5, 5)).apply {
    add(JButton("expand").apply {
      addActionListener { expandAll(tree) }
    })
    add(JButton("collapse").apply {
      addActionListener { collapseAll(tree) }
    })
  }
  return JPanel(BorderLayout(5, 5)).apply {
    setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5))
    add(JScrollPane(tree))
    add(p, BorderLayout.SOUTH)
  }
}
fun expandAll(tree : JTree) {
  var row = 0
  while (row < tree.getRowCount()) {
    tree.expandRow(row)
    row++
  }
}
fun collapseAll(tree : JTree) {
  var row = tree.getRowCount() - 1
  while (row >= 0) {
    tree.collapseRow(row)
    row--
  }
}
fun main(args : Array<String>) {
  EventQueue.invokeLater {
    JFrame("kotlin swing").apply {
      defaultCloseOperation = JFrame.EXIT_ON_CLOSE
      add(makeUI())
      size = Dimension(320, 240)
      setLocationRelativeTo(null)
      setVisible(true)
    }
  }
}
}}
#twocolumn

** JCheckBox [#JCheckBox]
- メモ
-- `Smart Cast`、キャスト%%で`if`のネストが深くなるのを避けたいが...%% `apply`で回避

#twocolumn
`Java`
#code{{
import java.awt.*;
import javax.swing.*;

public class JCheckBoxExample {
  public JComponent makeUI() {
    JCheckBox cb = new JCheckBox("Always On Top", true);
    cb.addActionListener(e -> {
      AbstractButton b = (AbstractButton) e.getSource();
      Container c = b.getTopLevelAncestor();
      if (c instanceof Window) {
        ((Window) c).setAlwaysOnTop(b.isSelected());
      }
    });
    JPanel p = new JPanel(new BorderLayout());
    p.add(cb, BorderLayout.NORTH);
    return p;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      f.add(new JCheckBoxExample().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}
}}
#twocolumn
`Kotlin`
#code{{
import java.awt.*
import javax.swing.*

fun makeUI(): JComponent {
  val cb = JCheckBox("Always On Top", true).apply {
    addActionListener {
      val w = getTopLevelAncestor()
      if (w is Window) {
          w.setAlwaysOnTop(isSelected())
      }
    }
//     addActionListener { e ->
//       val c = e.getSource()
//       if (c is AbstractButton) {
//         val w = c.getTopLevelAncestor()
//         if (w is Window) {
//           w.setAlwaysOnTop(c.isSelected())
//         }
//       }
    }
  }
  return JPanel(BorderLayout()).apply {
    add(cb, BorderLayout.NORTH)
  }
}

fun main(args : Array<String>) {
  EventQueue.invokeLater {
    JFrame("kotlin swing").apply {
      defaultCloseOperation = JFrame.EXIT_ON_CLOSE
      add(makeUI())
      size = Dimension(320, 240)
      setLocationRelativeTo(null)
      setVisible(true)
    }
  }
}
}}
#twocolumn

** インターフェイス、匿名内部クラス、throws [#tb58a862]
- メモ
-- `addTreeWillExpandListener(object: TreeWillExpandListener() { ...`と記述すると`error: this class does not have a constructor`とエラーになる
-- インターフェイスから匿名内部クラスのインスタンスを生成する場合は`()`は不要で、`addTreeWillExpandListener(object: TreeWillExpandListener { ...`と記述する

#twocolumn
`Java`
#code{{
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.IconUIResource;
import javax.swing.tree.*;

public class ThrowsExample {
  public JComponent makeUI() {
    JPanel p = new JPanel(new GridLayout(1, 0, 5, 5));
    p.add(new JScrollPane(new JTree()));
    p.add(new JScrollPane(makeTree()));
    p.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    return p;
  }
  private static JTree makeTree() {
    Icon icon = new EmptyIcon();
    UIManager.put("Tree.expandedIcon",  new IconUIResource(icon));
    UIManager.put("Tree.collapsedIcon", new IconUIResource(icon));

    JTree tree = new JTree();
    tree.setEditable(true);
    tree.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
    int row = 0;
    while (row < tree.getRowCount()) {
      tree.expandRow(row++);
    }
    tree.addTreeWillExpandListener(new TreeWillExpandListener() {
      @Override
      public void treeWillExpand(TreeExpansionEvent e)
          throws ExpandVetoException {
        //throw new ExpandVetoException(e, "Tree expansion cancelled");
      }
      @Override
      public void treeWillCollapse(TreeExpansionEvent e)
          throws ExpandVetoException {
        throw new ExpandVetoException(e, "Tree collapse cancelled");
      }
    });
    return tree;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new ThrowsExample().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

class EmptyIcon implements Icon {
  @Override
  public void paintIcon(Component c, Graphics g, int x, int y) {
    /* Empty icon */
  }
  @Override public int getIconWidth() {
    return 0;
  }
  @Override public int getIconHeight() {
    return 0;
  }
}
}}
#twocolumn
`Kotlin`
#code{{
import java.awt.*
import javax.swing.*
import javax.swing.event.*
import javax.swing.plaf.IconUIResource
import javax.swing.tree.*

fun makeUI(): JComponent {
  val emptyIcon = EmptyIcon()
  UIManager.put("Tree.expandedIcon",  IconUIResource(emptyIcon))
  UIManager.put("Tree.collapsedIcon", IconUIResource(emptyIcon))

  val tree = JTree().apply {
    setEditable(true)
    border = BorderFactory.createEmptyBorder(4, 4, 4, 4)
    addTreeWillExpandListener(object: TreeWillExpandListener {
      //@Throws(ExpandVetoException::class)
      override fun treeWillExpand(e: TreeExpansionEvent) {
        //throw ExpandVetoException(e, "Tree expansion cancelled")
      }
      //@Throws(ExpandVetoException::class)
      override fun treeWillCollapse(e: TreeExpansionEvent) {
        throw ExpandVetoException(e, "Tree collapse cancelled")
      }
    })
  }

  var row = 0;
  while (row < tree.getRowCount()) {
    tree.expandRow(row++);
  }

  return JPanel(GridLayout(1, 0)).apply {
    setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5))
    add(JScrollPane(JTree()))
    add(JScrollPane(tree))
  }
}

class EmptyIcon: Icon {
    override fun paintIcon(c: Component, g: Graphics , x: Int, y: Int) {
      /* Empty icon */
    }
    override fun getIconWidth():  Int = 0
    override fun getIconHeight(): Int = 0
}

fun main(args: Array<String>) {
  EventQueue.invokeLater {
    JFrame("kotlin swing").apply {
      defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
      add(makeUI())
      size = Dimension(320, 240)
      setLocationRelativeTo(null)
      setVisible(true)
    }
  }
}
}}
#twocolumn

* コメント [#comment]
#comment
#comment