2016-03-31

Fedora 24 アルファ版へアップグレード

3 月 29 日に Fedora 24 の Alpha 版が公開されました [1]。Live CD 用のインストーラが参考サイト [2] からダウンロードできますが、ここでは dnf のプラグイン、dfn-plugin-system-upgrade を使ってシステムアップグレードをしました [3]。こういった人柱的なアップグレードには失敗がつきものですので、万が一失敗してもいいように、先日 Fedora 23 をインストールしたばかりの格安ノート PC、HP Stream 11 を使いました [4]

Fedora 23 から 24(アルファ版)へのアップグレードの手順は以下のとおりです。sudo を使っていないので、su で root にログインしています。

$ su
パスワード:
# dnf update --refresh

# dnf install dnf-plugin-system-upgrade

# dnf system-upgrade download --releasever=24

# dnf system-upgrade reboot

一時間ちょっとでアップグレードが無事終わりました。Fedora 24 の特徴については、別の記事にまとめます。

参考サイト

  1. Releases/24/Schedule - FedoraProject
  2. Download Fedora Workstation Alpha
  3. DNF system upgrade - FedoraProject
  4. bitWalk's: HP Stream 11 に Fedora 23 をインストール (2016-03-27)

 

ブログランキング・にほんブログ村へ
にほんブログ村

2016-03-27

HP Stream 11 に Fedora 23 をインストール

HP Stream 11 に Fedora 23 をインストールしました。

Stream 11 は、CPU が 64bit Celeron、RAM 2GB そしてストレージ容量は eMMC 32GB と非力なノート PC ですが、バッテリー駆動時間が 10.5 時間というのは魅力です [1]。インターネットで調べてみると、Ubuntu などのインストール例がいくつも報告されていますので、Fedora でも大丈夫だろうと思い、ちょっと高いおもちゃを買ってしまいました。

今回、Amazon.jp から購入したのは以下の通りです。ポイントや割引を使って、総額は 32,157 円になりました。

HP Stream 11-r016TU28,980 円
Transcend microSDXCカード 64GB Class102,280 円
Tonor Bluetooth 3.0 ワイヤレス マウス2,180 円

プリインストールされている Windows 10 は使うつもりがないので、デュアルブートや万一のために Windows をバックアップする方策は講じていません。

Fedora のインストールイメージは、Rufus を利用して USB メモリに焼いて用意しておきます。

PCの起動時に、f10 キーを押して BIOS 設定画面に入れるように、Windows 上のコントロールパネルの「電源オプション」で「電源ボタンの動作を選択する」→「現在利用可能でない設定を変更します」→「高速スタートアップを有効にする」のチェックを外して保存します。

BIOS 設定画面ではセキュアブートの無効化およびレガシー サポートの有効化を行い、ブート メニューを使用して USB デバイスを最初のブートデバイスに設定します [2]

なお、USB メモリに燒いた Fedora インストーラが起動するまで、かなり時間がかかりました。

Fedora をインストールする際、ストレージには内蔵の 32GB eMMC と、MicroSD カードスロットに挿した 64GB の microSDXC カードの 2 つを指定して、パーティションは自動で設定しました。インストール後に確認したところ、ロジカルボリュームをうまく使って、ブート領域と、スワップ (~4GB)、システム領域 (50GB) とユーザー領域 (35GB) が確保されていました。

下記は、GNOME 端末上で確認した結果です。くれぐれも、PC の使用中に誤ってカードスロットに触れて MicroSD カードがイジェクトされてしまわないように気をつけなければなりません。

$ df -h
ファイルシス            サイズ  使用  残り 使用% マウント位置
devtmpfs                  936M     0  936M    0% /dev
tmpfs                     947M   64M  883M    7% /dev/shm
tmpfs                     947M  1.5M  945M    1% /run
tmpfs                     947M     0  947M    0% /sys/fs/cgroup
/dev/mapper/fedora-root    50G  5.0G   42G   11% /
tmpfs                     947M  108K  947M    1% /tmp
/dev/mmcblk0p2            477M  122M  326M   28% /boot
/dev/mmcblk0p1            200M  8.4M  192M    5% /boot/efi
/dev/mapper/fedora-home    35G  550M   32G    2% /home
tmpfs                     190M   12K  190M    1% /run/user/42
tmpfs                     190M   48K  190M    1% /run/user/1000
$ swapon -s
ファイル名    タイプ  サイズ 使用済み 優先順位
/dev/dm-1                               partition 3932156 992236 -1
$ 

無線ネットワークは問題なく繋がりました。Bluetooth のワイヤレスマウスも、最初はやり方が判らず戸惑いましたが、問題なく認識(ペアリング)されました。しばらく使ってみて特記することがあればレポートします。さしあたって、まもなくアルファ/ベータリリースされる Fedora 24 を試してみようと思います [3]

このところ、Linux のインストールがずいぶんと簡単になったばかりか、低価格帯のノート PC にも、比較的簡単にインストールできるようになりました。少ないリソースですが、HDD のように普段鞄に入れて持ち運ぶと劣化を心配しなければならないパーツがありません。どこまで使えるのか、とことん使い潰してみたいと思います。

参考サイト

  1. Stream 11-r000 製品詳細・スペック - ノートパソコン・PC通販 | 日本HP
  2. HP PC - コンピューターをブート可能 CD または DVD から起動できない (Windows 8) | HP® Customer Support
  3. Releases/24/Schedule - FedoraProject
  4. 3~5万円で買える安いノートパソコンおすすめ機種【2016年版】 – こまめブログ
  5. 新型HP Stream 11-r000辛口レビュー(外観編)本体デザインやキーボードの使い勝手を検証! – こまめブログ

 

