2017年12月23日土曜日

テキストエディタをJavaで作成する計画7

続きまして、第7回はポップアップ作成です。
バージョン情報を表示できるようにします。

【EditerView.fxml】

<Menu mnemonicParsing="false" text="ヘルプ">
    <items>
         <MenuItem mnemonicParsing="false" onAction="#aboutAction" text="バージョン情報" />
    </items>
</Menu>



【EditerController.java】

    private Editer editer;

    /**
     * バージョン情報
     *
     * @param event
     */
    @FXML
    private void aboutAction(ActionEvent event) {
        editer.showAboutInformationDialog();
    }



【Editer.java】

    /**
     * バージョン情報を表示します。
     */
    public void showAboutInformationDialog() {
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setTitle(CommonConst.ABOUT_INFORMATION_TITLE);
        alert.setHeaderText(CommonConst.ABOUT_INFORMATION_HEADER_TEXT);
        alert.setContentText(CommonConst.ABOUT_INFORMATION_CONTENT_TEXT);
        alert.showAndWait();
    }



【CommonConst.java】

    /**
     * バージョン情報画面 タイトル
     */
    public static final String ABOUT_INFORMATION_TITLE = "バージョン情報";

    /**
     * バージョン情報画面 ヘッダー
     */
    public static final String ABOUT_INFORMATION_HEADER_TEXT =
            "ヘッダー1行目\n" +            "ヘッダー2行目\n" +
            "ヘッダー3行目\n";

    /**
     * バージョン情報画面 コンテンツ
     */
    public static final String ABOUT_INFORMATION_CONTENT_TEXT =
            "コンテンツ1行目\n" +            "コンテンツ2行目\n" +
            "コンテンツ3行目\n";

[バージョン情報]をクリックすると、ポップアップが表示されるようになりました。









テキストエディタをJavaで作成する計画6

久しぶりにブログ更新です。

作成中のテキストエディタですが、ロジックがぐちゃぐちゃになってきそうなので、一旦構造を変えてみることにしました。

ターミナルで find コマンド入力するとこんな感じです。
XXXXXXXXXXX:src XXXXXXXXXX$ find .
./textediter
./textediter/controller
./textediter/controller/DialogController.java
./textediter/controller/EditerController.java
./textediter/controller/FindController.java
./textediter/controller/ReplaceController.java
./textediter/model
./textediter/model/CommonConst.java
./textediter/model/Dialog.java
./textediter/model/Editer.java
./textediter/model/Find.java
./textediter/model/Main.java
./textediter/model/Replace.java
./textediter/view
./textediter/view/DialogView.fxml
./textediter/view/EditerView.fxml
./textediter/view/FindView.fxm
./textediter/view/ReplaceView.fxml

これで実装し直してみたわけですが、FXMLファイルを別のパッケージに移動させると実行時エラーが出て地味に大変だったです。


Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: Location is not set.
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2434)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
at textediter.model.Editer.start(Editer.java:52)
at textediter.model.Main.start(Main.java:18)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
Exception running application textediter.model.Main

いっぱい出てきましたが、一言で言うとFXMLファイルが参照できなかったみたいですね。
色々試してみた結果、これで治りました。

        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/textediter/view/EditerView.fxml"));

次はポップアップ作ろうと思います。

2017年10月29日日曜日

テキストエディタをJavaで作成する計画5

日曜プログラマーごっこやるのもいいですが、晴れの日は外で遊びたいです。。。
今日は雨なので、久しぶりにブログ更新です!!

今回は「上書き保存」機能を実装してみます。
今作っているテキストエディタは複数ウィンドウ出て来て、それぞれファイルを開くことができることもあって、ファイルロックは実装しておきたいところです。
それと新規作成でファイルを開いていない状態からの「上書き保存」は「名前を付けて保存」ってことなので、「名前を付けて保存」が実装されたら処理変更しないといけないです。
ということで、割と重い作業なので、ファイルロックだけ実装します。

①ファイルを開くときにファイルをロックする。
②ファイルを閉じるときにロックを解除する。

ファイルロックできないときは考えてないので、とりあえず例外だけ投げて放置です。