ブログランキング・にほんブログ村へ
にほんブログ村

2016-03-25

Javaのアップデート公開、リモートコード実行の脆弱性に対処 - ITmedia エンタープライズ

Java のセキュリティアップデートとなる Java SE JDK/JRE 8 Update 77 が米国時間 3 月23 日にリリースされ、深刻な脆弱性が解決されました。 更新版を可能な限り早く適用することを強く推奨されています。なお、定例セキュリティアップデートの公開は、米国時間の 4 月 19 日に予定されています。

 

ブログランキング・にほんブログ村へ
にほんブログ村

2016-03-24

Google Developers Japan: V8 で WebAssembly を試験運用開始

Google の開発者向けのブログに WebAssembly の話題が出ていました。実は参考サイト [1] のニュースを先週読んだ時にブログで紹介しようと思ったのですが、残念なことに Google Chrome Canary [2] が Linux に対応していなかったので諦めてしまっていました。しかし、Chromium [3] をコンパイルすれば Linux でも WebAssembly を体験できそうだと考え、備忘録として書き留めておくことにします。

ところで WebAssembly とは何かということですが、もちろん上記記事で触れられていますが、Mozilla Japan のブログでも説明されています(参考サイト [4])。そう、WebAssembly は Google Chrome だけではなく、どの WebAssembly はオープンソースプロジェクトで開発されており、Web ブラウザでも実行可能なポータビリティを目指す、低レベルでポータブルなバイトコードなのです。当然、Microsoft Edge についても WebAssembly へのサポートが発表されています(参考サイト [5])。

なお、このプロジェクトが本格的に始まったのは、昨年の 6 月まで遡ります(参考サイト [6])。

JavaScript を補完してウェブを高速化する WebAssembly を Linux 上でも体験してみるため、しばらく Chromium のビルドに取り組んでみようと思います。

参考サイト

  1. JavaScriptを補完してウェブを高速化する「WebAssembly」をChromeがついに実装したので実行速度を試してみた - GIGAZINE (2016/03/16)
  2. Google Chrome Canary Buildとは 「Google Chrome Canary」 グーグルクロームカナリビルド: - IT用語辞典バイナリ
  3. Chromium - Wikipedia
  4. WebAssembly が 1 つのマイルストーンを達成しました: 複数ブラウザによる実験的なサポートがはじまりました | Mozilla Japan ブログ (2016/03/16)
  5. Microsoft Edge、WebAssemblyサポートでゲーム強化 | マイナビニュース (2016/03/16)
  6. 主要ブラウザで実行可能なバイナリ形式「WebAssembly」の開発がスタート。Chrome、WebKit、Firefox、Microsoft Edge、LLVM、Unityらがサポートを相次いで表明 - Publickey (2015/06/19)

 

ブログランキング・にほんブログ村へ
にほんブログ村

2016-03-21

JavaFX: LineChart を使いこなそう (6) - ズーム(改)

JavaFX のラインチャートをズームするサンプルを、以前の記事 [1] で紹介しましたが、コードを整理し、ズームおよび解除をプッシュボタン無しにできるように変更してみました。すなわち、マウス左ボタンを押しながらチャート上で左上から右下までドラッグしてマウスの左ボタンを離したときにズームを実行し、それ以外のドラッグをした場合、例えば、右上から左下まで左ボタンを押しながらドラッグするとズームが解除されるようにしました。

動作環境は次の通りです。

  • OS: Fedora 23 x86_64
  • jdk1.8.0_74-1.8.0_74-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.1

まずは、ズームの機能を担う ZoomableLayer クラスです。このクラスのインスタンスを生成して、LineChart のインスタンスの上に、StackPane クラスで重ねて使用します。

リスト:ZoomableLayer.java 
package zoomablelayer;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Point2D;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;

public class ZoomableLayer extends Rectangle {

    LineChart chart;
    double xLower, xUpper, yLower, yUpper;

    public ZoomableLayer(LineChart chart) {
        this.chart = chart;
        initZoom();
        setManaged(false);
        setFill(Color.LIGHTSEAGREEN.deriveColor(0, 1, 1, 0.5));
        setUpZooming();
    }

    private void initZoom() {
        NumberAxis xAxis = (NumberAxis) chart.getXAxis();
        xLower = xAxis.getLowerBound();
        xUpper = xAxis.getUpperBound();
        NumberAxis yAxis = (NumberAxis) chart.getYAxis();
        yLower = yAxis.getLowerBound();
        yUpper = yAxis.getUpperBound();
    }

    private void setUpZooming() {
        final ObjectProperty<Point2D> mouseAnchor = new SimpleObjectProperty<>();

        chart.setOnMousePressed((MouseEvent event) -> {
            mouseAnchor.set(new Point2D(event.getX(), event.getY()));
            setWidth(0);
            setHeight(0);
        });

        chart.setOnMouseDragged((MouseEvent event) -> {
            double x = event.getX();
            double y = event.getY();
            setX(Math.min(x, mouseAnchor.get().getX()));
            setY(Math.min(y, mouseAnchor.get().getY()));
            setWidth(x - mouseAnchor.get().getX());
            setHeight(y - mouseAnchor.get().getY());
        });

        chart.setOnMouseReleased((MouseEvent event) -> {
            if ((getWidth() > 0) && (getHeight() > 0)) {
                doZoom();
            } else {
                releaseZoom();
            }
        });
    }