【FXMLDocumentController】

    private ProcessManager pm;

    private void openAction(ActionEvent event) {

        bottomLabel.setText("開く");
        pm.setSelectedFile(pm.openFileChooser(scene));

        // ファイルが選択されたとき
        if (pm.getSelectedFile() != null) {
            pm.setCurrentFilePath(Paths.get(pm.getSelectedFile().getAbsolutePath()));

            try {
//            ファイルチャンネルを設定する
                pm.setFileChannel(FileChannel.open(pm.getSelectedFile().toPath(),
                        StandardOpenOption.CREATE,
                        StandardOpenOption.WRITE));
                if (pm.getFileChannel().tryLock() != null) {
                    // ファイルロックができれば表示する
                    textArea.setText(new String(Files.readAllBytes(pm.getCurrentFilePath()), pm.getCharset()));
                }
            } catch (OverlappingFileLockException ex) {
                // 別のプロセスがロック中
            } catch (IOException ex) {
                Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
            }
            bottomLabel.setText(pm.getSelectedFile().getName());
        }
    }


    /**
     * MenuItem[閉じる] イベントが発生したウィンドウを非表示にします。
     *
     * @param event
     */
    @FXML
    void closeAction(ActionEvent event) {
        bottomLabel.setText("閉じる");
        try {
            // ファイルロック解除
            if(pm.getFileChannel() != null) {
                pm.getFileChannel().close();
            }
        } catch (IOException ex) {
            Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
        }
        pm.terminateTextEditer(getScene());
    }

    /**
     * メニューの「上書き保存」を押下しすると、saveTextメソッドを呼び出します。
     *
     * @param event
     */
    @FXML
    private void saveAction(ActionEvent event) {
        bottomLabel.setText("上書き保存");
        pm.saveText(textArea.getText());
    }