    private void doZoom() {
        Point2D zoomTopLeft = new Point2D(getX(), getY());
        Point2D zoomBottomRight = new Point2D(getX() + getWidth(), getY() + getHeight());

        final NumberAxis yAxis = (NumberAxis) chart.getYAxis();
        Point2D yAxisInScene = yAxis.localToScene(0, 0);
        final NumberAxis xAxis = (NumberAxis) chart.getXAxis();
        Point2D xAxisInScene = xAxis.localToScene(0, 0);

        double xOffset = zoomTopLeft.getX() - yAxisInScene.getX();
        double yOffset = zoomBottomRight.getY() - xAxisInScene.getY();
        double xAxisScale = xAxis.getScale();
        double yAxisScale = yAxis.getScale();

        xAxis.setLowerBound(xAxis.getLowerBound() + xOffset / xAxisScale);
        xAxis.setUpperBound(xAxis.getLowerBound() + getWidth() / xAxisScale);
        yAxis.setLowerBound(yAxis.getLowerBound() + yOffset / yAxisScale);
        yAxis.setUpperBound(yAxis.getLowerBound() - getHeight() / yAxisScale);

        System.out.println(yAxis.getLowerBound() + " " + yAxis.getUpperBound());

        setWidth(0);
        setHeight(0);
    }

    private void releaseZoom() {
        NumberAxis xAxis = (NumberAxis) chart.getXAxis();
        xAxis.setLowerBound(xLower);
        xAxis.setUpperBound(xUpper);
        NumberAxis yAxis = (NumberAxis) chart.getYAxis();
        yAxis.setLowerBound(yLower);
        yAxis.setUpperBound(yUpper);

        setWidth(0);
        setHeight(0);
    }
}

LineChart と ZoomableLayer クラスのインスタンスを StackPane で重ねて表示するサンプルです。

リスト:SampleLineChart.java 
package zoomablelayer;

import java.util.Collections;
import java.util.Random;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class SampleLineChart extends Application {

    private static final int NUM_DATA_POINTS = 1000;

    @Override
    public void start(Stage primaryStage) {
        StackPane chartContainer = new StackPane();

        LineChart<Number, Number> chart = createChart();
        chartContainer.getChildren().add(chart);

        ZoomableLayer zoomRect = new ZoomableLayer(chart);
        chartContainer.getChildren().add(zoomRect);

        Scene scene = new Scene(chartContainer, 600, 400);
        primaryStage.setTitle(getClass().getSimpleName());
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private LineChart<Number, Number> createChart() {
        final NumberAxis xAxis = createAxis();
        final NumberAxis yAxis = createAxis();
        LineChart<Number, Number> chart = new LineChart<>(xAxis, yAxis);
        chart.setAnimated(false);
        chart.setCreateSymbols(false);
        chart.setData(generateChartData());
        return chart;
    }

    private NumberAxis createAxis() {
        final NumberAxis xAxis = new NumberAxis();
        xAxis.setAutoRanging(false);
        xAxis.setLowerBound(0);
        xAxis.setUpperBound(1000);
        return xAxis;
    }

    private ObservableList<Series<Number, Number>> generateChartData() {
        final Series<Number, Number> series = new Series<>();
        series.setName("Data");
        final Random rng = new Random();
        for (int i = 0; i < NUM_DATA_POINTS; i++) {
            Data<Number, Number> dataPoint = new Data<>(i, rng.nextInt(1000));
            series.getData().add(dataPoint);
        }
        return FXCollections.observableArrayList(Collections.singleton(series));
    }

    public static void main(String[] args) {
        launch(args);
    }
}

実行例を以下に示します。

LineChart を拡張したクラスにズーム機能を入れ込んだ方が簡単で良いのですが、現状の方法をそのまま使うのではなく、もっとスマートにズーム機能を追加できる方法がないか検討中です。

参考サイト

  1. bitWalk's: JavaFX: LineChart を使いこなそう (4) - ズーム
  2. Example of a LineChart that can be zoomed via mouse. · GitHub

 

ブログランキング・にほんブログ村へ
にほんブログ村

2016-03-19

JavaFX: LineChart を使いこなそう (5) - 縦線・横線

JavaFX のラインチャートを使っていると、チャート内に縦線あるいは横線の固定線を描画したい場合があります。例えば、目標値を強調する場合や、管理範囲を表示したい場合などです。参考サイト [1] にぴったりの例がありましたので紹介します。

動作環境は次の通りです。

  • OS: Fedora 23 x86_64
  • jdk1.8.0_74-1.8.0_74-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.1

まず、LineChartWithMarkers.java ですが、これは参考サイト [1] で紹介されている LineChart を継承した内部クラス LineChartWithMarkers を、通常のクラスにして、少しだけ書き換えたものです。

リスト:LineChartWithMarkers.java 
package linechartsample;

import java.util.Objects;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.chart.Axis;
import javafx.scene.chart.LineChart;
import javafx.scene.shape.Line;

public class LineChartWithMarkers<X, Y> extends LineChart<X, Y> {

    private final ObservableList<Data<X, Y>> horizontalMarkers;
    private final ObservableList<Data<X, Y>> verticalMarkers;

    public LineChartWithMarkers(Axis<X> xAxis, Axis<Y> yAxis) {
        super(xAxis, yAxis);
        horizontalMarkers = FXCollections.observableArrayList(data -> new Observable[]{data.YValueProperty()});
        horizontalMarkers.addListener((InvalidationListener) observable -> layoutPlotChildren());
        verticalMarkers = FXCollections.observableArrayList(data -> new Observable[]{data.XValueProperty()});
        verticalMarkers.addListener((InvalidationListener) observable -> layoutPlotChildren());
    }

    public void addHorizontalValueMarker(Data<X, Y> marker) {
        Objects.requireNonNull(marker, "the marker must not be null");
        if (horizontalMarkers.contains(marker)) {
            return;
        }
        Line line = new Line();
        line.setStyle("-fx-stroke:green;-fx-stroke-width:1px;");
        marker.setNode(line);
        getPlotChildren().add(line);
        horizontalMarkers.add(marker);
    }

    public void removeHorizontalValueMarker(Data<X, Y> marker) {
        Objects.requireNonNull(marker, "the marker must not be null");
        if (marker.getNode() != null) {
            getPlotChildren().remove(marker.getNode());
            marker.setNode(null);
        }
        horizontalMarkers.remove(marker);
    }

    public void addVerticalValueMarker(Data<X, Y> marker) {
        Objects.requireNonNull(marker, "the marker must not be null");
        if (verticalMarkers.contains(marker)) {
            return;
        }
        Line line = new Line();
        line.setStyle("-fx-stroke:orange;-fx-stroke-width:1px;");
        marker.setNode(line);
        getPlotChildren().add(line);
        verticalMarkers.add(marker);
    }

    public void removeVerticalValueMarker(Data<X, Y> marker) {
        Objects.requireNonNull(marker, "the marker must not be null");
        if (marker.getNode() != null) {
            getPlotChildren().remove(marker.getNode());
            marker.setNode(null);
        }
        verticalMarkers.remove(marker);
    }

    @Override
    protected void layoutPlotChildren() {
        horizontalMarkers.stream().forEach((horizontalMarker) -> {
            drawHorizontalMarker(horizontalMarker);
        });
        verticalMarkers.stream().forEach((verticalMarker) -> {
            drawVerticalMarker(verticalMarker);
        });
        super.layoutPlotChildren();
    }

    private void drawHorizontalMarker(Data<X, Y> horizontalMarker) {
        Line line = (Line) horizontalMarker.getNode();
        line.setStartX(0);
        line.setEndX(getBoundsInLocal().getWidth());
        line.setStartY(getYAxis().getDisplayPosition(horizontalMarker.getYValue()) + 0.5); // 0.5 for crispness
        line.setEndY(line.getStartY());
        line.toFront();
    }

    private void drawVerticalMarker(Data<X, Y> verticalMarker) {
        Line line = (Line) verticalMarker.getNode();
        line.setStartX(getXAxis().getDisplayPosition(verticalMarker.getXValue()) + 0.5);  // 0.5 for crispness
        line.setEndX(line.getStartX());
        line.setStartY(0d);
        line.setEndY(getBoundsInLocal().getHeight());
        line.toFront();
    }

}

次に、サンプルチャートを描画する LineChartSample.java ですが、これは過去の記事 [2] をベースに、横線を前述の LineChartWithMarkers クラスの addHorizontalValueMarker メソッドで描画する機能を追加しています。なお、縦線を描画するには addVertialValueMarker メソッドを用います。

リスト:LineChartSample.java 
package linechartsample;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.stage.Stage;

public class LineChartSample extends Application {

    @Override
    public void start(Stage stage) {
        stage.setTitle("Line Chart Sample");

        //defining the axes
        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();
        xAxis.setLabel("X軸ラベル(年)");
        yAxis.setLabel("Y軸ラベル(数値)");

        //creating the chart
        LineChartWithMarkers<String, Number> lineChart = new LineChartWithMarkers<>(xAxis, yAxis);
        lineChart.setData(getChartData());
        lineChart.setTitle("折れ線グラフのサンプル");
        lineChart.addHorizontalValueMarker(new XYChart.Data<>("", 1));
        lineChart.addHorizontalValueMarker(new XYChart.Data<>("", -1));

        Scene scene = new Scene(lineChart, 600, 400);
        scene.getStylesheets().add(getClass().getResource("LineChart.css").toExternalForm());

        stage.setScene(scene);
        stage.show();
    }

    /**
     *
     * @return ObservableList<XYChart.Series<String, Double>>
     */
    private ObservableList<XYChart.Series<String, Number>> getChartData() {
        double y1 = 0.5;
        double y2 = -0.5;

        Series<String, Number> series1 = new Series<>();
        Series<String, Number> series2 = new Series<>();

        series1.setName("系列1");
        series2.setName("系列2");

        for (int i = 2011; i < 2021; i++) {
            series1.getData().add(new XYChart.Data<>(Integer.toString(i), y1));
            y1 = y1 + Math.random() - .5;

            series2.getData().add(new XYChart.Data<>(Integer.toString(i), y2));
            y2 = y2 + Math.random() - .5;
        }

        ObservableList<XYChart.Series<String, Number>> seriesList = FXCollections.observableArrayList();
        seriesList.add(series1);
        seriesList.add(series2);

        return seriesList;
    }

    public static void main(String[] args) {
        launch(args);
    }
}

LineChart.css は過去の記事 [2] と同じです。

リスト:LineChart.css 
.chart {
    -fx-padding: 10px;
    -fx-background-color: white;
}

.chart-content {
    -fx-padding: 10px;    
}

.chart-title {
    -fx-font-size: 18pt;    
}


.chart-legend {
    -fx-font-size: 12pt;    
    -fx-background-color:  transparent;
    -fx-padding: 10px;
}

.axis-label {
    -fx-font-size: 14pt;
}

.axis {
    -fx-tick-label-font: 12pt system;
}

.chart-series-line {
    -fx-stroke-width: 2px;
    -fx-effect: null;
}

.default-color0.chart-series-line { -fx-stroke: red; }
.default-color1.chart-series-line { -fx-stroke: blue; }

.default-color0.chart-line-symbol {
    -fx-background-color: red, #f88;
    -fx-background-radius: 6px;
    -fx-padding: 6px;
}
.default-color1.chart-line-symbol {
    -fx-background-color: blue, #88f;
    -fx-background-radius: 0;
    -fx-padding: 6px;
}

実行例を以下に示します。データは乱数でプロットされていますので、場合によっては横線 y = ± 1 が表示エリアに含まれない場合があります。

参考サイト

  1. java - How to add two vertical lines with JavaFX LineChart - Stack Overflow
  2. bitWalk's: JavaFX: LineChart を使いこなそう (2)

 

2016-03-08

NetBeans IDEでのネイティブ・パッケージング

Java でプログラミングをする一番大きな理由は、(自分にとっては)クロスプラットフォームな言語だからです。UI はプログラミングの一部であると思っているので、最も身近なデスクトップの GUI にフォーカスして取り組んでいますが、JavaFX を使うようになってからは、手軽に JavaFX を扱える NetBeans IDE ばかりを使うようになりました。NetBeans IDE では、アプリケーションをビルドするとプロジェクトディレクトリの中に dist というディレクトリを作成し、アプリケーション全てをまとめた jar ファイルを作成してくれます。

これだけでも結構重宝するのですが、NetBeans IDE が動作しているプラットフォーム (OS) に対応したインストールパッケージを作成する機能もあります。これを NetBeans IDE では「ネイティブ・パッケージング」と呼んでいます。結構嬉しい機能です。

上記サイトでは Windows を例にして、詳しく説明がされていますので、ここでは RPM 系 Linux である Fedora の場合について紹介したいと思います。Linux 上で動作する NetBeans IDE では、このネイティブ・パッケージングで Red Hat 系の RPM あるいは Debian 系の deb パッケージを作成します。

動作環境は次の通りです。

  • OS: Fedora 23 (x86_64)
  • Java: jdk1.8.0_74-1.8.0_74-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.1

まず、RPM パッケージ作成に必要な rpm-build パッケージをインストールしておきます。

$ rpm -qa | grep rpm-build
rpm-build-4.13.0-0.rc1.12.fc23.x86_64
rpm-build-libs-4.13.0-0.rc1.12.fc23.x86_64
$ 

RPM パッケージ化するサンプルとして、JavaFX のサンプルである BrickBreaker を使います。新規プロジェクトを作成する際に、カテゴリの下の方に「サンプル」がありますので JavaFX を選びプロジェクトの欄から BrickBreaker を選んで、「次へ」ボタンをクリックします。

「終了」ボタンをクリックして、BrickBreaker プロジェクトを作成します。

ファイルタブでプロジェクト BrickBreaker を選択、右クリックしてプロパティを選択してプロジェクトのプロパティ・ウィンドウを開きます。

左側のカテゴリのリストから、「ビルド」→「デプロイメント」を選択します。

「ネイティブ・パッケージの有効化」をチェックします。

「アイコンとスプラッシュ・イメージ」の「編集」ボタンをクリックして。「ネイティブ・パッケージ・アイコン」の欄に適当なアイコン画像を指定しておきます。

ここでは、以下のような Linux のマスコット Duke の 128x128 ピクセルの PNG 画像を指定しています。

ビルドされるパッケージの名前に付加されるバージョン番号は、カテゴリ「アプリケーション」の画面で指定します。ここでは 1.0 のままにします。

プロジェクト BrickBreaker を選択して、メニューから「実行」→「プロジェクト(BrickBreaker)を消去してビルド」を選択して、プロジェクトをビルドします。

プロジェクトタブでプロジェクト BrickBreaker を選択、右クリックして「パッケージとして」→「RPMパッケージ」を選択します。

すると、「出力」ウィンドウに下記のようなメッセージが表示され、しばらく待つと「ビルド成功」と緑字で表示されて終了します。RPM パッケージは NetBeansProjects/BrickBreaker/dist/bundles 以下に作成されています。

ant -f /home/bitwalk/NetBeansProjects/BrickBreaker -Djar.archive.disabled=true -Dnative.bundling.type=rpm build-native
build-native:
init:
deps-clean:
Updating property file: /home/bitwalk/NetBeansProjects/BrickBreaker/build/built-clean.properties
Deleting directory /home/bitwalk/NetBeansProjects/BrickBreaker/build
clean:
init:
deps-jar:
Created dir: /home/bitwalk/NetBeansProjects/BrickBreaker/build
Updating property file: /home/bitwalk/NetBeansProjects/BrickBreaker/build/built-jar.properties
Created dir: /home/bitwalk/NetBeansProjects/BrickBreaker/build/classes
Created dir: /home/bitwalk/NetBeansProjects/BrickBreaker/build/empty
Created dir: /home/bitwalk/NetBeansProjects/BrickBreaker/build/generated-sources/ap-source-output
Compiling 10 source files to /home/bitwalk/NetBeansProjects/BrickBreaker/build/classes
警告: [options] ブートストラップ・クラスパスが-source 1.6と一緒に設定されていません
警告1個
Copying 45 files to /home/bitwalk/NetBeansProjects/BrickBreaker/build/classes
compile:
Created dir: /home/bitwalk/NetBeansProjects/BrickBreaker/dist
Detected JavaFX Ant API version 1.3
Launching  task from /usr/java/jdk1.8.0_74/jre/../lib/ant-javafx.jar
Warning: From JDK7u25 the Codebase manifest attribute should be used to restrict JAR repurposing.
         Please set manifest.custom.codebase property to override the current default non-secure value '*'.
Launching  task from /usr/java/jdk1.8.0_74/jre/../lib/ant-javafx.jar
Note: To create native bundles the  task may require external tools. See JavaFX 2.2+ documentation for details.

Launching  in native packager mode...
Copying 1 file to /home/bitwalk/NetBeansProjects/BrickBreaker/build/icon
Source native icon reference: /home/bitwalk/画像/duke3D-128.png
Processed native icon reference: /home/bitwalk/NetBeansProjects/BrickBreaker/build/icon/BrickBreaker.png
ベースJDKがありません。パッケージはシステムJREを使用します。
ベースJDKがありません。パッケージはシステムJREを使用します。
パッケージ(.rpm)は次に保存されました: /home/bitwalk/NetBeansProjects/BrickBreaker/dist/bundles
jfx-deployment-script:
jfx-deployment:
jar:
jfx-rebuild:
jfx-build-native:
ビルド成功(合計時間: 1分17秒)

早速インストールしてみます。なお、このパッケージには実行に必要なランタイム (JRE) が含まれていて、インストール先は /opt 以下になります。

[bitwalk@notepc ~]$ cd NetBeansProjects/BrickBreaker
[bitwalk@notepc BrickBreaker]$ ls
build  build.xml  dist  manifest.mf  nbproject  src
[bitwalk@notepc BrickBreaker]$ cd dist/bundles
[bitwalk@notepc bundles]$ ls
brickbreaker-1.0-1.x86_64.rpm
[bitwalk@notepc bundles]$ su
パスワード:
[root@notepc bundles]# dnf install brickbreaker-1.0-1.x86_64.rpm
メタデータの期限切れの確認は、2:16:33 前の Sun Mar  6 10:44:44 2016 に実施しました。
依存性が解決されました。
================================================================================
 Package                アーキテクチャ
                                   バージョン            リポジトリ        容量
================================================================================
インストール:
 alsa-lib               i686       1.0.29-2.fc23         fedora           392 k
 brickbreaker           x86_64     1.0-1                 @commandline      52 M
 glibc                  i686       2.22-11.fc23          updates          4.3 M
 libX11                 i686       1.6.3-2.fc23          fedora           616 k
 libXau                 i686       1.0.8-5.fc23          fedora            34 k
 libXext                i686       1.3.3-3.fc23          fedora            43 k
 libXi                  i686       1.7.6-1.fc23          updates           46 k
 libXrender             i686       0.9.9-2.fc23          fedora            30 k
 libXtst                i686       1.2.2-5.fc23          fedora            25 k
 libgcc                 i686       5.3.1-2.fc23          updates           97 k
 libxcb                 i686       1.11.1-1.fc23         updates          206 k
 nss-softokn-freebl     i686       3.22.2-1.0.fc23       updates          197 k

トランザクションの要約
================================================================================
インストール  12 パッケージ

合計容量: 58 M
総ダウンロード容量: 5.9 M
インストール済み容量: 207 M
これでいいですか? [y/N]: y
パッケージをダウンロードしています:
(1/11): libXext-1.3.3-3.fc23.i686.rpm           277 kB/s |  43 kB     00:00    
...
(省略)
...
(11/11): glibc-2.22-11.fc23.i686.rpm            2.5 MB/s | 4.3 MB     00:01    
--------------------------------------------------------------------------------
合計                                            626 kB/s | 5.9 MB     00:09     
トランザクションの確認を実行中...
トランザクションの確認に成功しました。
トランザクションのテストを実行中...
トランザクションのテストに成功しました。
トランザクションを実行中...
  インストール    : libgcc-5.3.1-2.fc23.i686                               1/12 
...
(省略)
...
  検証中          : nss-softokn-freebl-3.22.2-1.0.fc23.i686               12/12 

インストール:
  alsa-lib.i686 1.0.29-2.fc23      brickbreaker.x86_64 1.0-1                   
  glibc.i686 2.22-11.fc23          libX11.i686 1.6.3-2.fc23                    
  libXau.i686 1.0.8-5.fc23         libXext.i686 1.3.3-3.fc23                   
  libXi.i686 1.7.6-1.fc23          libXrender.i686 0.9.9-2.fc23                
  libXtst.i686 1.2.2-5.fc23        libgcc.i686 5.3.1-2.fc23                    
  libxcb.i686 1.11.1-1.fc23        nss-softokn-freebl.i686 3.22.2-1.0.fc23     

完了しました!
[root@notepc bundles]# 

GNOME デスクトップの「アクティビティ」をクリックして、アプリケーションを表示すると、Duke のアイコンの BrickBreaker が追加されています。

下記のように BrickBreaker が起動しました。

 

2016-03-06

JavaFX: TreeView と ContextMenu (2)

JavaFX の TreeView にポップアップ・メニュー (ContextMenu) を表示するサンプルについての続きです。今回は、TreeItem に ContextMenu を関連付けてポップアップ・メニューを表示させるサンプルを紹介します。なお、今回紹介するサンプルでも、[1] のサイトで掲載されている素材を 32 x 32 に縮小して利用させていただきました。

考え方としては、TreeItem クラスを継承した新しいクラスを作成し、固有のポップアップメニュー (ContextMenu) を表示させるようにします。

実行例

今回のサンプルでは、内部クラスを追加するので少々ソースが長くなります。そのため、最初に実行例を示しておきます。

「りんご」が選択されました。

見た目は、前回のサンプルと代わり映えしませんが、最初のレベルである「野菜」「果物」を表示しているノードでは、マウスの右クリックでポップアップメニューを表示せず、「りんご」など末端のノードではポップアップメニューが表示されるように変更されています。

最初のレベル「野菜」「果物」を表示するノードには、TreeItem クラスを継承した TreeBranch というクラスを作成して使用しています。この継承したクラスでは、ポップアップメニュー (ContextMenu) を表示させる機能(メソッド)、getMenu() を追加して、ポップアップメニューに使用する ContextMenu のインスタンスを TreeCell へ返すようにしています。ただし、この TreeBranch では、そのメソッドを実装していますが null を返すだけです。

「りんご」など末端のノードには、TreeBranch クラスを継承した TreeLeaf というクラスを作成して使用していますが、ItemBranch クラスで追加されたメソッド、getMenu() をオーバーライドして固有のポップアップメニューを定義して、その ContextMenu のインスタンスを TreeCell 返すようにしています。

その上で TreeCell クラスを拡張した TreeCellImpl クラスで、TreeBranch クラスが返すgetMenu() メソッドが返す ContextMenu のインスタンスを表示する機能を紐付けています。これを、setCellFactory メソッドで、このサンプルの TreeView クラスの tree インスタンスが使用する TreeCell に設定しています。

以上の拡張は、参考サイト [2] を参考にしています。

ソース

動作環境は次の通りです。

  • OS: Fedora 23 (x86_64)
  • Java: jdk1.8.0_74-1.8.0_74-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.1
リスト:Sample_TreeView2.java 
package sample_treeview2;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import static javafx.application.Application.launch;

public class Sample_TreeView2 extends Application {

    Image CAROT = new Image(getClass().getResource("carot.png").toString());
    Image EGGPLANT = new Image(getClass().getResource("eggplant.png").toString());
    Image TOMATO = new Image(getClass().getResource("tomato.png").toString());
    Image APPLE = new Image(getClass().getResource("apple.png").toString());
    Image GRAPE = new Image(getClass().getResource("grape.png").toString());
    Image BANANA = new Image(getClass().getResource("banana.png").toString());

    TreeView<String> tree;

    @Override
    public void start(Stage primaryStage) {

        TreeItem<String> top = new TreeItem<>("root");

        TreeBranch<String> nodeItemA = new TreeBranch<>("野菜");
        addNode(top, nodeItemA);
        nodeItemA.setExpanded(true);
        TreeBranch<String> nodeItemB = new TreeBranch<>("果物");
        addNode(top, nodeItemB);
        nodeItemB.setExpanded(true);

        TreeLeaf<String> nodeItemA1 = new TreeLeaf<>("にんじん", new ImageView(CAROT));
        addNode(nodeItemA, nodeItemA1);
        TreeLeaf<String> nodeItemA2 = new TreeLeaf<>("なす", new ImageView(EGGPLANT));
        addNode(nodeItemA, nodeItemA2);
        TreeLeaf<String> nodeItemA3 = new TreeLeaf<>("とまと", new ImageView(TOMATO));
        addNode(nodeItemA, nodeItemA3);

        TreeLeaf<String> nodeItemB1 = new TreeLeaf<>("りんご", new ImageView(APPLE));
        addNode(nodeItemB, nodeItemB1);
        TreeLeaf<String> nodeItemB2 = new TreeLeaf<>("ぶどう", new ImageView(GRAPE));
        addNode(nodeItemB, nodeItemB2);
        TreeLeaf<String> nodeItemB3 = new TreeLeaf<>("ばなな", new ImageView(BANANA));
        addNode(nodeItemB, nodeItemB3);

        tree = new TreeView<>(top);
        tree.setShowRoot(false);
        tree.setCellFactory((TreeView<String> p) -> new TreeCellImpl());

        StackPane root = new StackPane();
        root.getChildren().add(tree);

        Scene scene = new Scene(root, 200, 300);

        primaryStage.setTitle(getClass().getSimpleName());
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    void addNode(TreeItem<String> parent, TreeItem<String> child) {
        parent.getChildren().add(child);
    }

    class TreeBranch<T> extends TreeItem<T> {

        public TreeBranch(final T value) {
            super(value);
        }

        public TreeBranch(final T value, final Node graphic) {
            super(value, graphic);
        }

        public ContextMenu getMenu() {
            return null;
        }
    }

    class TreeLeaf<T> extends TreeBranch<T> {

        public TreeLeaf(final T value) {
            super(value);
        }

        public TreeLeaf(final T value, final Node graphic) {
            super(value, graphic);
        }

        @Override
        public ContextMenu getMenu() {
            ContextMenu popup = new ContextMenu();
            MenuItem menuItem = new MenuItem("処理");
            menuItem.setOnAction((ActionEvent event) -> {
                TreeItem selItem = tree.getSelectionModel().getSelectedItem();
                System.out.println("「" + selItem.getValue() + "」が選択されました。");
            });
            popup.getItems().add(menuItem);

            return popup;
        }
    }

    public final class TreeCellImpl extends TreeCell<String> {

        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);

            if (empty) {
                setText(null);
                setGraphic(null);
            } else {
                setText(getItem() == null ? "" : getItem());
                setGraphic(getTreeItem().getGraphic());
                setContextMenu(((TreeBranch) getTreeItem()).getMenu());
            }
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

参考サイト

  1. 野菜・果物アイコン 画像フリー素材集|無料素材倶楽部
  2. Is this possible that i can add context menu at TreeItem rather then TreeView in JavaFX - Stack Overflow

 

2016-03-05

JavaFX: TreeView と ContextMenu (1)

JavaFX の TreeView のツリー項目を右クリックすると、ポップアップ・メニュー (ContextMenu) が表示されるサンプルを、二回に亘って紹介します。今回は ListView で紹介した方法 [1] と同じです。なお、今回紹介するサンプルでは、[2] のサイトで掲載されている素材を 32 x 32 に縮小して利用させていただきました。

動作環境は次の通りです。

  • OS: Fedora 23 (x86_64)
  • Java: jdk1.8.0_74-1.8.0_74-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.1
リスト:Sample_TreeView.java 
package sample_treeview;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Sample_TreeView extends Application {

    Image CAROT = new Image(getClass().getResource("carot.png").toString());
    Image EGGPLANT = new Image(getClass().getResource("eggplant.png").toString());
    Image TOMATO = new Image(getClass().getResource("tomato.png").toString());
    Image APPLE = new Image(getClass().getResource("apple.png").toString());
    Image GRAPE = new Image(getClass().getResource("grape.png").toString());
    Image BANANA = new Image(getClass().getResource("banana.png").toString());

    @Override
    public void start(Stage primaryStage) {

        TreeItem<String> top = new TreeItem<>("root");

        TreeItem<String> nodeItemA = new TreeItem<>("野菜");
        addNode(top, nodeItemA);
        nodeItemA.setExpanded(true);
        TreeItem<String> nodeItemB = new TreeItem<>("果物");
        addNode(top, nodeItemB);
        nodeItemB.setExpanded(true);

        TreeItem<String> nodeItemA1 = new TreeItem<>("にんじん", new ImageView(CAROT));
        addNode(nodeItemA, nodeItemA1);
        TreeItem<String> nodeItemA2 = new TreeItem<>("なす", new ImageView(EGGPLANT));
        addNode(nodeItemA, nodeItemA2);
        TreeItem<String> nodeItemA3 = new TreeItem<>("とまと", new ImageView(TOMATO));
        addNode(nodeItemA, nodeItemA3);

        TreeItem<String> nodeItemB1 = new TreeItem<>("りんご", new ImageView(APPLE));
        addNode(nodeItemB, nodeItemB1);
        TreeItem<String> nodeItemB2 = new TreeItem<>("ぶどう", new ImageView(GRAPE));
        addNode(nodeItemB, nodeItemB2);
        TreeItem<String> nodeItemB3 = new TreeItem<>("ばなな", new ImageView(BANANA));
        addNode(nodeItemB, nodeItemB3);

        ContextMenu popup = new ContextMenu();
        TreeView<String> tree = new TreeView<>(top);
        tree.setShowRoot(false);
        tree.setContextMenu(popup);
        createPopupMenu(popup, tree);

        StackPane root = new StackPane();
        root.getChildren().add(tree);

        Scene scene = new Scene(root, 200, 300);

        primaryStage.setTitle(getClass().getSimpleName());
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    void addNode(TreeItem<String> parent, TreeItem<String> child) {
        parent.getChildren().add(child);
    }

    void createPopupMenu(ContextMenu menu, TreeView tree) {
        MenuItem item = new MenuItem("処理");
        item.setOnAction((ActionEvent t) -> {
            TreeItem selItem = (TreeItem) tree.getSelectionModel().getSelectedItem();
            System.out.println("「" + selItem.getValue() + "」が選択されました。");
        });
        menu.getItems().add(item);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

実行例を以下に示します。

「野菜」が選択されました。
「にんじん」が選択されました。
「果物」が選択されました。
「なす」が選択されました。
「ぶどう」が選択されました。

問題点

ListView の項目に対しては、同一のポップアップ・メニューを表示させることができれば用が足りましたが、TreeView の場合は事情が少し違います。もちろん、今回紹介したようなポップアップメニューで十分な場合もあるのかもしれませんが、大抵の場合、各ノード(項目)の階層(レベル)によって、ポップアップ・メニューの表示内容を変えたり、あるいはレベルごとに表示/非表示を変えたい場合が多いのではないでしょうか。

次回は、TreeItem に ContextMenu を関連付けてポップアップ・メニューを表示させるサンプルを紹介する予定です。

参考サイト

  1. bitWalk's: 【備忘録】ListView にポップアップメニューをつける - JavaFX
  2. 野菜・果物アイコン 画像フリー素材集|無料素材倶楽部