【ProcessManager】

    /**
     * 編集中のファイルパス
     */
    private Path currentFilePath;
    /**
     * 作業中のファイルチャンネル
     */
    private FileChannel fileChannel;

    /**
     * 開いているファイルにテキストデータを上書き保存します。
     *
     * @param text 保存するテキストデータ
     */
    public void saveText(String text) {
        try {
            Files.write(currentFilePath, text.getBytes(charset),
                    StandardOpenOption.CREATE,
                    StandardOpenOption.WRITE,
                    StandardOpenOption.TRUNCATE_EXISTING
            );
        } catch (IOException ex) {
            Logger.getLogger(ProcessManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

ソースが長くなってきて、かなり省略してますけど、いるところ抜けてないかな?
アクションにロジック書いちゃったのはミスでした。
ファイルロックできないときは参照モードとかもいるのかな?
テキストエディタって思ったより大変ですね。

2017年10月1日日曜日

テキストエディタをJavaで作成する計画4

今回はファイルを「開く」機能を追加します。

流れとしては、

①メニューの「開く」ボタンを押下する。
②FileChooserを用いてファイルを選択する。
③選択したファイルのデータがTextAreaに表示される。

です。下記の内容で実装してみました。

【FXMLDocumentControllerクラス】FileChooserを呼び出し、戻り値のFileをUTF-8で読み込み、値をTextAreaにセットします。ついでに、ウィンドウの下の方にファイル名が表示されるようにしました。
public class FXMLDocumentController implements Initializable {

    private ProcessManager pm;
    private Scene scene;

    private void openAction(ActionEvent event) {
        bottomLabel.setText("開く");
        File selectedFile = pm.openFileChooser(scene);
        if(selectedFile != null) {
            try {
                textArea.setText(new String(Files.readAllBytes(Paths.get(selectedFile.getAbsolutePath())), StandardCharsets.UTF_8.name()));
            } catch(IOException e) {
                e.printStackTrace();
            }
            bottomLabel.setText(selectedFile.getName());
        }
    }
}


【ProcessManagerクラス】拡張子のフィルター機能がありますが、今回は一旦、「すべてのファイル」としておきました。
public class ProcessManager extends Application {

    public File openFileChooser(Scene scene) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.getExtensionFilters().addAll(
                new ExtensionFilter("すべてのファイル", "*.*")
        );
        File selectedFile = fileChooser.showOpenDialog(scene.getWindow());
        return selectedFile;
    }
}






という事で、UTF-8ならちゃんとファイルを開くことができるプログラムができました。

2017年9月24日日曜日

テキストエディタをJavaで作成する計画3

さてさて、今回はテキストエディタの「新規作成」機能と「閉じる」機能を実装します。

よく考えたら新規作成にもいろんなパターンがありますね。
①新しいウィンドウが開く
②新しいタブが作成される
③作業中のファイルを閉じてからそのまま開く

個人的には①が好きなので、この方法で実装します。



新しいウィンドウが開く処理はダイアログの表示でも使えるはずなので、どちらにしても作れるようになっておきたい部分です。

結論から言うと、JavaFXで新しくウィンドウを作るのはかなり大変な作業でした。
これはStageクラスの使い方がある程度理解が必要なことと、[閉じる]ボタンを押したときに全ウィンドウ閉じられたり、別のウィンドウが閉じられたりするなど、色々予定外のバグがでました。主にスレッド関係が原因のようでした。

また、ネットの情報は断片的でテキストエディタを作るとなると自分で考えないと無理でした。
と言うことで、ここから先については僕のオリジナルな部分が多いので、設計の良し悪しは不明です。動作確認では一応、違和感なく動作しました。

【ProcessManagerクラス】このクラスのmainメソッドが初めに実行されます。残念なことにApplicationクラスのサブクラスである必要がありました。
public class ProcessManager extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        createTextEditer();
    }

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

    /**
     * 新しいテキストエディタを作成します。
     */
    public void createTextEditer() {
        try {
            new TextEditer01().start(new Stage());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 引数で指定されたウィンドウを非表示にします。
     * @param scene 終了対象の画面
     */
    public void terminateTextEditer(Scene scene) {
        try {
            scene.getWindow().hide();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

【TextEditer01クラス】ProcessManagerクラスから呼ばれます。普通はこのクラスのプロパティにSceneがありますが、イベントからSceneをうまく取得できなかったので、代替案としてSceneをFXMLDocumentControllerクラスに持っていき、FXMLに紐づいているコントローラの情報を保持しておきます。
public class TextEditer01 extends Application {

    private FXMLDocumentController controller;
    private ProcessManager pm = new ProcessManager();

    @Override
    public void start(Stage stage) throws Exception {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
        Parent root = fxmlLoader.load();
     
        controller = (FXMLDocumentController) fxmlLoader.getController();
        controller.setScene(new Scene(root));
     
        stage.setScene(controller.getScene());
        stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent event) {
                event.consume();
                try {
                    pm.terminateTextEditer(controller.getScene());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        stage.show();
    }
}


【FXMLDocumentControllerクラス】Sceneをプロパティにするとイベントとうまく紐付けできました。
public class FXMLDocumentController implements Initializable {

    private ProcessManager pm;
    private Scene scene;

    /**
     * 新しいウィンドウを表示します。
     * @param event
     */
    @FXML
    private void newAction(ActionEvent event) {
        pm.createTextEditer();
    }

    /**
     * MenuItem[閉じる] イベントが発生したウィンドウを非表示にします。
     * @param event
     */
    @FXML
    void closeAction(ActionEvent event) {
        pm.terminateTextEditer(getScene());
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        pm = new ProcessManager();
    }

    public Scene getScene() {
        return scene;
    }

    public void setScene(Scene scene) {
        this.scene = scene;
    }


こんな感じで「新規作成」と「閉じる」が実装できました。
次は「開く」を追加します。

2017年9月16日土曜日

テキストエディタをJavaで作成する計画2

前回に続きまして、じっくり一晩考えてみてテキストエディタの機能を決めました。

メニュー
├── ファイル
   ├── 新規作成
   ├── 開く
   ├── 上書き保存
   ├── 名前を付けて保存
   ├── 印刷
   └── 閉じる
├── 編集
   ├── 元に戻す
   ├── やり直す
   ├── すべて選択
   ├── 切り取り
   ├── コピー
   ├── 貼り付け
   ├── 検索
   └── 置換
├── 表示
   ├── 右端で折り返す
   └── フォント
└── ヘルプ
    └── バージョン情報

もう十分ですね。これくらいならなんとかなるでしょう。というかほとんどメモ帳と同じになってしまいました。
右クリックの機能は一旦保留にします。

問題なのは印刷ですね。作ったことないのでどう実装するのか分かりません。
あとフォントは設定が残るようにしないといけないので、設定ファイルがいりそうです。

まだまだ仕様がふわふわしてますけど、SceneBuilderを使ってとりあえず画面だけ作ってみます。



画面だけなら5分でできました!
もう完成したような気持ちになるけど、保存とかできませんからね。
青空文庫から「吾輩は猫である」をそのまま貼ってみますと、動作が結構重くなりました。
そして長い横スクロールもあってすごく使いにくいです。
TextAreaにwrapText="true" を付け加えると治りました。

<TextArea prefHeight="200.0" prefWidth="200.0" wrapText="true" BorderPane.alignment="CENTER" />



この部分はメニューの[右端で折り返す]の機能なので、またコードを少しいじらないといけないですね。
ちなみに動作はさらに重たくなった感じしますが、どうしようもないですね。

次はメニューで何か選択された時に呼び出されるメソッドの名前を定義します。

メニュー
├── ファイル
   ├── 新規作成・・・・・・private void newAction(ActionEvent event)
   ├── 開く・・・・・・・・private void openAction(ActionEvent event)
   ├── 上書き保存・・・・・private void saveAction(ActionEvent event)
   ├── 名前を付けて保存・・private void saveAsAction(ActionEvent event)
   ├── 印刷・・・・・・・・private void printAction(ActionEvent event)
   └── 閉じる・・・・・・・private void closeAction(ActionEvent event)
├── 編集
   ├── 元に戻す・・・・・・private void undoAction(ActionEvent event)
   ├── やり直す・・・・・・private void redoAction(ActionEvent event)
   ├── すべて選択・・・・・private void selectAllAction(ActionEvent event)
   ├── 切り取り・・・・・・private void cutAction(ActionEvent event)
   ├── コピー・・・・・・・private void copyAction(ActionEvent event)
   ├── 貼り付け・・・・・・private void pasteAction(ActionEvent event)
   ├── 検索・・・・・・・・private void findAction(ActionEvent event)
   └── 置換・・・・・・・・private void replaceAction(ActionEvent event)
├── 表示
   ├── 右端で折り返す・・・private void wrapAction(ActionEvent event)
   └── フォント・・・・・・private void fontAction(ActionEvent event)
└── ヘルプ

    └── バージョン情報・・・private void aboutAction(ActionEvent event)

こんな感じでしょうか。
あと下の方に、行数とか処理内容とか表示されたら良さそうなので、Labelも画面に追加しました。




例えばフォントを選択すると下に「フォント」と出てきます。
「右端で折り返す」はデフォルトがtrueのCheckMenuItemにしてあります。

【FXMLDocumentController.java】
public class FXMLDocumentController implements Initializable {
 
    @FXML
    private Label bottomLabel;
 
    @FXML
    private void newAction(ActionEvent event) {
        bottomLabel.setText("新規作成");
    }
    ・
    ・
    ・
}

【FXMLDocument.fxml】
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="textediter01.FXMLDocumentController">
    <top>
        <MenuBar BorderPane.alignment="CENTER">
            <menus>
                <Menu mnemonicParsing="false" text="ファイル">
                    <items>
                        <MenuItem mnemonicParsing="false" onAction="#newAction" text="新規作成" />
                        <MenuItem mnemonicParsing="false" onAction="#openAction" text="開く" />
                        <MenuItem mnemonicParsing="false" onAction="#saveAction" text="上書き保存" />
                        <MenuItem mnemonicParsing="false" onAction="#saveAsAction" text="名前を付けて保存" />
                        <MenuItem mnemonicParsing="false" onAction="#printAction" text="印刷" />
                        <MenuItem mnemonicParsing="false" onAction="#closeAction" text="閉じる" />
                    </items>
                </Menu>
                <Menu mnemonicParsing="false" text="編集">
                    <items>
                        <MenuItem mnemonicParsing="false" onAction="#undoAction" text="元に戻す" />
                        <MenuItem mnemonicParsing="false" onAction="#redoAction" text="やり直す" />
                        <MenuItem mnemonicParsing="false" onAction="#selectAllAction" text="すべて選択" />
                        <MenuItem mnemonicParsing="false" onAction="#cutAction" text="切り取り" />
                        <MenuItem mnemonicParsing="false" onAction="#copyAction" text="コピー" />
                        <MenuItem mnemonicParsing="false" onAction="#pasteAction" text="貼り付け" />
                        <MenuItem mnemonicParsing="false" onAction="#findAction" text="検索" />
                        <MenuItem mnemonicParsing="false" onAction="#replaceAction" text="置換" />
                    </items>
                </Menu>
                <Menu mnemonicParsing="false" text="表示">
                    <items>
                        <CheckMenuItem mnemonicParsing="false" onAction="#wrapAction" selected="true" text="右端で折り返す" />
                        <MenuItem mnemonicParsing="false" onAction="#fontAction" text="フォント" />
                    </items>
                </Menu>
                <Menu mnemonicParsing="false" text="ヘルプ">
                    <items>
                        <MenuItem mnemonicParsing="false" onAction="#aboutAction" text="バージョン情報" />
                    </items>
                </Menu>
            </menus>
        </MenuBar>
    </top>
    <center>
        <TextArea prefHeight="200.0" prefWidth="200.0" wrapText="false" BorderPane.alignment="CENTER" />
    </center>
   <bottom>
      <Label fx:id="bottomLabel" BorderPane.alignment="CENTER_LEFT" />
   </bottom>
</BorderPane>

次回に続く。。。かも



2017年9月9日土曜日

テキストエディタをJavaで作成する計画1

やっぱりプログラムは書かなきゃ覚えられません。設計の良し悪しも失敗しないと理解できません。

ということで、練習でテキストエディタを作ってみたいと思います。ファイルの取り込みと編集や保存、多少の設定など基本的なことが練習できて良い経験になる予定です。

さて仕様について考え中ですが、
Webアプリケーションにする案も一瞬ありましたが、誰も得しそうにないのでやめました。
普通にデスクトップから起動してWindows標準装備の「メモ帳」に少し機能が追加されてるぐらいのエディタになるといいなと思いました。

ということで、Windowsの「メモ帳」が僕にとってのベンチマークになるので、仕様を確認してみます。メニューを見るとだいたい機能が分かりそうなので、メニューを確認してみました。


【メモ帳】
メニュー
├── ファイル(F)
│ ├── 新規(N)
│ ├── 開く(O)
│ ├── 上書き保存(S)
│ ├── 名前を付けて保存(A)
│ ├── ページ設定
│ ├── 印刷(P)
│ └── メモ帳の終了(X)
├── 編集(E)
│ ├── 元に戻す(U)
│ ├── 切り取り(T)
│ ├── コピー(C)
│ ├── 貼り付け(P)
│ ├── 削除(L)
│ ├── 検索(F)
│ ├── 次を検索(N)
│ ├── 置換(R)
│ ├── 行へ移動(G)
│ ├── すべて選択(A)
│ └── 日付と時刻(D)
├── 書式(O)
│ ├── 右端で折り返す(W)
│ └── フォント(F)...
├── 表示
│ └── ステータスバー(S)
└── ヘルプ
  ├── ヘルプの表示(H)
  └── バージョン情報(A)


こうして見ると思ったより多いですね。
そういえば、右クリックというやつもありましたね。

「右クリック」
元に戻す(U)
切り取り(T)
コピー(C)
貼り付け(P)
削除(D)
すべて選択(A)
右から左に読む(R)
Unicode 制御文字の表示(S)
Unicode 制御文字の挿入(I)
IMEを開く(O)
再変換(R)


これも意外に多い気がしました。日曜大工なのでテキパキしないと、かなり時間かかりそうです。
ついでにMac標準装備の「メモ」も機能を確認してみました。

メニュー
├── メモ
│ ├── メモについて
│ ├── 環境設定…
│ ├── アカウント…
│ ├── ロックされたメモを全て閉じる
│ ├── サービス▶︎
│ ├── メモを隠す
│ ├── ほかを隠す
│ ├── すべて表示
│ └── メモを終了
├── ファイル
│ ├── 新規メモ
│ ├── 新規メモ
│ ├── 環境設定…
│ ├── 共有 ▶︎
│ ├── ”メモ”に読み込む… ▶︎
│ ├── PDFとして書き出す…
│ ├── このメモをロック
│ └── プリント…
├── 編集
│ ├── 取り消す
│ ├── やり直す
│ ├── カット
│ ├── コピー
│ ├── ペースト
│ ├── ペーストしてスタイルを合わせる
│ ├── ペーストしてスタイルを保持
│ ├── 削除
│ ├── 全てを選択
│ ├── ファイルを添付…
│ ├── リンクを追加…
│ ├── 添付ファイルを名称変更…
│ ├── 検索 ▶︎
│ ├── スペルと文法 ▶︎
│ ├── 自動置換 ▶︎
│ ├── 変換 ▶︎
│ ├── スピーチ ▶︎
│ ├── 音声入力を開始…
│ └── 絵文字と記号
├── 表示
│ ├── サイドバーを隠す
│ ├── サムネール
│ ├── 目次
│ ├── ハイライトとメモ
│ ├── ブックマーク
│ ├── コンタクトシート
│ ├── 連続スクロール
│ ├── 単一ページ
│ ├── 2ページ
│ ├── プロファイルを使ってソフトプルール
│ ├── イメージ背景を表示
│ ├── 実際のサイズ
│ ├── ウインドウに合わせる
│ ├── 拡大
│ ├── 縮小
│ ├── 選択部分に合わせて拡大
│ ├── マークアップツールバーを表示
│ ├── ツールバーを隠す
│ ├── ツールバーをカスタマイズ…
│ ├── スライドショー
│ └── フルスクリーンにする
├── 移動
│ ├── 上
│ ├── 下
│ ├── 前の項目
│ ├── 次の項目
│ ├── ページ移動…
│ ├── 戻る
│ └── 進む
├── ツール
│ ├── インスペックタを表示
│ ├── 拡大鏡を表示
│ ├── カラーを調整
│ ├── サイズを調整
│ ├── テキスト選択
│ ├── 長方形で選択
│ ├── 注釈 ▶︎
│ ├── ブックマークを追加
│ ├── 反時計回りに回転
│ ├── 時計回りに回転
│ ├── 水平方向に反転
│ ├── 垂直方向に反転
│ ├── 切り取り
│ ├── プロファイルを割り当てる…
│ └── 位置情報を表示
├── ウインドウ
│ ├── しまう
│ ├── 拡大/縮小
│ └── すべてを手前に移動
└── ヘルプ
  ├── 検索
  └── プレビューヘルプ


「右クリック」
’’を調べる
Googleで検索
カット
コピー
ペースト
段階スタイル ▶︎
チェックリスト
チェック済みにする
共有 ▶︎
フォント▶︎
スペルと文法 ▶︎
自動置換 ▶︎
変換 ▶︎
スピーチ ▶︎
レイアウトの方向 ▶︎
スポークントラックトしてiTunesに追加
テキストを半角に変換



機能としてはメモどころじゃありません。しかも「▶︎」や「...」がついている項目はさらに深い階層に機能があるので、これは大変です。


心が折れそうなので、今日はここまでです。

2017年9月3日日曜日

JavaFXで画面遷移してみた件

JavaFXで画面遷移できるように実装してみました。Webアプリケーションでも画面遷移は勉強し始めの頃は大変困りました。そして今でも困ってます。

今回のアプリの仕様は3画面ほど作りまして、[前へ]ボタンと[次へ]ボタンで双方向に遷移できます。シンプルすぎて役に立たないアプリが完成しました。



     ↑        ↓



     ↑        ↓




さて、プログラムの構成はこんな感じです。
JDKは古いバージョンだとJavaFXは使えないので注意です。




今回はFXMLを使っていまして、ビューとコントローラは1対1になるようにしてます。

【Mainクラス】

public class Main extends Application {

    private static Stage stage;

    @Override
    public void start(Stage stage) throws Exception {
        Main.stage = stage;
        changeView("View0101.fxml");
        Main.stage.show();
    }

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

    public void changeView(String fxml) {
        try {
            stage.setScene(new Scene(FXMLLoader.load(getClass().getResource(fxml))));
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

画面遷移するにはStageに紐づいているFXMLファイルを切り替えてあげればいいだけでした。コントローラから画面遷移できるようにしたいので、ChangeViewメソッドを作成し、引数には遷移対象のFXMLのファイル名としました。




【Controller0101〜Controller0103クラス】の抜粋
    
    @FXML
    private void nextButtonAction(ActionEvent event) {
        new Main().changeView("View0102.fxml");
    }

ChangeViewの呼び出しはこんな感じになりました。

改善の余地がありそうですが、一旦完成です。

2017年8月27日日曜日

「DataSource が無効であるため、Connection を取得できません」の解決方法

NetBeansのサイト(https://netbeans.org/kb/docs/web/mysql-webapp_ja.html)にあるサンプルを見ながら、JavaからSQLを実行するプログラムを作成中です。

手順を間違えたのか、こんなエラーが出てしまいました。



exception
javax.servlet.ServletException: javax.servlet.jsp.JspException: DataSource が無効であるため、Connection を取得できません: "java.sql.SQLException: No suitable driver found for jdbc/IFPWAFCAD"

root cause
javax.servlet.jsp.JspException: DataSource が無効であるため、Connection を取得できません: "java.sql.SQLException: No suitable driver found for jdbc/IFPWAFCAD"


DataSourceについてはglassfish-resources.xmlで定義されてますが、記述内容に間違いなさそうでした。構成ファイルにちゃんと入ってます。



ん?構成ファイル??
サーバー・リソースじゃないの??



glassfish-resources.xmlをサーバー・リソースに移動させてみました。
それから、プロジェクトをデプロイしてみると、



JDBCリソースと接続プールに新しく追加されていました!


ちゃんと、サンプルどおりに表示されるようになりました。

2017年8月23日水曜日

MacでMySQLを使えるようにしておいた

MacにMySQLとMySQL クライアントのSequel Proをインストールしてみます。

はじめに、下のサイトからMySQL Community Serverをダウンロードします。
https://dev.mysql.com/downloads/mysql/

ダウンロードできたら、展開してします。


mysql-5.7.19-macos10.12-x86_64.dmgをダブルクリックします。


[続ける]ボタンをクリックします。




読めないので、[続ける]ボタンをクリックします。




[同意する]ボタンをクリックします。




[インストール]ボタンをクリックします。



インスールが意外と早く終わると、初期のパスワードが書いてあるダイアログが表示されるので、パスワードをメモっておきます。パスワードが分からなくなったら、マニュアル見ながらパスワードをリセットする作業が発生するようです。



[閉じる]をクリックして完了です。


ついでに、MySQLを起動させてみます。

デスクトップの左上にあるリンゴをクリック

システム環境設定をクリック

をクリック



[Start MySQL Server]をクリック




runnningに変わりました。
正常にインストールできたようなので、次は初期のパスワードを変更します。

ターミナルを開いてこんな感じでコマンドを入力します。

MacBook-Air:/ ユーザー名$ cd /
MacBook-Air:/ ユーザー名$ /usr/local/mysql/bin/mysqladmin -u  root -p password '新しいパスワード'
Enter password: 初期のパスワード
mysqladmin: [Warning] Using a password on the command line interface can be insecure.
Warning: Since password will be sent to server in plain text, use ssl connection to ensure password safety.
MacBook-Air:/ ユーザー名$ /usr/local/mysql/bin/mysql -u root -p
Enter password: 新しいパスワード
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2402
Server version: 5.7.19 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.03 sec)

mysql> exit;
Bye

MySQLのセットアップ終了しましたー

続いて、Sequel Proをインストールします。
下のサイトからSequel Proをダウンロードします。
http://www.sequelpro.com

ダウンロードしたDMGファイルをクリックします。



Sequel Proをアプリケーションフォルダにコピーして、Launchpadから起動できるようにしておきます。
起動してみると、接続情報を入力できる画面が表示されます。
接続情報は特に変更していなければ、内容は同じはずです。


















接続情報を入力したら、「接続をテスト」ボタンをクリックしてみます。
「接続が成功しました」が表示さればOKです。
「お気に入りに追加」ボタンを押しとくと、後々楽できます。
「接続」→左上の「データベースを選択」から選択すると、色々情報が見られるようになります。

次はJavaから接続とかやろうかなー

2017年8月19日土曜日

NetBeansのパレットの表示の仕方

結構、放置してたけど、今思い出したので更新。
NetBeansの公式ホームページにある「Java EEおよびJava Webの学習」を使って勉強中です。IDE標準装備のパレットの出し方をいつも迷うので、ここに書きつつ覚える作戦!



[ウィンドウ]→[IDEツール]→[パレット]です。

ショートカットは、Windowsだと[Ctrl]+[Shift]+[8]、Macだと[shift]+[command]+[8]です。
まぁ、どっちも似た感じですが。