ぼそっ(今日の独り言) 2024

メインページに戻る
1998 1999 2000 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025

謹賀新年

あけましておめでとうございます
今年もよろしくお願いいたします。

2024年01月01日 独り言

Jsoupの使い方がよくわかんない

このWebページを生成するプログラムをC++11以前の古いC++で作っていたのをjavaでjsoupを使って書き換えようという気分になって書き換え始めたのだけれど、jsoup自体初心者なので細かい問題にぶつかってばかり。
最初はjsoupでnodeとかdocumentとかelementとかの使い分けがわからないところからスタートしているのでjavadocっぽいドキュメントを頑張って読んでいました。
その後はxmlヘッダーやドキュメントヘッダーの付け方に悩み、今は改行の付け方に悩んでいます。
一応このページはXHTML 1.0 Strictで作っているので、改行は<br />なのですが、appendElement("br /")だと閉じタグが生成されて<br /></br />になってしまうんですよね。
appendElement("br")ならばならば閉じタグが作られず<br>だけが生成されるのに。
もしかしてjsoupでこれはxhtmlだとかhtml5だとか教えることができて、その辺の設定ができるとうまいことやってくれるのかしら?
(追記)やっとわかった。XHTMLだから、jsoupをhtmlモードではなくxmlモードで動かさなければならない模様。

doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml);

してからdoc.outerHtml();すれば良いんだ!
とりあえずXHTMLの骨組みはこんな感じで生成できそう

doc = new Document("");
XmlDeclaration xmlDecl = new XmlDeclaration("xml", false);

xmlDecl.attr("version", "1.0");
xmlDecl.attr("encoding", doc.charset().displayName());
DocumentType docType = new DocumentType("html", 
"-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");

doc.appendChild(xmlDecl);
doc.appendChild(docType);

Element html = doc.appendElement("html");
html.attr("xmlns","http://www.w3.org/1999/xhtml");
html.attr("xml:lang","ja");
html.attr("lang","ja");
Element head = html.appendElement("head");
head.append("<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\" />");
head.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />");
head.append("<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />");
doc.title("MyPage");
Element body = html.appendElement("body");

Element ddd = body.appendElement("div");
ddd.appendChild(new Comment("Comment Node"));
ddd.appendChild(new TextNode("TextNode"));
ddd.appendElement("br");
ddd.appendText("&");

doc.outputSettings().indentAmount(0);
doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml);

doc.outerHtml();

誰かのお役に立てれば。

2024年01月13日 プログラミング雑談

VSCodeでmavenでJUnitとかjacocoとか

割と最近までVisualStudioでC++の人だったのでjavaとかVSCodeとか、何かしようとするたびに壁にぶつかる今日この頃。
ググりまくりなのだけれど、右も左もわからない初心者なのでググるキーワードが多分不適切なのでしょう。全然情報が見つかりません・・・(涙)
VSCodeでExtension Pack for JavaとかMaven for Javaを入れて、簡単なコードを書いて、JUnitのテストコードを書いて実行してみてます。
コマンドパレットで"Maven Execute Commands..."で"install"を実行すると多分実行jarを作ってくれて、JUnitのテストを実行してくれて、カバレッジまで測ってくれるようです。ステキ。
そしたら間もなく
[WARNING] Rule violated for method com.segu.Index.addText(org.jsoup.nodes.Element, java.lang.String): complexity total count is 7, but expected maximum is 5
とか言われ始めました。
悪かったね! どうせ私のコードはスパゲッティだよ! とか思いながら、とりあえずcomplexityのmaximumを8とかにすれば良いんでしょ?ってことで、VSCodeのsettings.jsonとかに何か書けばいいんだろうなと思いながらググること何時間?。結局解決策がわからず、
[ERROR] Failed to execute goal org.jacoco:jacoco-maven-plugin:0.8.4:check
で"install"がエラーになってから手動でJUnitのテストを実行してました。
pom.xmlを見ると

<maximum>${jacoco.unit-tests.limit.method-complexity}</maximum>

という行があったので、method-complexityというパラメタ名でググったけれどわからず。
あきらめてcomlexityのチェック行をpom.xmlから全削除するという暴挙に出てERRORを回避して何日か過ごしました。
で、
別件でpom.xmlを見てたら

<jacoco.unit-tests.limit.method-complexity>5</jacoco.unit-tests.limit.method-complexity>

なんて行があるではないですか。なんだ、pom.xmlの中で上限値を設定してたのかよ!ってことで、ここで上限値を8とかにしたらWARNINGもERRORも消えてすっきり

で、さらに私の前に(多分客観的には低い)壁が出現するわけですよ
JUnitのテストはlog4jで何のテストを実行したかログを出力したいので、log4j2.xmlが見えるようにクラスパスを設定したいのだけれど、どうやったら設定できるかわからずに半日ググった結果、このサイトを見つけました。
いや、見つけたってなんだよ。VSCodeのMavenプラグインが設定してくれたpom.xmlにmaven-surefire-pluginって書いてあんだから、surefireのオフィシャル見に行くのは当然だろ!って気もしますが、わかんないことばかりでどこを見に行って何を読めばいいかわかんないんですよ....と言い訳しておきます。
私はプロジェクトのルートにlog4j2.xmlを置いているのでpom.xmlに次のように書けばよいみたいです。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>${maven-surefire-plugin.version}</version>
  <configuration>
    <additionalClasspathElements>
      <additionalClasspathElement>./</additionalClasspathElement>
    </additionalClasspathElements>
  </configuration>
</plugin>

数日経つと忘れちゃうんだろうなという事で記録を残してみます。備忘録かよっ

2024年01月20日 プログラミング雑談

javaで正規表現

このページをテキスト形式からhtmlに変換するプログラムはC++で2009年に書いたものです。
これをjavaでjsoupを使って書き換えようと思い始めて多分2週間。
機能実現検証用の試作が動きました・・・。
もう若くないので夜更かしはできないし、平日昼間は仕事だし、このwebページをjava版の変換プログラムで作るのは2月に入ってからかなぁ。
秀丸の置換とかsedとかgawkで正規表現を便利に使っていますがjavaの場合のやり方を少しメモ。

Pattern pattern = Pattern.compile("^[ \t]*&([^:]+):") ;
Matcher matcher = pattern.matcher(inLine);
if(matcher.find()) {
    if(matcher.group(1).equals("end")) {

とかすると、"&end:"が検出できる模様。Patternの行からfindの行までは1行で書けるので、それなりにすっきり書くこともできるのですね。
はまったポイントは数字とマッチする"\d"は"\"自身がエスケープ文字なので"\\d"と書かねばならないとか、find()まで実行しないとgroupが使えないところですかね。

2024年01月21日 プログラミング雑談

java版のこのwebページ生成ツール 仮運用開始

正月が明けてからテレビアニメも見ずにプログラムを書いていました。
タイトルの通り、今日からこのwebページのhtmlはjavaで作り直したプログラムで生成を開始しました。
ページの見た目はcssファイルの方なのであまり変わっていないはず。個々のアーティクルへのリンクは極力従来通りに生成できるようにコードを書いたので、htmlの方もhtml自体をテキストエディタなどで見比べない限り(見比べても)わからないのではないかな。
もちろん何もないところからwebページのhtmlが出てくるわけではないので原稿があります。原稿はテキストファイルです。今回java版を作って従来の原稿を流すまで気が付きませんでしたが、これまでShift-JISファイルを使っていましたが、今回はUTF-8 BOM無しのテキストファイルを原稿の文字コードにしました。
その他、原稿のリンクや箇条書きなどはマークダウン風の記法にしました。今まではいくつかの独自記法でコード記載ブロックを切り分けていましたが、その他は原稿にhtmlタグを書くというweb黎明期でもほとんどはやらなかったであろう地味な作業をしていましたが、これももう不要です。改行のbrタグすら手書きだったものなぁ。
今回取り入れたマークダウン風の記法は

あたりです。
いままでコード記載ブロックの処理にバグがあって空行が表示されていませんでしたが、これも表示されるようになったはず。しばらく気が付きませんでしたが、気が付いた時に空行ではなくスペース一つ入力して回避してたりしました。
htmlのエスケープ文字もjsoupが自動で変換してくれるはず。
コーディング上は、15年前のC++版でも途中まで単体テストを入れていましたが、コーティングが進むにつれてメソッドの複雑度が上がってテストを書くのを断念してしまっていました。それだけでなく15年の歳月の間に流行りのc++テストツールが世間的に交代してしまったようで、その意味でもテストを書いて動かし続けるのが困難な状態でした。
今回はメソッドのコード複雑度(サイクロマチック)5以下でここまで作り切っていますので、今度こそ単体テストを後付けで作っていけるはず。
たくさんコードを書いたようなつもりだったけれどかぞえチャオで数えたら1,500ステップもなかった

2024年01月29日 プログラミング雑談,このページのリフォーム

ページのレイアウトをいじってました

ページの見た目をマイナーチェンジしました。
パソコンで見たときに、中途半端なウインドウ幅にしたときにレイアウトが崩れるのを放置していましたが、私のところではちゃんと表示するようにしたのと、スマホで見たときに少し見やすい感じを狙ってみました。
今回いじったのはcssファイルが中心で、ブラウザのキャッシュをクリアしないと変更が反映されないかも。
PC(firefox、chrome)とChromeBook(chrome)ではまあ想定通りの表示になったけれど、スマホのchromeでなぜか右に余白ができて右スクロールができてしまうのがちょっと気になる。あとはスマホのchromeで縦スクロールがカクカクする感じ。私の今のスマホ、5年位経ってたっけ・・・
(追記)スマホで右スクロールになってしまう件、ログ出力の英文がブラウザからは一単語に見えて改行できず、長い長い1行で表示していたためだったようです。cssファイルに

word-break: break-all;

って書いたら直りました。

2024年02月03日 このページのリフォーム

サイクロマチック数 max 5の世界

久しぶりにプログラムを書くといろいろ勉強になりますね。
今回の一番の収穫はメソッドのサイクロマチック数をmax 5で作るのも良いものだ、という事を実感したことかもしれません。
最初はmavenの環境をチュートリアル見ながら構築したらデフォルトでそのような設定になっていたというだけなのですが、これがデフォルトという事は何か意味があるに違いないと思ってmax 5縛りで作ってみました。
最初に影響が出たのがswitch文。こんなの使うとあっという間にサイクロマチック数5を超えてしまいます。ファクトリーメソッドで処理を切り分けるようにしました。ファクトリーメソッドでもファクトリー部分で分岐が出ないようにArrayListとかに選択肢を詰め込んでおいてget(key)で探したりforeachで探したり。
次にif文の使用。メソッドの責務をシンプルにして、メソッドの上から下まで条件分岐なしでいかに流しきるか考えるようになりました。今回作っていたプログラムは、テキストファイルを読み込んでhtmlに変換して書き出すというシンプルなコマンドラインプログラムでした。メソッドの入り口で「入力ファイルを確認する」みたいなメソッドでチェックして、NGならエラーリターンし、その後の処理は余計なことは考えずに上から下まで一気に流す、みたいなスタイルになっていきました。

そのうちメソッドのサイクロマチック数 max 5はまあ普通に守れるようになってきましたが、次にクラスでmax 20という条件で引っかかるようになりました。メソッドが1つあればサイクロマチック数も最低1あるという数え方ですので、クラスのメンバー変数がいくつかあってsetter、getterを書き始めるとたちまち超えます。setter、getterは今回はあまり書かないで作ってみました。これが正しい対処法かどうかわかりませんが、
それよりも「もし入力ファイルが無かったら」はFileReaderクラスの責務、「もし入力ファイルの記載が間違っていたら」は処理するクラスの責務、みたいにクラスの責務を整理して、一つのクラスで処理しなければならないメソッドを減らすことに注力してました。
テキストファイルを読み込んだり、htmlをファイルに書き込んだりするのはhtmlを生成するクラスの責務ではないよね、ということで、ファイル読み書きは別クラスに切り出したり。

おかげで単体テストコードも書きやすいです。まだあまり書けていませんが、これまでコードの構造のせいでテストが書きにくいといった事には出くわしていません。
まだ単体テストを一通り書いていないのにこんなことを言うのもなんですが、単体テストってプログラマーの意図通りコードが書けているかどうかのテストなのだなぁと実感していました。単体テストが通っているのに出力されたhtmlファイルが意図通りではないことが頻発しています。これはplaywrightみたいなツールで結合テストするしかないのかもしれないですね

そうそう、サイクロマチック数とは関係ないかもですが、今回は(今回こそ)設計書をちゃんと書くぞと(まだ)思っています。DoxygenとかplantUMLとか使ってちまちま書いています。
私が飽きるのが先か、テストや設計書を作り切るのが先か、どうなるんでしょうね?

2024年02月04日 プログラミング雑談

jsoupで最初つまづいたところ

今度のお休みに書こうと思っていることをメモ
jsoupで私のwebページを書こうとして結構ずっと混乱していたのがappendChild()とappendElement()の使い方。

Element ddd = new Element("body");
ddd.appendElement("div").attr("name", "segu");

と書くことはできるけれど

Element ddd = new Element("body");
ddd.appendChild(new Element("div")).attr("name", "segu");

と書くと多分思ってたのと違う結果になる。
前者は<body><div name="segu">で
後者は<body name="segu"><div>になるはず。
jsoupのAPIリファレンスに書いてある通りだし、今考えるとこれが当然の挙動なのだけれど、その辺が理解できるまで思ったようなhtmlにならなくてだいぶ混乱してました

2024年02月08日 プログラミング雑談

rdfファイル生成もjavaに移行

テストはあまり書けていませんがrdfファイル作成もjavaのプログラムに書き換えました。
書き換えたと言ってもC++版のコードは見ていないのですけど。今回のjavaプログラム化は結局C++のコードは全然見ないで作ってしまいました

2024年02月10日 このページのリフォーム

xhtml 1.0 strict

プログラミングというよりこのページのリフォームの話題かな。
何度か言っていますが、このページはxhtml 1.0 strictで作っています。このたびページの見た目の不具合も解消したいなと思ってcssファイルの方も見直しました。ポイントとしてはスマホ重視に切り替えた感じです。
ついでにhtmlとしてあるべき感じにしたいなぁと、htmlの入門サイトで<div>ばっかりじゃなく<nav>とか<main>とか<header>とか使った方が良いと書いてあったので直しました・・・。そしたらxhml 1.0 strictのバリデータにErrorだって言われてしまいました。
あとはサイト外のページへのリンクにtarget="_blank"使ったらこれもダメ。
strictの道は厳しい

2024年02月11日 このページのリフォーム

3日なんてあっという間

jsoupについて何か書こうと思っていたけれど、gradleとかgroovyとかkotlinとか調べてたら土日が終わって、sonarQubeとかいうのの存在を知って使い方を調べて今回書いたコードをみてもらったら指摘がドバドバあって、月曜も終わってしまいました。

2024年02月12日 プログラミング雑談

javaの本

C++がある程度わかってきたら、書籍 プログラミング言語C++で勉強しなおすとすごくためになると思っています。
同様にjavaの場合にプログラミング言語Javaを読めばいいのかというと、なんか違う気がします。おとといの土曜まで知りませんでしたが、この本はJava 1.5までの内容しか書かれていないそうじゃないですか。せめて1.8のラムダとかメソッド参照とかstreamとか書かれていないといまどきのプログラミング言語として物足りないと思います。どおりでこの本をいくら調べてもメソッド参照について書かれていないわけだ!
昨日いろいろ書籍をググっていましたが、多分Effective Javaあたりから読むとよいのかなと。またはJavaによる関数型プログラミングかな。
他の言語も同様ではあるのですが、入門書はたくさんあるのですが、例えばif文を極力使わないでプログラミングしようとか、Exceptionをどのようなケースで使うのが良いのかとか、ファクトリーメソッドでどのタイミングでインスタンス生成すると良いのかとか、疑問は尽きません.
今からjavaを勉強しても勉強したことを生かしてプログラミングすることももう無さそうなんだけど。

2024年02月19日 プログラミング雑談

デザインパターンを勉強せずになんとなく使っているので説明できない

C++とかJavaとかで継承を学ぶと使いたくなるのがFactory Method。
その時はわかったような気分になるのですが、時々こんがらがってくるのでメモ。
「乗り物」を作る「工場」がある
「乗り物」は「自転車」もあれば「三輪車」もある。
「自転車」を作る「自転車工場」や「三輪車」を作る「三輪車工場」がある。

「乗り物」がProduct、「自転車」や「三輪車」がConcreteProduct
「工場」がCreator、「自転車工場」や「三輪車工場」がConcreteCreator

で、ここから先の正しい定義がいまだによくわからないのです。動的に、その時作りたい乗り物をswitch文などで切り分ける処理は何と呼べばいいのでしょう?
GoFの実装例ではCreatorクラスのCreator::Create()でMINEとかYOURESとかに応じて適切なProductをnewしているようです。
やっぱりちゃんとGoFのデザインパターンをちゃんと勉強しなきゃだな。もしかしてFactory Methodは適切なProductをnewするところまでで、どのように「乗り物」を作るかはAbstruct Factoryとかなのかしら。デザインパターンはつまみ食い状態だから全体像がつかめていない・・・

2024年02月23日 プログラミング雑談

Java AutoValueの私的なメモ

Effective Javaで今更ながらJavaを勉強中
最初の方の章でdataクラスを作るならequalとかちゃんとやらなきゃだめだよとか書いてあるみたい。自分で定義した値クラスを比較してないなら問題ないんでしょ? と思いながら、ちょっとお試し。
githubのAutoValue
detailed documentationをまるっとコピーしてしまうと、コード側の使い方はこんな感じらしい。@AutoValueというアノテーションを書くこととabstractクラスにすることがポイントらしい。インスタンス生成するためにabstractじゃないクラス名が必要だからcreateメソッドも必要ってことかな。

import com.google.auto.value.AutoValue;

@AutoValue
abstract class Animal {
  static Animal create(String name, int numberOfLegs) {
    return new AutoValue_Animal(name, numberOfLegs);
  }

  abstract String name();
  abstract int numberOfLegs();
}

mavenの場合pom.xmlには次のように書くみたい。${auto-value.version}は適切なバージョンに置き換える。

<dependencies>
  <dependency>
    <groupId>com.google.auto.value</groupId>
    <artifactId>auto-value-annotations</artifactId>
    <version>${auto-value.version}</version>
  </dependency>
</dependencies>

これだけだとAutoValue_Animalなんてクラス知らないって言われるので次の記載も必要みたい

<build>
  <plugins>
    <plugin>
      <artifactId>maven-compiler-plugin</artifactId>
      <configuration>
        <annotationProcessorPaths>
          <path>
            <groupId>com.google.auto.value</groupId>
            <artifactId>auto-value</artifactId>
            <version>${auto-value.version}</version>
          </path>
        </annotationProcessorPaths>
      </configuration>
    </plugin>
  </plugins>
</build>

これでビルドするとtarget/generated-sourcesの下にAutoValue_Animal.javaが作られる。
私はたいしてjavaのコードを書いていないからこれまでこういうことを知らなくても実害はなかったけれど、コンテナに自作クラス(のインスタンス)を入れて何かさせる場合はequalとかちゃんと作らなきゃならないようなので、今は実害が無くてもちゃんと作る習慣を今からつけていかないと将来発見が難しいエラーを作りこんでしまうって事だろうな。

2024年02月24日 プログラミング雑談

匍匐前進

今年作っていたjavaのプログラム、VSCodeでMavenを使っていましたが、gradleも使ってみたくて。

VSCodeなのでGradle for Javaのプラグインを入れて、コマンドパレットで"Create a Gradle Java Project"でKotlinでJUnit5だったかな、そんな感じで選んでプロジェクトを作成。
もう一歩進むたびにやり方をググって・・・
依存パッケージの設定はbuild.gradle.ktsに

dependencies {
    // This dependency is used by the application.
    implementation("org.jsoup:jsoup:1.17.2")
    implementation("org.apache.logging.log4j:log4j-api:2.22.0")
    implementation("org.apache.logging.log4j:log4j-core:2.22.0")
}

とか書いて、VSCodeの左の象のアイコン→Tasks→build→buildしたらエラー。
どうやらbuild.gradleを更新したらUpdateする必要があるみたい。Mavenの時はpom.xmlを更新すると更新しますかみたいなメッセージボックスか何かが出てUpdateされていたみたいですが、まだ私の環境はbuild.gradleを更新しますかみたいなメッセージボックスか何かが出ているのですが反映されていないみたい。(追記)JDKとJREをインストールしなおしたら解決しました
とりあえずVSCodeを終了して立ち上げなおせば反映される。

Javaのソースファイルとテスト用データファイルを一式コピーしてbuild。今度はコンパイルが通ったけれど今度はテストでエラー。Webページのhtmlファイルを作るプログラムなので、生成したファイルの中の文字をチェックするのだけれど、UTF-8の文字列にもかかわらずShift-jisのつもりで比較している模様。UTF-8のソースファイルなのにShift-JISとしてコンパイルされているみたい。文字コードが誤認識されていてもビルドが通るとは恐るべし
VSCodeのエクステンションの設定かしらと思ってEncodeとか頑張って探すけれど設定する箇所が見つからない。
いろいろググってたらbuild.gradleで設定するらしい。このサイトの記載をそのまま使わせていただきました。

tasks.withType<JavaCompile>().configureEach {
    options.encoding = "UTF-8"
}

すっかり忘れていたけれど、Mavenの時はpom.xmlに

  <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

みたいなのを書いた気がします。

VSCodeのjavaのプラグイン(?)でCreate Java Project→Maven→archetype-quickstart-jdk8とかで入ってくるcheckstyleとかjacocoとかはまだどうやったら使えるのかわからないし、log4jもまだlog4j2.xmlにパスが通っていないみたいでログが出てこないし、しばらくは前途多難な匍匐前進なのだな
でもググれば何かわかるというのは実に助かります。良い時代ですね。

2024年03月02日 プログラミング雑談

javaでifを使わずにnullじゃなかったら実行する

javaでもC++でも良いのですけれど、コードを書いているとnullチェックのif文が並んで、なんだかなぁ、と思うことが多いです。
例えばjavaで次のような感じ。クラスAaa、Bbbなどは省略します。

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < args.length; i++) {
            create(args[i]);
        }
    }

    private static void create(String devName) {
        Map<String, Supplier<Xxx>> factory = new HashMap<>();
        factory.put("A", Aaa::new);
        factory.put("B", Bbb::new);
        Supplier<Xxx> sup = factory.get(devName);
        if (sup != null) { // ★
            Xxx xxx = sup.get();
            System.out.println(xxx.getProduct());
        }
    }
}

factory.get()のところをgetOrDefault()使ってnullが返らないようにする手もありますが、このケースでは本来エラーになるケースでsup.get()で無駄なインスタンスを生成してしまうのでいやだなぁと。
もう20世紀じゃない。javaでNullじゃなければ実行する、みたいなスマートな方法があるはず。どう調べればよいかわからないのでたどり着くのに時間がかかりましたが、こんな方法があるようです

    private static void create(String devName) {
        Map<String, Supplier<Xxx>> factory = new HashMap<>();
        factory.put("A", Aaa::new);
        factory.put("B", Bbb::new);
        Optional<Supplier<Xxx>> optxxx = Optional.ofNullable(factory.get(devName));
        optxxx.ifPresent(sup -> System.out.println(sup.get().getProduct())); // supにoptxxxが入る
    }

java.util.Optionalを使ってofNullableで「この変数、nullかもしれない」と申告しておいて、ifPresentで「もしnullじゃなかったらヨロシク」ってことらしい。
このコードではifPresentで実行までしていますが、生成したインスタンスを返して戻り先で実行させるならこんな感じ。「nullかもしれない」値をOptionalに入れて処理して、最後にorElseでインスタンスを取り出すみたい。

        Optional<Supplier<GenHtml>> maker = Optional.ofNullable(factory.get(htmlMode.toLowerCase(Locale.getDefault())));
        Optional<GenHtml> makerMethod = maker.map(zz -> zz.get());
        return makerMethod.orElse(null);

最初の方の例はこのページに書くためにでっち上げたコードだったけれど、こっちは自分のコードからコピペ。
多分読み慣れればifでnullチェックするよりも読みやすくなるのでしょうね。

問題というほどの問題ではないのですが、ifPresentやmapの中でラムダ式を使うのでjacocoではサイクロマチック数を一つ使ってしまうのですよね。Optionalの処理をメソッドにして追い出してしまうとかいう使い方を想定しているのでしょうかねぇ。

2024年03月10日 プログラミング雑談

どこまでも文字コードが付きまとう

javaでgradle使ってプログラム作るの第2弾。poiでexcelファイルを作る。

cell.setCellValue("日本語文字列");

ってやったら文字化けした。
poi側で何か文字コード設定があるのかと思ってググるのだけれどあまりヒットしない。日本語フォントを設定すれば文字化けが直るとか書いてあるサイトもあったけれどフォントを指定しても直らない。
しばらく悩んで

System.out.println("日本語文字列");

したらこっちも文字化けした(笑)
そうだった、build.gradle.ktsに

tasks.withType<JavaCompile>().configureEach {
    options.encoding = "UTF-8"
}

って書いてUTF-8でビルドしなきゃならないんだった

引き続き、
Excelのxlsxファイルを読み込んで条件付きで文字色を変更して別ファイルに保存させるプログラムを書こうと四苦八苦。OPCPackageってなんだかわからないけれどpoiのサイトのサンプルのコピペで

OPCPackage pkg = OPCPackage.open(new File("indata.xlsx"));

って書いてファイルを読むと読み出ししたいだけなのにファイルが何か更新されてしまうみたい。結局

XSSFWorkbook wb_r = (XSSFWorkbook) WorkbookFactory.create(new File("indata.xlsx"), null, true);

って書いて解決。create()の3番目の引数がread onlyにするフラグらしい。
でもなんか別ファイルを作って保存ってpoiではセル一つ一つを別ファイルにコピーする必要があるみたいで面倒らしい。poiの新しめのバージョンではメソッド一つでシートごとコピーできたりしないのかな・・・。後で調べてみる。

2024年03月20日 プログラミング雑談

ChromeBookってLinuxマシンだったんだな

AndroidでもiPadでもいいから電子書籍リーダーや動画プレイヤーとして使えるタブレット端末がほしいと思って購入したキーボード分離型のChromeBook。
購入前の下調べで開発者モードにするとLinuxが使えるとかVisual Studio Codeすら使えるとか知りましたが、Androidアプリが使えればそれで十分かなと思っていました。
ところが、物理キーボードが意外と打ちやすいし、かなキー入力が普通にできる事がわかって、これは携帯用のテキスト入力マシンとして使える! 私の予備のWebページ更新用端末にしたいという誘惑に囚われてしまいました。
ChromeBook購入とは関係なく、これまでC++(クラスと継承が使えるC言語のレベル)で作って使っていたhtml生成用のコマンドラインアプリをjavaで書き換えましたので、これをAndroidアプリにすれば・・・と考えて、PCにAndroid Studioを入れてjavaのコマンドラインアプリにAndroid用のUIでくるむことを検討してみました。多分一週間くらいちゃんと勉強すれば作れそうな気がしました。
でも今はちょっとAndroidアプリ作成の勉強をする時間が確保できない(今はjavaで自分で納得できるレベルのアプリが書けるようになりたいということで勉強中なので)ので、ChromeBookの開発者モードにjreを入れて、現時点のjavaアプリをそのまま使っちゃえばいいじゃんという発想に至りました。
前置きが長くなりましたが

で数分でLinuxの環境ができてしまいました。
前提知識を持っていなかったので、開発者モードってChromeBookの普通の環境を動かしている土台のLinuxを公開するモードなのかなと思っていましたがもしかしてChromeBookのOSの上で動く仮想OSとかコンテナなのかも。このあたりはおいおいググって調べてみようと思います。
Linuxのシェルが開きましたので、最初はlsコマンドなどが動くことを確認。ChromeBookのメニューに「vim」とか出てきたので起動してみると本当にvimっぽい。

java --version

と打ってみましたがjavaなんて知らないって言われてしまいました。
ググってみましたら

sudo apt-get install default-jre

でjreが入るようです。

$ java --version
openjdk 17.0.10 2024-01-16
OpenJDK Runtime Environment (build 17.0.10+7-Debian-1deb12u1)
OpenJDK 64-Bit Server VM (build 17.0.10+7-Debian-1deb12u1, mixed mode, sharing)

PCで動かしているhtml生成のコマンドラインアプリを持ってきて動かしてみましたら、無事動きました。

2024年03月29日 ChromeBook CZ1000DV

エレコムの安いキーボード(5年経過)の潤滑化メンテ

職場であてがわれたパソコンのキーボードが"X"の下にaltキーがあって"Z"の下にWindowsキーがある極悪なキー配置だったので苦情を言って変えてもらったのだけれど、それもなんかイマイチだったのでBYOD。
別にRealforceやメカニカルのキーボードにしてほしいと言っているわけではなくて、結局使っているのはエレコムの安いキーボードであるところのTK-FCM103XBK。今Amazonで見たら830円だった。安い。
さすがに5年も使っていると打鍵感にひっかかりが出てきて、しばらくキーボード欲しい病を発病していました。

自宅ではFILCOのメカニカル。茶軸の打鍵感が心地よくて15年位前だったかにヨドバシの店頭で一目惚れして購入。その後、今から5年前に今使っている茶軸のコンパクトタイプのキーボードに変えました。Realforceも何度も検討したのですが、どうも打鍵感にワクワクを感じなくて。店頭で触った感じはキーに引っ掛かりも感じず滑らかでいいのですが、なんだろう、メカニカルのCherryの茶軸と比べて押し始めのラバーカップ感とでも言えばいいのか、モニョっとした感じが、何万円も出して買うキーボードではない感じがしてしまっています。
ラバーカップの打鍵感も千円前後のキーボードならば許容範囲。でも冒頭に書いたように5年も使っていると打鍵感に引っ掛かりが出てきて、滑らかな打鍵感に憧れてRealforceやメカニカルのキーボードを家電量販店の店頭で感触を確かめながら、2万円とか3万円とかの値札を見て購入をためらっていました。キーボードは商売道具でもあるのでケチりたくはないのですけれど、値段分の価値を感じられなくて。
ってことで(前振りが長い)、結局またエレコムの安いのを買ってしまいました。TK-FDM105TXBK。ワイヤレスで1,280円だったので。うん。打鍵感に引っ掛かりもなく良い感じ。これで十分。
私のキーボードの嗜好は、必須の条件はシリンドリカルのキートップで左altキーが標準的な位置にあることだけかもしれません。テンキーがあるとマウスが遠くなるのでテンキーレスとかコンパクトタイプのものを最近は選択してしまっています。あったらいいな、くらいの条件が、打鍵感やなんちゃってでいいのでステップスカルプチャ。最近はHomeキーやEndキーもよく使うのであまり特殊なキー配置は敬遠してしまいます。

で、今まで使っていた打鍵感に引っ掛かりが出てきたキーボード、ググったところルブと呼ばれているらしい、グリス類で打鍵感を改善することにトライ。
ググって見かけたのがメカニカルキーボードのキースイッチを分解してグリスを塗ったり、メンブレンキーボードの可動部にシリコンスプレーする方法。私は電気接点があるメカニカルキーボードに絶縁性の何かを塗るとか怖くてできません。シリコンスプレーはメカニカルキーボードを使い始める前にメンブレンのキーボードで試したことがあります。その時の記憶は、打鍵感の引っ掛かりは解消するのですが動きに液体っぽい抵抗感が感じられてイマイチというもの。
今回は何年か前に鍵穴の潤滑用にフッ素樹脂スプレーを入手していますので、フッ素樹脂スプレーで打鍵感の潤滑化に挑戦。鍵穴があんなに滑らかになるのだもの。きっとキーボードにも効果があるに違いありません。シリコンスプレーよりずっと高価でしたが、スプレー後すぐに乾いてサラサラ感があるのでシリコンスプレーと違って液体っぽい抵抗感も無いに違いない。
ところがTK-FCM103XBKってキーキャップを引っ張ってもキーが抜けない。Y字型の特殊なネジが使われていて分解もままなりません。830円で買えるキーボードの打鍵感改善のために900円超のフッ素スプレーと500円弱のY字ドライバーか・・・と思わないでもありませんが、今回新規購入したのはY字ドライバーだけなので気にしない。これでもホームセンターを3件まわってやっと見つけた安価なY字ドライバーだったりします。地元のホームセンター、コメリで購入。ホームセンタームサシには確か千円超だったけれどもっと太いタイプのY字ドライバーがあったような気がします。どうも話がすぐにわき道にそれますが・・・。
キーボードの裏ブタのネジを外します。このキーボード、ラベルのシールの下にネジが隠されていないあたり構造が良心的。ACアダプターとかいくつか分解したことがありますがラベルのシールの下にネジが隠れているのがデフォルトだったので、少し覚悟をしていたのですが、ラベルをはがさなくてよくてちょっとうれしい。
裏ブタを外すとキーの部分とメンブレンのシートと裏ブタに分かれます。キーの部分はひっくり返してもキートップが外れない構造。新聞紙を広げてキーの部分をひっくり返して置き、可動部にフッ素樹脂スプレーを吹きかけました。しっとりした感じになり、気化熱でキーボードがひんやり。可動部にスプレー液がちゃんとつくようにキーをカチャカチャ動かして、乾燥するのを待ちます。少し白っぽくなるのはこのスプレーの特性。どうせ見えなくなる部分なので気にしない。
有機化合物っぽい異臭が室内にこもるので外は暴風雨の夜でしたがやむなく窓を開けて換気します。
キーボードを組み立てて打鍵感を確認。引っ掛かりが解消。液体っぽい抵抗感はなく、ラバーカップの特性がダイレクトに感じられる打鍵感。キーを押したときのモニョっとした感じがRealforceっぽい。830円のキーボードでこの打鍵感ならお値段以上の価値がありますよ、これ。
でもやっぱり私はメカニカルの柔らかいバネっぽい押し下げ感の方が好きだわ。
そういえばせっかくねじを外したんだから標準的な+ネジに付け替えれば良かった。どうせM3くらいの安いので大丈夫だろうし。
フッ素樹脂スプレーは呉のドライファストルブ、Y字型のドライバーはSUNFLAGのNo.17-Cでいけました。No.17-Cはネジに合わせてみるとちょっと細い感じなので、3mmくらいのサイズのがあると良いと思いました。

2024年03月30日 エレコム廉価版キーボード TK-FDM105

エレコムの安いキーボードの潤滑化メンテ手順

キーボードをいわゆる「ルブ」したいと思いながらしばらく踏み切れなかったので、同じように踏み切れない人の背中を押すつもりで、エレコムの安いキーボードTK-FDM105TXBKの潤滑化について書きます
キーボード外観

用意するもの

Y字型のドライバーはSUNFLAGのNo.17-Cが近所で安かったのでこれを使いました。
SUNFLAGのNo.17-C
ネジの溝部分のサイズが2.2mm向けのドライバーのようです。これでもエレコムのキーボードのネジは回せましたが、もっと大きなドライバーが好ましいと思います。多分3.0mmくらいあった方が良いと思います。

潤滑用のスプレーは呉のドライファストルブを使いました。
ドライファストルブ

分解

ネジの場所は赤く丸をつけたところです。水抜きの穴もあるのですべての穴にネジが入っているわけではありません。

ネジの場所
ちゃんと力を入れてドライバーを押し込む感じでネジを回す必要がありました。サイズが合ったドライバーならそれほど気を使わなくても良いと思います。

裏ブタと表のキーボード側の分離はキーボード側に3箇所小さな爪がありますので、爪の場所は裏ブタ側を外に押し広げる感じで外すと良いでしょう。
爪の場所

ネジはこんな感じ
ネジ
Y字のネジを一般的な+ネジに付け替えたくて近所のホームセンターに行きましたが同じサイズのネジは置いていませんでした。タッピングネジで鍋タイプの3x8よりは1mm位短くて、3x8の先端1mm位を切り落とした感じに見えます。
(追記: B0型タッピング ナベ M3×7 になるみたい)

中の構造

キーボード部分を外した裏ブタ側はこんな感じ。
裏ブタ側
メンブレンの白いシートは有線タイプのTK-FDM103と同じものだと思います。メンブレンのシートと右上の基板は3つのネジで圧着させる構造。この基板を有線タイプ、無線タイプ、Bluetoothタイプで使い分けるのでしょう。ちょっと高価なBluetoothタイプでメンブレンのシートが接触不良を起こしたら安い有線タイプを買ってきてシートだけ入れ替えれば使えるのではないかな。購入時期が何年も違うと中身が微妙にバージョンアップして互換性が失われているかもしれませんので積極的におすすめはしませんが。そうでなくても5年使った私のキーボードは、今回買い足して気が付きましたが、キートップがツルツルになっていたり左手親指の腹があたるキーボード下部がすり減っていたりしましたので、数年使ったのならば修理とか考えずに買い替えた方が良さそうです。2万円超のRealforceだと10年位使いたいかも?

キーボードの裏側、キートップの取り付け部分
キーの裏側
キートップは筐体に爪ではまっている構造です。キートップを引っ張っても抜けないように作られているのですね。
キーを押し込むとこんな感じ
キーを押し込む

スプレー作業

キーを押し込むとキートップと筐体の接触部分が露出しますので、ここにドライファブのスプレー液を付着させる感じで作業しました。作業時はキーを押し込まなくても筐体をひっくり返して広げた新聞紙の上に置けば自然とキーが押された状態になります。スプレー付属のストローを溝のように見える隙間に差し込んで、スプレー液で濡れようにします。
ルブのターゲット
気にしなくても良いのかもしれませんが、液がちゃんとキートップと筐体の接触部分にまんべんなく付着するように、キー4つくらいずつまとめてスプレーして、乾く前に手でキーをカチャカチャ押し込んでました。キートップが気化熱でひんやりすると、キートップにも液がちゃんとついてるんだなと安心できる感じ。
どのくらいの量をスプレーするのが最適かわかりませんが、キーボードの引っ掛かり感が解消していれば目的は達成できているのでヨシとしています。

天候などの関係で可能ならば屋外、せめて窓を開け放った室内で作業することをお勧めしておきます。有害物質は使われていないと思いますが、ちょっと溶剤っぽいにおいが気になるので。

組み立て

スプレー液がちゃんと乾くのを待って、キーボードを組み立てます。
呉のドライファストルブは乾くと白くなります。ところどころ白い汚れが付着したかなって感じになります。まあ組み立ててしまえば見えないところですので気にしません。
あ、白くなった写真を撮り忘れました・・・。

効果

PCに接続して試し打ち。
気のせいかもしれませんが打鍵音のカチャカチャの高音部が少し静かになった気がします。
押下感は滑らか。わざと斜めに押し込もうとしてもキーの引っ掛かり感はありません。(昔、斜めに押し込んでも引っ掛かりが無いパンタグラフタイプのキーボードが好きだった時期がありました)。メンブレンのラバーカップの変形する感触なのだと思いますが、押し始めがクニュっとして一番重い感じ。このクニュっとした感触がいまいち好きになれなくて、メカニカルのキーボードの方が好みなんだと思います。とはいえ職場で支給されたキー配置レベルでダメダメなキーボードに比べれば、このキーボードは十分ハッピーです。
あと、これも気のせいかもしれませんが、スプレー前よりもキーが重くなった?
今回は1週間くらい使ったくらいのほぼ新品に潤滑スプレー処理をしましたので劇的な改善はありませんが、斜めに押し込もうとしても引っ掛かり感はありませんので私の変な打鍵癖でキーが引っかかって入力されない(特にshiftキー)は改善されると思いますし、これだけ滑らかな打鍵感ならば高価なrealforceは私にはいらないと思いました。キーボード欲しい病がほぼ治りました。少なくともrealforceは欲しいものリストから削除されました。(茶軸のメカニカルはまだちょっと魅力的なのですけれどね)

2024年04月06日 エレコム廉価版キーボード TK-FDM105

Android StudioをJavaで使うときライブラリのjarはどこに置くの?

私のWebページのスタティックhtmlファイルを生成するjavaプログラムをAndroidアプリ化しようとトライ中。
ググっていると広告ばっかりでイライラしてくるので入門書を購入。
あら、でもAndroid Studioでjavaのライブラリjarをどうやったら使えるか書いていない本を買ってきてしまったみたい。
(1) プロジェクトのviewでappフォルダ右クリック → New → Directory でlibsフォルダを作成
(2) エクスプローラーアプリからjarファイルをドラッグしてきてAndroid Studioのプロジェクトのviewの今作ったばかりのlibsフォルダにドロップ
(3) Copyするファイル名とフォルダを確認するダイアログが出るのでOKで閉じる
(4) プロジェクトのviewでCopyしたjarファイルを右クリック → Add as Library → Addするモジュールの確認ダイアログがでるのでドロップダウンリストから選択。デフォルトで良いみたい。
するとbuild.gradle.ktsに「implementation(files("libs\\jsoup-1.17.2.jar"))」みたいな行が追加されて、ライブラリが使えるようになりました。

jsoupはこれで使えたけれど、log4j2が実行時にエラーになる。まだAndroid Studioの使い方が全然わかっていないのでどんなエラーか把握できていないしどうやってデバッグすればいいかも勉強中。そもそもlog4jの使い方もわかっていないのでlog4jの使い方をちゃんと読めばいいのかな。

2024年04月07日 プログラミング雑談

実行可能jarを作る

javaのCLIでの実行jarの作り方を覚えてられないのでメモ
マニフェストファイルを作ります。

Manifest-Version: 1.0
Class-Path: .
Main-Class: com.my.App

classフォルダで

jar cvf [作りたいjarファイル名] [classファイルが入っているフォルダ名。例えばcom]
jar uvfm [作ったjarファイル名] [マニフェストファイル名]

2024年04月08日 プログラミング雑談

OpenJDKでJavaFXを使う

新しいバージョンのJavaが使えると限らないけれど、Java 8くらいならばどこでも使えそうな気がするので私が書いているJavaプログラムはターゲットをJava 8にしています。
OracleのJREはJava 8でもバージョンに気を付ければ使えるけれど、JDKはOracleのアカウント登録が必要で使いにくいのでOpenJDKを使っています。
今回買ってきたJavaの本はGUIアプリでJavaFXを使っているので本のチュートリアルに書いてあるHello World!をポチポチ入力。でもjavafx.application.Applicationがimportできない。この本はOracleのJDKをインストールしている前提なので、JavaFXなんて使えて当たり前でしょ? みたいなノリで全く説明なし。
いろいろググった結果、JavaFXを使うならばAmazon CorrettoにはJavaFXが入っているので簡単なようです。
adoptiumのOpenJDKをアンインストールしてCorrettoを入れてみました。とりあえずチュートリアルのJavaFXのHello World!はあっさりコンパイルできて動きました。

JavaのUI、Swingならばたいていどこでも使えるだろうと思ってちょっとHello Worldを動かしたことがありますが、Windowsのディスプレイの拡大/縮小はプログラマが意識してコードを書く必要がありそうで、私の200%拡大設定ではUIが小さくてなんだかなぁと思っていました。JavaFXはディスプレイの拡大/縮小の設定が効いているように見えますし、ファイル選択のコモンダイアログもWindowsのを使えているみたいなので良いかも。
ChromeBookでもJavaFXは使えるかな?
jarを作ってChromeBookに持って行ったけれど動かない。javaFxが入っていないのかな。

sudo apt-get insatll openjfx

しても"Package 'openjfx' has no installation candidate"って言われてインストールできませんでした。

2024年04月08日 プログラミング雑談

Androidアプリでlog4j2が使えない

自作javaアプリをAndroidアプリに作り替えようとしているのですけれど、使っているライブラリ、jsoupとlog4j2のうちjsoupはAndroidでも使えそうなのですけれどlog4j2の方はビルドすらできませんでした。
ちゃんとエラーメッセージを見たらlog4j2のパッケージのjarにMETA-INF/DEPENDENCIESというファイルがあるのがダメらしい。このファイルをjarから削除したらビルドだけは通るようになりました。
でも、Androidアプリで使おうとするとエラーになってダメなのは変わらないのですけれどね。ファイルに書き込もうとするときに何か制限があるのかしら。Androidアプリに関しては初心者未満だから手も足も出ない感じ。

2024年04月10日 プログラミング雑談

原稿ファイルにinclude機能を追加してました

毎回同じことを言っていますが、このwebページはテキストファイルからスタティックのhtmlファイルにプログラムで変換しています。
だいたい一つのテキストファイルが一つのhtmlファイルに相当しますので、indexページ(トップページ)と過去ログページと話題ごとのまとめページ、例えばプログラミング雑談に同じ文章をコピペしていました。これが地味にめんどくさかったので原稿のテキストファイルに別ファイルをincludeできるように機能追加してました。
原稿テキストファイルにincludeするファイル名を書いておいて、includeファイルが見つかったら挿入するだけの話なんですけれど、includeするファイルは原稿テキストファイルの相対パスにしておかないとユーザーの使い勝手が悪いし、このプログラムは将来Androidにもっていきたいので絶対パスはどうも使わない方が良いらしい。ってことで

Path currentFile = Paths.get(原稿ファイル名);
Path includeFile = Paths.get(includeファイル名);
String includeFileString = currentFile.resolveSibling(includeFile).toString();

でincludeファイル名を処理してから読み込んでいます。
html生成プログラム実行時のカレントフォルダは原稿ファイルと別フォルダですけれど、原稿ファイルとincludeファイルは同じフォルダという条件では今のところこのコードで動いています。原稿ファイルとincludeファイルが違うフォルダのケースはまだテストしていないので、テストしなきゃなぁ・・・

2024年04月20日 プログラミング雑談

SCR3310-NTTComがWindows 11で使えなくなってた

引き出しの奥からSCR3310-NTTComが出てきた。
どれどれ、動くかなと思ったら動かなかった。
ググったらWindows 11には非対応だそうだ。多分後継機種はSCR3310V2.0
買ってくればいいのだろうけれど、年に1回しか使っていないような気がする。マイナンバーカードもスマホで認識させればPCのカード読み取り装置は使わないし、後継機種を買ってくるのもなぁ
いろいろググった結果、
Windowsで設定→プライバシーとセキュリティ→Windowsセキュリティ→デバイスセキュリティ→コア分離→メモリ整合性 を オフにして、SCR3310のデバイスドライバーをインストールすればSCR3310が使えた
用事がすんだらドライバーをアンインストールして、メモリ整合性をオンに戻して・・・、あれ? オンにならない。
妨げているデバイスとしてSTCFUx64.sysってやつが表示される。そのファイルをアンインストールすればよさそう
管理者権限のコマンドプロンプトで

pnputil /d oem??.inf

とかやれば良いみたい。

2024年04月29日 独り言

オーバーグラスはカッコ悪いけどまぶしくない

昼間散歩していると日差しがまぶしくて目が開けてられません。
帽子をかぶってメガネに日光が当たらないようにしていますし、もちろん目に日光が当たるわけではないのですが、景色がまぶしくて。
1時間とか外にいると目の調子がおかしくなって、どこにもピントが合わなくなる感じになったりします。
視力が悪いので度付きサングラスとか作らないとダメかなと思っていましたがメガネの上にかけることができるオーバーグラスとかいうのを教えてもらいました。
スポーツ用品店やホームセンターに行ったらサングラスと並んで何種類かありました。サングラスと違っていろいろなものから選べるわけでもありませんでしたが、とりあえず比較的お手頃価格でサングラスによる紫外線カットで目の不具合が改善されるかどうかお試しできるので買ってきました。だいたい3千円くらい。
買ってきたのはこんなの。
オーバーグラス
レンズ部分の色はグレーっぽいののほかに茶色っぽいのと青っぽいのが選べましたが、私が探した範囲ではデザインとかは選択の余地なしでしたね。
いつもかけている眼鏡は遠近タイプの大きい眼鏡なのでメガネの上にオーバーグラスをかけることができるか心配でしたが、店頭展示品で試した感じは問題なさそう。
オーバーグラスをかけて自撮りしてみましたが、絶望的にカッコ悪いです。かっこいい普通のサングラスをかけても年齢が年齢なので、カッコ悪いオーバーグラスは身の丈に合った選択という気もします。
で、使ってみた感じですが
超日差しが強い日というわけではありませんでしたが目が普通に開けてられる! これはうれしい。後日普通に日中の散歩に使ってみます!

2024年05月26日 独り言

Androidアプリ化

最近少しAndroidプログラミングの本を読もうというくらいに気分は上向き。時間帯が時間帯なので本を開くと眠くなるのはしかたがないとしても、数ページ読み進んだだけ。
そんな状況ではありますが、気が向いたので、このwebページのhtml作成環境をAndroidアプリ化に着手しました。
事前確認でjsoupはAndroidに持ってこれそうだけどLog4j2は持ってこれないことがわかっていましたので、Log4jを外してAndroidのLogに置き換えて、あとは野となれ山となれ。
意外と無修正でなんか動きました。
動いたと言ってもファイル周りはなんか調子が悪いです。
Androidのインテントで入力ファイルを選択するとUri形式でファイルが取得され、いわゆるファイル名文字列で取得する方法がわからない。
このあたりはAndroidプログラミングを勉強すれば解決できるようになるのかな。とりあえずUri形式のファイル名を無理やり文字列置換でファイル名のように変換して動かしています。

2024年06月09日 このページのリフォーム

Androidアプリ化、とりあえず版

先週はフォルダを決め打ちしてこのwebページのhtmlファイルを生成するプログラムを仮に動く状態にしました。
PCでjavaで作っていたときはFileクラスとかでファイルにアクセスしていましたが、Androidの場合はAndroidのUriクラスでファイルにアクセスする必要がある模様。
Uriからファイルパスやファイル名を取得する方法が無いものか一週間ググりまくりましたが見つからず。休日になったので少し腰を据えて、まだあまり読み進んでいなかった入門書を読んだりAndroidのAPIリファレンスを読んだりしてました。
どうもFileではなくUriを使うのはセキュリティ対策の模様。Uriからフルパスのファイル名に変換するのはすっぱり諦めるのがよろしいようです。
ということでjavaで作ったプログラムをUri前提のAndroidプログラムに書き換えることにしました。
UriからInputStreamでファイルを読み込むように変更した時に一番困ったのがファイルにファイルをincludeするところ。Uriだとファイルがどのフォルダに存在するか全くわからないのでincludeしたいファイルもどこにあるかわからない。
今回は入力ファイルが存在するフォルダを設定するUIとそのフォルダからファイルを選択する処理の2段階でファイルを選択することでinclude処理で読み込み先のフォルダを特定するようにして回避しました。

今日の分の更新はスマホで文章を入力してhtmlへの変換、FTPでサーバーにアップロードまで全てスマホでやってみるつもり。
bluetoothのキーボードをこの前買ってきたから文字入力はかなりストレスが軽減しているはずなのだけれど、やっぱりPCよりはなんか面倒だな・・・

今はFTPでアップロードするところは世間のアプリで代用していますが、どうせプログラムを書くのだからそのうちFTPにアップロードするところまで自作アプリに取り込みたいところ。いつになることやら。

2024年06月15日 このページのリフォーム

Androidアプリのファイルとりまわし

今日は普通にPCで入力中。
Androidアプリ、javaでよちよち作成中。
今までPCでコマンドラインアプリでtxt→html変換アプリ作っていたときは、 htmlに変換する入力テキストファイルの選択は昔ながらのmakeを使っていたので個々のファイルの変換は気にしてなくて、原稿のtxtファイルが更新されてたらhtmlファイルを生成するという仕組みでした。そのあたりの仕組みをAndroidアプリに組み込むのが面倒だったので、原稿ファイルを一つ一つUIで選択してhtmlを生成する事にしました。

        //ファイル選択ボタンのリスナー登録
        btnFile.setOnClickListener(view -> {
            Intent is = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            is.setType("text/plain");
            startForFilenameResult.launch(is);
        });

とかやってファイルマネージャーでファイルを選択して、

        // ファイル選択ボタン押下時
        ActivityResultLauncher<Intent> startForFilenameResult = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(), result -> {
                    Intent i = result.getData();
                    if (i != null) {
                        Uri fileUri = i.getData();

とかやるとfileUriにファイルのURIが入って、

        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(
                        getContentResolver().openInputStream(fileUri)
                )
        )) {
            Stream<String> lines = reader.lines();
            // ファイルから1行読み込みList<String>に入れる
            lines.forEachOrdered(inString::add);
        }

という感じでファイルを読み込む。インテント経由で選択したファイルは読み込めるのだけれど、同じフォルダに拡張子だけhtmlに変更したファイルを書き込もうにも同じフォルダにファイルを作る事すらままならない。
Uriからフォルダはわからないけれどファイル名はとれる。ググると別の方法が出てきたような気がしますが、Androidデベロッパーサイトのチュートリアルを見ると、次の方法でファイル名がとれるとのこと

        String inFileName = DocumentFile.fromSingleUri(this, fileUri).getName();

チュートリアルサイトを見ていたらフォルダのパスとアクセス権を取得する方法も記載されてました

        // フォルダ選択ボタンのリスナー登録
        btnFolder.setOnClickListener(view -> {
            Intent is = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
            is.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
            startForFolderResult.launch(is);
        });

受け取り側は

        // フォルダ作成ボタン押下時
        ActivityResultLauncher<Intent> startForFolderResult = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(), result -> {
                    Intent i = result.getData();
                    if (i != null) {
                        Uri folderUri = i.getData();
                        if (folderUri != null && result.getResultCode() == RESULT_OK) {
                            DocumentFile folder = DocumentFile.fromTreeUri(this, folderUri);

URIは扱いが面倒だけれど、DocumentFileならばこのフォルダの下にファイルを作るのもできそう。

DocumentFile outFile = folderUri.createFile("text/plain", fileName);

でフォルダの中にファイルが作れる。

Androidアプリの基礎を知っていれば簡単なことなのかもしれないけれど、PCでjava 8でコマンドラインアプリをちまちま書いてた程度の知識レベルではここまでたどり着くのにものすごく時間がかかりました。先週の土曜から今週の土曜まで仕事をしていない時間はずっとこれを調べてたと言っても過言ではない!(いや、過言だから)
どうせ公開しないアプリなのでUIはやっつけ仕事。
アプリのUIまで手が回らない

せっかく作ったのに自分のスマホでデバッグはできるけれどリリースビルド版がインストールできずにこれまたググりまくりだったわけですが、それはまた気が向いたら。

2024年06月16日 プログラミング雑談

久しぶりにjavaプログラミング三昧

職場ではなかなか落ち着いてプログラムを書けないので土日に試作。職場のテストデータを持ち帰れないので架空のデータを使用。
DBから読み込んだデータに基づきツールで生成したhtmlファイルなのだけれど、DBのデータに一部不備があるとかで、現在のhtml生成ツールを直すか、生成したhtmlを別ツールで直すかという選択。
本来はhtml生成ツール側を直すのが正しいと思うけれど、データの不正が検出できるメソッドとそのデータを使って表などを生成するメソッドが遠くて、データの不正が発覚した時点ではもうhtml生成の面で後戻りできないように見えたので、別ツールを作ることに。
javaでjsoupを使う。
jsoup自体はこの年末年始に結構戯れていたのでそれなりに使えるはず。
でもjavaの基礎的なところが頭に入っていないのでMapの初期化ってどうやるんだっけ? という次元のところでめんどくさい。
どうせ忘れてしまうので備忘録
HashMapの初期化

    private static Map<String, String> fileToStrMapE = new HashMap<>();

    static {
        fileToStrMapE.put("indexx.html", "STRING_for index.html");
        fileToStrMapE.put("somefile.html", "STRING_for index.html");
        fileToStrMapE.put("nofile.html", "no title line");
        fileToStrMapE.put("errorfile.html", "empty title string");
    }

List<String[]>の初期化
String[][] tableStrを作る

new String[][]{{"aaa", "bbb"}, {"cc", "dd"}, {"e", "f"}}

で、作ったtableStrを使って

        List<String[]> listStringArray = new ArrayList<>();
        Collections.addAll(listStringArray, tableStr);

とかやればList<String[]>にデータが入ってくれるみたい。

あとは何だったっけ。そうそう、Mapから文字列を取り出すのだけれど、keyに対応するvalueが無い場合にnullが返ってきたりするのでOptional.ofNullableとか

        String fileOnly = Paths.get(inFile).getFileName().toString();
        Optional.ofNullable(MyResources.selectToString(fileOnly))
            .ifPresent(o -> { // selectToStringでMapから取り出した値が存在する場合
                // 何かする
            });

ありゃ? よく見ると肝心の「Mapから取り出した値」を使っていない(笑)

gradleを使うつもりだったけれどその設定も忘れ去っているのでググりまくり。
build.gradle.ktsにいろいろコピペしました

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    java
    application
    checkstyle
    jacoco
}
dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation(libs.junit.jupiter)

    testRuntimeOnly("org.junit.platform:junit-platform-launcher")

    // This dependency is used by the application.
    // implementation(libs.guava)
    implementation("org.jsoup:jsoup:1.18.1")
}

jacoco {
    toolVersion = "0.8.11"
    applyTo(tasks.run.get())
}

tasks.register<JacocoReport>("applicationCodeCoverageReport") {
    executionData(tasks.run.get())
    sourceSets(sourceSets.main.get())
}

tasks.jacocoTestReport {
    dependsOn(tasks.test) // tests are required to run before generating the report
    reports {
        xml.required.set(false)
        csv.required.set(false)
    }
}

tasks.named<Test>("test") {
    // Use JUnit Platform for unit tests.
    useJUnitPlatform()
}

tasks.javadoc {
    options.encoding = "UTF-8"
}

こんなところかな。VSCodeのコンソールの文字コード設定なのかjavadocのコンソール出力の文字コードの問題なのか、何か文字化けするけれどjavadoc出力には問題ないみたいだからとりあえずこれでいいかな。
それにしてもcheckstyleさん、指摘が細かい。

2024年08月04日 プログラミング雑談

Jsoup、XHTMLで&nbsp;が出ない・・・

このwebページはテキスト形式の原稿からjavaで自作したツールでhtmlに変換しています。といういつもの枕詞を書いたところで。
以前ツールを作ったときは&nbsp;の出し方がわからなかったので、ま、改行が入ってもいいやってことでスペースを出力して妥協していました。ところが業務でJsoupでhtmlを取り扱う必要があって突貫でツールを作ったところでどうしても&nbsp;を出力しなければならなくなったのでググってみました。
以前自力で調べようとしていたときはJsoupのソースの中に"&nbsp;"という文字列が存在しているようなので何らかの方法で出せるはず!という気はしていたのですよね。
で、結局"\u00a0"が"&nbsp;"に変換されるらしいということで、業務で作っていたツールは解決しました。

ところが、このwebページを変換するツールの方は"\u00a0"で"&nbsp;"にならず"&#xa0;"と出力されてしまいます。
業務のツールもプライベートのツールも私が書いたのに・・・なんでや?!
結局、JsoupのDocumentインスタンスでoutputSettings.escapeMode(EscapeMode.base)を設定すればOK。
業務のツールはOutputSettings.Syntaxが多分デフォルトのhtmlだったけれど、プライベートのツールはxmlに設定していたのでEscapeModeも自動的にxhtmlになっていたのだと思います。

んー、ってことは、もしかしてxhtmlの場合は&nbsp;と出力するところを&#xa0;と出力するのが正解なのかな?

	Document doc;
	// この間にいろいろな処理
        doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml);
        doc.outputSettings().escapeMode(EscapeMode.base);

2024年08月12日 プログラミング雑談

Jsoup appendChildとappendElementはわかった気でいても、つい間違う

        Element body = new Element("body");
        body.appendChild(new Element("div").appendElement("div").attr("name", "test")
                .appendText("[Initial Value]")).appendElement("br")
            .appendChild(new Element("b").appendText("[Value Range]"));

ってやると

 <body>
  <div name="1st">
    <div name="2nd">
     [Initial Value]
    </div>
  </div>
  <br><b>[Value Range]</b></br>
 </body>

ってなるかなと思うと

 <body>
  <div name="2nd">
   [Initial Value]
  </div>
  <br><b>[Value Range]</b></br>
 </body>

になる。
最初のbody.appendChild()でbodyの子エレメントになるのはnew Element("div")ではなくて.appendElement("div")の方。だから.appendElement("div")のdivに[Initial Value]がつく。
いつもわかった気になるのだけれど、しばらくJsoup使わないと忘れちゃう。
.appendChild()やattr()は親Element側が戻り値になる。
.appendElement()だけが特殊で、ここで作られた新しいElementが戻り値になる。

2024年08月13日 プログラミング雑談

FTPアップロードのテスト

javaプログラムからftpのアップロードができるか確認です
PCからはアップロードできましたが、ChromeBookからはアップロードできませんでした。

ftp.storeFile("filename", instream);

のところで失敗しているみたい。

試行錯誤の結果、今のところChromeBookのLinuxではcurlでアップロードすることにしました。

curl -T {アップロードファイルパス} -u {ユーザー名}:{パスワード} ftp://{ホスト名}/{任意のアップロード先ディレクトリ}

でできるみたい。

でもこのままだとPC用はFTPでアップロードする実装が入っていて、ChromeBook用は入っていない状態になってしまう。これはコード管理上めんどくさいのでChromeBook上でデバッグするか・・・ってVSCodeベースでjavaビルド環境を作ろうとしていますが、gradleのエクステンションを入れたところでVSCodeが実用に耐えないレベルで重い。どのくらい重いかというとjavaのHello world!がビルド出来ないくらい(笑)
もしかしてjreは入っているけれどjdkが入っていない?

javac App.java

したら、javacが見つからないって言われてしまった。

apt list --installed | grep jdk

したところ、それっぽいのが入っていない・・・。なんてこったい。

sudo apt-get install default-jdk

でjdkを入れて、javacコマンドが通ることを確認してVSCodeを起動しなおし。
VSCodeのブラグインはPCと同じように入れたのだけれど、ビルドはできるけれどVSCode上でjavaプログラムの実行もデバッグも固まってしまってできない感じ。ビルドしてコマンドラインから実行しながらよちよちデバッグしてました。
結局、

ftp.enterLocalPassiveMode();

でパッシブモードに入ったらftpのアップロードができるようになりました。
このwebページの作り始めの時期に手書きのhtmlファイルをftpでコマンドを打ちながらアップロードしていた時代に、パッシブモードにしないと固まることがあったので、このあたりを最初に疑っていました。
FTPクライアントが入っていればこんなに苦労しなかったのだろうけれど・・・
まあ、とりあえず動いてよかった。コードをきれいにして単体テストとかコメント書いたりすれば出来上がりってことになるかな。

2024年08月14日 独り言,プログラミング雑談

私の部屋のエアコンがうるさい

webページ生成プログラムを更新して、ページの更新の手数が大幅に簡略化されたので、今までならX(twitter)でつぶやいていたような事も簡単に書けるようになりました!。それってこのページを見る人にとって幸せかどうかはわかりませんが。

で、本題のエアコンの話。
昨年、2023年のはじめ、部屋が寒かったので暖房しようとエアコンをつけたけれど数分待っても暖かい風が出てこない。エアコンが壊れたかなと思ったけれど、暖房ならばとりあえず灯油のファンヒーターがあるし、ということで寒さはやり過ごしました。
その夏(=2023年の夏)は新潟は猛暑で、日中は40℃くらいまで気温が上がり、夜も30℃くらいでとても眠れたものではないのでエアコンをON!。冷房はちゃんと涼しい風が出てきてくれました。
それでひと夏過ごした後、煖房は動かないんだったなと思いだしまして、エアコンを買い換えました。三菱→松下。白物家電には強いこだわりがありませんので、安いやつ。CS-J223Dって機種。

今年、2024年の夏は昨年の猛暑ほどではありませんが、それでも暑い夜はエアコンつけて眠りたい!
で、ちゃんと涼しい風が出てきて涼しく眠れるのですが、温度調節でエアコンが運転し始めるたびにグーーーっていう謎のモーター音がうるさい。この音のせいで夜中に目が覚める。それと、ナノイーX/内部クリーンの青いLEDが夜中は気になる!
エアコンを使わないと暑さで寝苦しいし、エアコンを使うと騒音と青色LEDで眠りの質が低下するしで、やだなぁ、三菱のエアコンの方がよかったなぁと思っていたのですよ。

愚痴っていても状況は変わらないので対策だ。
青色LEDの方はLEDの光を軽減するように薄手の紙を貼りつけました。
騒音の方は、もしやと思って風の向きの設定をいじってみたら、上下方向風向きが変わるときにうるさいことが判明。上下の風向きを「自動」に設定していたので自動で上下するたびにうるさかった模様。ってことで、上下の風向きを固定する設定にしたところグーーーっていう謎のモーター音が止まりました!
これで今夜からエアコン使っても安眠できるに違いない。

2024年08月15日 独り言

FTP書き込み処理をAndroidアプリに入れる

このwebページ生成プログラムはjavaで書いているので理想的にはWrite once, run anywhere.なのだろうけれど、Andropidはセキュリティの制限でファイルアクセス関係が独特で、PC用のコードはそのままでは動かない。
今回はGUIではない、CLIとかCUIとかいうコマンドラインで起動するタイプのアプリなので、Android用に簡単なGUIでボタンを押すと各機能が呼び出されるようなアプリをとりあえず作りました。前回のAndroidアプリ化は6月だったので2か月ぶりにAndroid Studioを起動した感じ。
今回もファイルアクセスがあるのでPC用のコードから変更があることは覚悟していました。PC用アプリならばファイル名がわかれば

Paths.get(ファイル名)

でPathにしたり、

Paths.get(ファイル名).toFile()

でFileにしたり。Javaアプリのファイル操作はPathかFileで何でもできそうな気がするので、ここ何週間かのプログラマ生活でだいぶ慣れた感じがします。
一方でAndroidアプリはちゃんと勉強していないせいでまだ理解できた感が全くありません。
Androidアプリはユーザーが普通にアクセスすることができないアプリ専用の領域ならばファイル名でアクセスできるみたいですけれど、それ以外はURIという謎の名前でアクセスする必要がある模様。
テキストエディタで書いたwebページの原稿をgrepしてから必要なファイルだけ書き換えて・・・とか、どうやればいいのかいまだによくわかりません。とりあえず「扱いたいファイルはこのフォルダにあるからね」とユーザーに選択してもらえば、そのフォルダのファイルは割と自由に扱えるみたいなので、今回は必要なファイルが単一のフォルダに全部あるという前提でAndroid化しました。
それでも最初の操作対象ファイルはURIで指定されるので

String inFileName = DocumentFile.fromSingleUri(this, fileUri).getName();

でUriで指定されたfileUriからinFileNameに(フォルダ名が無い)ファイル名を取り出したり

DocumentFile folder = DocumentFile.fromTreeUri(this, folderUri);

でフォルダ情報をDocumentFile形式にして

ContentResolver cr = getContentResolver();

で取得したContentResolverを使って

InputStream instream = getContentResolver().openInputStream(inFileName.getUri());

でUriで指定されたファイルをInputStreamにして

getFtpClient().storeFile(書き込み先のファイル名, instream);

でFTPでファイルアップロード。

PCでjavaコードを書いていたときはApacheのFTPClientの説明どおりにコードを書けばそのまま動きましたが、Androidの場合はこの処理を

    Executors.newSingleThreadExecutor().execute(() -> {
        ... 何か、FTPでファイルアップロードするコード
    });

みたいに別スレッドに移さなければならない模様。
さらに、私はまだよく理解できていないのだけれど、AndroidのUIに何か表示するためにはその時使っている"Activity"のクラスにUI操作のコードを書く必要があるみたいで、Activityとは別クラスのFTPクラスの処理中にユーザーに何か伝えたくてもやり方がわからない。FTPクラスのアクティビティ用にUIを持ったクラスを作ればいいのかしら。

2024年08月16日 独り言,プログラミング雑談

新潟の人、新潟の米や酒が好きすぎ問題

秋田のお土産にお酒の小瓶をもらいました。
北秋田」という名前のそのお酒はワイングラスでおいしい日本酒ってことで賞をもらったとのことです。
もしかして新潟でも普通に買えるのかしら?と思って地元のスーパーのお酒コーナーに足を踏み入れましたが、日本酒コーナーは新潟県内の酒に占拠されていて、それ以外は灘や伏見の酒が少しだけある、という感じ。
ちなみに別のスーパー、こっちは福島の会津が地盤のスーパーで最近新潟にも進出してきた感じのお店ですが、ここは新潟のお酒が棚の半分くらい、残りの半分は磐梯のお酒「榮川」というお酒で構成されていました。
だんだん面白くなってきて新潟地盤ではないドラッグストアも行ってみました。新潟のお酒が3分の2、残りがその他、という感じ。
結局「北秋田」というお酒は新潟でもドラッグストアで買うことができる模様。スーパーではまだ見つけていません。
それにしてもfirefoxで見る「北秋田」の北鹿のwebサイト、iモード時代のサイトかしら?って感じ。もしやと思ってChromeで開いたら近代的なサイトでした。

今回は酒を探して、新潟以外の酒が意外と入手難であることに気が付きましたが、米も同様だなとずっと思ってました。
コシヒカリ、新之助などを擁する新潟。お手頃価格の米もこしいぶきとかあります。何年か前に山形のつや姫がおいしいと全国ネットのワイドショーで話題になったときも新潟のスーパーでは全く見かけずに試食すらできなかったり。
2020年頃に川崎に3年ほど住みましたが、つや姫も青天の霹靂もつがるロマンもあきたこまちも普通にスーパーにあって、いろいろ食べ比べてました。結果、新之助が一番好きかな。みずほの輝きは安い割においしい。あきたこまちはこしいぶきと同等かなぁ・・・。
新潟県民の味覚は新潟の産物に最適化されているのですかね。新潟県外で普通にいろいろ選べる環境でも新潟産米をあえて選んでしまうくらいには新潟県の食べ物が大好きなんだなぁと

スーパーの日本酒コーナーをうろうろしていたところ、「日本酒度」という指標が書かれていることに気が付きました。そういう指標がある事すら知らない状態でプラスの方が日本酒っぽいのかしらん? という曖昧な気分で眺めていたら、日本酒度が-35とかいう、ほかの酒とは桁が違う日本酒を発見。かれん(あ、これも新潟県の酒だ)というお酒。日ごろ全然お酒を飲まない私ですが、かれんSilkというのを300ml瓶一つ買ってきました。こりゃ甘い。文字通り甘い。うっかりジュース気分で飲めそう。米と麹だけでこんな味にできてしまうんだ? まあ甘酒も米と麹だと思えばこの甘さもわからないでもない。

2024年08月17日 独り言

安いChromeBookでgradleは重すぎたけどmavenはいける

ChromeBookでjavaで書いたFTPの処理がうまく動かない件で、ChromeBookに開発環境入れてみたときに、gradleは重すぎて実用にならないと思いましたがmaven(VSCode + maven)は使えなくもない感じでした。

2024年08月18日 プログラミング雑談

24インチ4kモニタのススメ

昔のPC9800の640x400の画面時代から画面のサイズはあまり大きくしなくてよいので画素数を増やして密度を上げてほしいと思い続けていました。
ブラウン管ではどうやら原理的に解像度をあまり上げられないようでしたが、時代は変わり液晶に。スマホでは文字のジャギー感が全く無い高密度の表示が常識になっていますので、デスクトップPCのモニターにもこの流れが来てくれると嬉しいのですが、どうもまだそのようなトレンドが見えてきません。

歳をとって細かい文字が見えにくくなりましたが、プログラミング関係のチュートリアル本などの文字の大きさがコーディングしやすい文字サイズだなと思っていまして、最近24インチくらいのモニターでVSCodeのフォントサイズを12pxに設定しています。
4kモニターの表示はこんな感じになります。
4kモニターの表示はこんな感じ
ブラウザーの設定によって違うでしょうけれど私のところではVSCodeで10cm幅で表示される領域です。同じ領域を2kモニターで表示するとこんな感じになります。
2kモニターで表示するとこんな感じ
ブラウザーで4kのイメージと比較できるようにピクセル補完なしで長さ比2倍に拡大しています。
私のところだとブラウザーで20cm位の幅で見えていますので文字のジャギー感が拡大されて表示されちゃっていますが、フルHD 100%表示だとどんなふうに見えているのでしょう・・・・

JRAサイトの馬柱はこんな感じで表示されています。上が4k、下が2k(フルHD)です
4kモニターで表示する馬柱
2kモニターで表示する馬柱
4kモニターの方が文字が読みやすくて良いと思っているのですが、共感していただけませんかね。

普通に売っている4kモニターは27インチ以上で、24インチってLGから1つ出ているだけで選択肢がありません。
せっかく4kモニター使うんだから大きな画面にしようよという意見もわかるのですけれど、昔の人間なので画面サイズを考えるときに96dpi、つまりフルHDは約23インチ位で等倍、4kならば23インチ位で200%でしょ?って認識から逃れられません。画面サイズが大きくても人間の視界はそんなに広くないし・・・・。
画面幅が8センチ前後大きくなることを許容して4kの27インチで175%表示に設定するってのが良いのでしょうか。32インチで150%が良い? とりあえず今はモニターを買い換える予定が無いので、買い替えるタイミングで私の嗜好に合わせて機種選定することになりますけれど、今の嗜好で言えばエディターで文章を書くときに明朝は明朝っぽく、ゴシックはゴシックっぽく表示されて、「ペ」と「ベ」が容易に見分けられること、ってあたりを基準にすると思います。
その他「一」「-」の見分けがつくってのも良いですね。ゴシック系のフォントだと見分けがつかないケースが多いですけれど、私は明朝系のフォルトを使用していることが多いので結構気になるポイントです。

2024年08月25日 独り言

衆議院議員選挙

明日は衆議院議員選挙。有権者としてこんなに関心が持てない国政選挙はいつ以来だろう。
NHK以外でテレビで選挙の話を全然聞かなかったなぁ。
与党も野党も「バラ色の未来になったらいいなぁ」って言うだけで具体的にどうやったらバラ色の未来が来るかノーアイディアっぽくて。今の私は政治不信じゃなくて、政治を諦めちゃったかんじ。

2024年10月26日 独り言

SeleniumはJava8で使えなくなってたのね

htmlファイルのリンクチェックツールを更新しようと思って、SeleniumをJavaで使おうとしたらランタイムエラー。バージョン55が必要なのに52までしか動かない環境だよ、みたいなメッセージ。
htmlファイルのチェックツール、最近作ったときはPlaywright使ってたし、以前Selenium(Selenide)使ったときはJavaではなくてC#(.net)で使ってた気がします。
最近私のPCのJavaをAmazon Correttoに切り替えたばかりなので何か環境に問題があるのかなと思ってあれこれググってたところ、結局SeleniumはJava 11以上のみサポートに変わっていた模様。
Java 11かぁ。もうちょっとJava 8で遊んでいたいので今回はSeleniumは使わないことにします。

別件ですが
Javaって、JDKのフォルダにJREのフォルダもある事には気が付いていたけれど、なんとなくJREをインストールしてからJDKをインストールするものだと思い込んでいました。VisualStudioCode + Amazon Correttoでmavenでのコンパイルに失敗するのでなんでだろうと思ってたけれど、結局JAVA_HOMEがjreの方を指していたのが原因だった模様。うーん、職場のPCにJREをインストールしてたけど、こっちもアンインストールしよう。

2024年10月27日 プログラミング雑談

WindowsのCopilotってのを使ってみる

世間はAI、AIととってもAIブーム。
国会でもAIで作った質問をしたってニュースがあったのはいつのことだったか。
夏に職場に来たインターンの大学生もCopilotでちょっとしたことを調べてたっけ。
今の人工知能って、コンピュータにあるまじき「正しい答えを出してくれるとは限らない。嘘かもしれない答えを平気でしてくる奴」だと思っているのでイマイチ好きになれずにいます。
とはいえ、何度かWindowsのタスクバーに現れては削除し、またしばらくすると勝手にタスクバーに舞い戻っているCopilotを試してみました。
いまどきはgoogle検索でも自然な日本語で質問文を書いても受け付けてくれるようで、google検索結果のトップにAIの要約が出てきますが、Copilotの出力も同程度の印象です。
田舎者なので、鉄道ローカル線廃止が進むと高校生の通学って困るよなぁ、鉄道が日本ほどきめ細かくない米国の高校生はどうやって通学しているのだろう と思ってCopilot君に米国の高校生が通学に使う交通機関の比率を問いかけたらCommuterの調査結果を回答しやがるし、なんかちゃんと自力でgoogle検索して個々のデータにあたって調べた方が安心だなという印象になっています。
少なくとも現時点ではCopilotの回答を鵜呑みにするのは絶対ダメ。

2024年11月02日 独り言

米百俵の精神

10月26日に「「与党も野党も「バラ色の未来になったらいいなぁ」って言うだけで具体的にどうやったらバラ色の未来が来るかノーアイディアっぽくて。今の私は政治不信じゃなくて、政治を諦めちゃったかんじ。」と書きましたが、わからないなりにどうやったらバラ色の未来が来るか考えてました。
企業が製造設備などの未来への投資ができるように金利を下げましょう!、若者がこれからの日本を支えていけるように学校に通えるように学費や給食費を補助しましょう!ってのが、政治家の言い分なのだけれど、年寄りとしてはピントが外れているような気がして。
20年前、30年前からしている仕事をそのまま規模拡大して生産コストを下げましょう!、そのために製造用の設備を更新しましょう! と言ってみたところで、何十年前から作っているようなジャンルの製品は海外で生産するというトレンドらしいので国内で作っても高値で販売することはできなくて利益が上がらなくて労働者の賃金も上がらないような気がして。
設備投資以前に、何が売れるか知恵を出して、売れるものを作らなければ成長できない時代だと思うのです。
三菱MRJが結局1機も売ることなく開発を断念してしまいました。航空機自体は革命的な製品ではありませんが、燃費の良い航空機を作って売ろうと事業を起こした企業があるのですから、日本政府はもっとかかわるべきだったと思うのです。米国で審査が通らなかったので飛ばすことができません、ではなく、日本で審査を通して日本の空を飛べるよう後押ししなければならなかったのだと思います。それを日本政府はしなかった。
一方でラビダスとかいう半導体製造会社を立ち上げようと日本政府は何百億円とか投じて支援しています。東芝メモリー改めキオクシアでしたっけにも支援しています。前世紀末のジャパンアズナンバーワンの夢よもう一度、ってことで半導体に投資するのでしょうけれど、すでに時代は半導体チップを製造することよりも新しいCPUだったりGPUだったりPGAだったり(これらも既に新しい話ではないのですけれど)を設計して、誰かに製造してもらって、新しい用途で市場を作っていくことで利益を得る時代に移っています。
AppleなりNVIDIAなりが何ミリメートル角のチップ1個何万円で売りますが、どんなに高価で売れるチップを製造しても製造工場の取り分はウエハー一枚何万円とかにしかならないはず。熊本あたりにTSMCの製造工場を誘致したようですが、投資するならば製造工場ではなくTSMCに製造を委託して高値で販売できるチップを設計(チップを使う市場を創造)する分野だと思うのです。

少子高齢化はいろいろな面で問題だと思います。
「子供がいると落ち着いて仕事に行けないし、育児や教育にお金がかかる」ので支援する、という気持ちはわからなくもないのですが、年寄りの感覚とはずれていて。
子供が3歳になるまでは親(母でも父でもいい)がべったりお世話できる社会が良いと思うのです。その後中学卒業くらいまでは日中はジジババが「スープの冷めない距離」でフォローできれば比較的安心かと。このジジババの役割は学童保育でもいいですけれど。子供の面倒を「親自身や信頼できる人が見てくれるから安心」という環境があって、子育てをしていても特に贅沢しなければ普通に暮らしていける家計であれば、改めてそれを行政が支援する必要は薄いと思うのです。
老齢年金は現役世代からの仕送り型ではなく、年金を受け取る本人が老後の自分のために蓄えておくのが基本。将来の現役世代の増減に一喜一憂しない国の仕組みを作ることによって少子高齢化の問題の一つ、老人世代を支えるためという不毛な負担を現役世代に強いる必要がなくなる。
医療費の高騰がもしも超高額の費用がかかる少数の病気のせいであれば、健康保険がカバーする領域を限定して、普通のけがや病気の治療にかかる町医者の取り分を増やしてもいいと思う。超高額の医療費がかかる分野はクラウドファンディング的な対応ができないものかな。

鉄道、赤字ローカル線は問題。でも実は赤字ローカル線の地域の人はそれほど困っていなかったりする。多分廃止されても困らない。おそらく困るのは車がつかえない学生と老人。自動車の自動運転が実現されれば赤字ローカル線は廃止して良いのではないかな。それまでは高校に通う学生については自動車運転免許取得可能な年齢を15歳まで引き下げて対応できないかな。

米の価格上昇や食料自給率が低いとかは私は何か論じれるほど知識がありません。
東北線を大宮-小山くらいまで乗ったときに思いましたが、農地が太陽光発電の発電所に変わってしまったところがかなりありそうな風景でした。主食用の穀物生産が太陽光発電より稼げるようにならないとカロリーベースの食料自給率の向上は無理なのではないかなと思って思考停止しています。

ってことで、全然まとまっていませんが時間切れなので・・・
マクロでは低金利による投資後押しも良いですし、子育て世代の支援も良いのですが、立法や行政がやらなければならないミクロの取り組みを、それが今の現役世代に負担を強いるものであっても、次の現役世代が希望をもって生きていくために必要ならば実施していく必要があるよね、という気分で書き始めた文章をいったん閉じたいと思います。

2024年11月04日 独り言

高校や大学の教育無償化にはあまり賛成できない

中学の給食無償化や高校の教育無償化といった話を聞いていると、日本は懐も心も貧しくなったのだなぁと思うのです。
給食費無償化の話って、お金があっても給食費を払わない家庭の子供に給食を食べるなと言えないとかいうのが本当の理由なのでしょう? いまどき給食費は振込だろうから学校での集金トラブルを避けるという理由は無いだろうし。給食費を払えない貧困家庭は給食費免除にしても学校で集金しなければ生徒たちは誰が給食費免除かわからないし。普通の家庭が子供の給食費を払うのに困窮するような国だとしたらその貧しさこそが大問題です。

高校・大学の教育無償化って、高校や大学に行きたくない、学ぶ意欲が欠如した生徒に対して本来親が「勉強する気が無いなら学校なんか行かずに働け」と言うべきタイミングを消し去って、高校3年間だったり大学と合わせて7年間だったりを無駄に遊びに浪費させてしまうという面が多々あると思うのです。いまどき高校くらい出ていないとできる仕事が無い・・・という感じではないのですよね。ウーバーイーツのリュックを背負った若者たちの仕事に高校以上でしか学ばない知識が必要なのか? と言えば、わかってもらえるでしょうか。
今の高校や大学がどのような教育をしているのか知識をアップデートできていないので的外れなことを言っている可能性大ですが高校は高卒で社会に出る人向けの職業訓練校的な学校と大学以上を目指す学校に明確に分けた方がいい。とりあえず普通科に行っておけばOKみたいな風潮はやめたい。卒業する学生を労働者として受け入れる企業はちゃんと即戦力かどうかテストして学生を値踏みした方がいい。プログラマーを雇うならばプログラムを実際に書かせてみる。新卒社員の初任給が同一学歴なら同額なんてのはナンセンス。今の世の中使い物にならない人材を雇ってしまっても企業側に育成する義務があるらしいので、即戦力と要教育の人材の給与に差があるのはごく自然。

大学はもっと天才を生み出す方にシフトしたら面白い。大学は就職を目指すのではなく、起業を目指すかいきなり企業の幹部を目指すかの2択くらいの方がおもしろい。小中高大の6334という画一の年数ではなくて、高校は2年でも5年でも目的に応じて長さを設定してしまえばいいし、大学も卒業に必要な単位をとるのに5年以上でも6年以上でもかかるように設定すればいい。

高校生も大学生もアルバイトなんかする暇がないくらい学業がハードな方がいい。学生のうちに社会に触れた方がいいならば企業と提携してインターン的な就労体験を1か月でも2か月でも学校のカリキュラムに組み込めばいい。企業は大学から新卒の社員を採用するときに学校に社員(学生)の能力に応じた金を支払うような仕組みにすれば大学の方も熱心に教育してくれるに違いない。能力があるけれど学費が払えない学生も、企業に高く買ってもらえる人材であれば学校側も育てる動機が出てくるでしょう。企業も大学で教育させた人材よりも自前で育てた方が安いという事になれば企業内の教育に熱心に取り組むようになるだろうし。
昭和の頃から世の中がこんなに変わっているのにどうして学校の仕組みや就職の仕組みがこんなに硬直的なまま変わらないのか不思議でなりません。

2024年11月09日 独り言

javaのenumはCのenumとは別物

プログラミングはFORTRANで入門したものの、その後ボードマイコンや低スペックPCを使う中でアセンブラを使い、Cみたいな低レベルのネイティブ開発言語こそが至高!という潜在意識が消えることなく21世紀を迎え、平成末期に仕事の都合でjavaに入門。javaでの開発も良いものだと思い始めたのはここ2年位というプログラミング歴の私。
javaってC++みたいなもの、という気持ちで入門していたのでjavaでC++と同じ用語が使われていると同じ概念かなと勘違いしていたところが多数あります。例えばenum。
これを書く前にちょっとenumでググってみましたが、C界隈ではなんかenumって忌み嫌われた存在のようで、C++的にはenum classを使うのが推奨されるのかな。
javaのenumもCのenumみたいなものかなと思い込んでいましたが、Effecitve Java読んでたらjavaのenumってCのenumやC++のenum classとは全然別の存在であることに今更気が付きました。C++のenum/enum classを私が正しく理解しているという自信もないのですけれど(話す前から言い訳が先行)

Effecitve Java 164ページ(もちろん日本語版)に書かれている「enum型にabstractメソッドを宣言して、各enum定数にそれぞれの振る舞いをoverrideする」コードにちょっと衝撃を受けてます。
そんなことができるの?って感じ。
C/C++気分でenumの列挙値を作っておいて、それぞれの列挙値に対応したKey文字列を使ってMapでValueを管理とかしていたのがもしかしてenumの中だけで完結しちゃうの?
仕事のコードだからコピペで持ってこれないから気分だけ書いてしまうと

public enum Entry {
    FIRST, SECOND, THIRD,
};

public class App {
    public static Map<Entry, String> xxx = new HashMap<>();
    static {
        xxx.put(Entry.FIRST, "一番目の文字列");
        xxx.put(Entry.SECOND, "二番目の文字列");
        xxx.put(Entry.THIRD, "三番目の文字列");
    }
}

みたいなコードは不要で、

public enum Entry {
    FIRST("一番目の文字列"),
    SECOND("二番目の文字列"),
    THIRD("三番目の文字列"),
};

としておけば、

    System.out.println(Entry.FIRST.toString());

でいいし、

public enum Entry {
    FIRST, SECOND, THIRD,
};

public class App {
    public static Map<Entry, Supplier<zzz>> xxx = new HashMap<>();
    static {
        xxx.put(Entry.FIRST, zzzImplFirst::new);
        xxx.put(Entry.SECOND, zzzImplSecond::new);
        xxx.put(Entry.THIRD, zzzImplThird::new);
    }
    public void create(Entry key) {
        Optional.ofNullable(xxx.get(key)).ifPresent(o -> o.get().xxxMethod());
    }
}

も、多分

public enum Entry {
    FIRST{public void xxxMethod() { // do something; } },
    SECOND{public void xxxMethod() { // do something; } },
    THIRD{public void xxxMethod() { // do something; } };
    public abstract void xxxMethod();
};

で処理を振り分けられる。
実際のコーディングではjavaコンパイラに受け入れてもらえるようにちゃんと書かなければなりませんけれど、インターフェースを定義してインプリメントのクラスを作って・・・という回りくどいことが不要になるケースが結構ありそう。

2024年11月10日 プログラミング雑談

jdk17ではjacoco0.8.8以上が必要だった

週末、久しぶりにプログラムを書く気になったので、8月頃に更新したこのwebページ用のhtmlを生成するjavaプログラムをメンテしてました。2か月とか経っているのですっかりどんなコードを書いたか忘れている。
開発環境はWindows 11のPCでjava8でmavenで・・・という感じ。archetype-quickstart-jdk8ってのを使っているのでjunitはjupiter、jacocoとかsurefireとか入ってます。
実行用jarを作るのにmvn installとかするとcheckstyleが口うるさいことを言ってくるけれど都度対応しているし、jacocoもメソッドのサイクロマチック数5以下とか言ってくるのでifとかelse ifとか使っているとあっという間に違反してしまうのでコーディングしたいロジックよりもいかにメソッドのサイクロマチック数を小さくするかにエネルギーを使っていたり。
最近ChromeBookでもjavaの開発環境を作ってみたのでPCからソースファイル一式をChromeBookに持っていってmvn installしてみた。
そしたら単体テスト中にlog4jあたりでExceptionが発生。

java.lang.instrument.IllegalClassFormatException: Error while instrumenting sun/util/resources/cldr/provider/CLDRLocaleDetaMataInfo.
        at org.jacoco.agent.rt.internal_  (以下省略)

って感じ。Exceptionが発生したらスタックトレースを自分の書いたコードまでさかのぼって修正するものだと思っていますが、log4jでgetLoggerするあたりなもので、log4jのとりまわしはよくわからないままチュートリアル的な処理をコピペしてたのであんまり理解できていないのですよね。
javaってWrite once, run anywhere.じゃなかったんかい?とか愚痴りながら、それでも心当たりがありそうなところを手直ししていました。
PCではちゃんとmvn installが正常終了するのになぜ? という観点で見ていましたが、もしかしてPCはjdk8でChromeBookはjdk17なのが悪さしている? ってことで、ググるキーワードにjdkとか追加してましたらやっと原因らしいものにたどり着けました。
結論: jacoco-mavne-pluginのバージョンを0.8.4から0.8.12(最新)にすべし
jacoco 0.8.8で

JaCoCo now officially supports Java 17 and 18 (GitHub #1282, #1198)

ってことだそうです。
pom.xmlに

<jacoco-maven-plugin.version>0.8.4</jacoco-maven-plugin.version>

ってあったので、0.8.12に書き換えたらExceptionが解消。やっと心穏やかにChromebookでjavaのコンパイルができます。

そうそう、去年の春まで使っていたPCのubuntuを22.?から24.?に入れ替えました。こっちでもVisual Studio Code入れてjdk17を入れてコンパイルできるようにしました。まだgitは入れていません。
WindowsではコードのマージとかにWinMergeを使っていますがLinuxに同様のツールは何があるのだろうとググったらmeldというのがヒット。入れてみました。細かい使い勝手は違うけれど、これで十分っぽい。
linuxでブラウザはあるしエディタはあるしjavaの開発もできるし、なんかWindowsが無くてももしからしたらひどく困ることはないのかも。

2024年11月17日 プログラミング雑談

Effective Javaを読み進むごとにjavaの難しさを感じる

今年、2024年2月に書籍Effective Javaを買ってきて、よちよち読んでいますがまだ読み終わりません。
実はEffective Javaをいつ買ったのかなと小遣い帳を見ていたらプログラミング言語Javaは2011年に購入していてちょっとびっくりしていました。てっきり2017年頃買ったのだとばかり思っていたので。Androidのスマホを買ってちょっとAndroid向けのアプリを書いてみたかったのかもしれません
で、Effective Javaの方ですが、やっとページ数で6割くらい読み進んだ感じです。
読めば読むほど自分が幼稚なJavaプログラムを書いていたことを認識してしまいます。まあ仕事ではあまりjavaプログラムを書いていないので主に趣味のコードを書き換えたくなります。
プログラミング言語C++を読んだ時もいろいろショックを受けましたが、あの時は"クラスのあるC"レベルから"C++ 11"に知識をアップデートするのが主目的で、仕事ではC++ 11のコードを書いていないはずなので、自分のプログラミングレベルの幼さよりもC++ 11の新しさに圧倒された感じでした。

で、今週位に読んだ範囲ですと、私は去年の年末あたりからmavenでjacocoあたりにメソッドのサイクロマチック数5とかクラスのサイクロマチック数20とかでmaven installできなくなるので、サイクロマチック数を減らすという観点でstreamなどを使ってjava 1.8の世界に浸っていたわけですが、streamって考えなしに使うなと怒られてしまいました。streamのforEachとかでローカル変数を書き換えてはいけないようです。私ってばコンパイルが通ればあまり気にしていませんでした。
あとはprivate変数でコンテナを持って、コンテナはpublicのgetなんちゃら()というアクセサでアクセス方法を限定して公開していたつもりでしたが、getなんちゃら()でprivateのコンテナをreturnするとコンテナを書き換えられてしまう可能性があるのでセキュアではないとか。

本の最初の方でもequalsやhashCodeのオーバーライドとかComparableの実装とか、クラスを作っても全然意識したことが無かったので目から鱗でしたし。

Effective JavaってJava 9の時代の本なんだよなぁ。ChromeBookに入れられるJDKは既にJava 17だし・・・。Effecitve Javaを読み終わって、Javaが少しわかったような気になったところで世界はもっと先に進んでいるのですよねぇ。全然追いつけません。

2024年11月24日 独り言,プログラミング雑談

JavaのリフレクションでEnumを探す

Javaでプログラムを書いていて、publicクラスAppの中のprivate enumのMakerを引数に持つAppの中のprivateメソッドをテストしたい。
リフレクションを使えばできると聞いてはいるけれど、この手の細かいことは覚えてられないので備忘録的なメモ

// Appクラス
public final class App {
    private enum Maker {
        INDEX("index", Index::new),
        KEYWORD("keyword", Keyword::new);
    }
    private boolean execGen(Maker htmlMode, String inFileName) {
    }
}
// AppTestクラス
class AppTest {
    @Test
    void appTest_execGen() {
        try {
            Class<?> enumAppMaker = null;
            for (Class<?> clazz : App.class.getDeclaredClasses()) {
                if ("Maker".equals(clazz.getSimpleName())) {
                    enumAppMaker = clazz;
                    break;
                }
            }
            Map<String, Enum<?>> makerMember = new HashMap<>();
            for (Object enumConst : enumAppMaker.getEnumConstants()) {
                makerMember.put(((Enum<?>) enumConst).name(), (Enum<?>) enumConst);
            }
            Method method = App.class.getDeclaredMethod("execGen", enumAppMaker, String.class);
            method.setAccessible(true);
            // 入力ファイルがnullの場合はエラーになる
            assertFalse((boolean) method.invoke(app, makerMember.get("INDEX"), ""));

Appクラスの中ではexecGen()もenum Makerもprivateだからいろいろめんどくさい。
execGenの方はメソッドだからググればすぐにヒット。でも引数のenum型の指定方法がわからない。
App.class.getDeclaredClasses()でAppの中のクラス(enumを含む)の配列を取得して、getSimpleName()がenum名、ここでは"Maker"に一致するクラスが探しているenum。
見つけたClass<?>型のenumをgetEnumConstants()するとenum.Values()的な意味合いになる模様。
これを使ってメソッドexecGen()を探したりメソッドexecGen()の引数にしたり。

2024年11月30日 プログラミング雑談

Java mavenで依存jarのクラスパスなどをMANIFESTに書く

2024年5月11日にjava -classpath jarファイル パッケージ名+メインのクラス名 で実行jarが動くとか書いていましたが、maven-jar-pluginを入れれば

java -jar jarファイル

で実行jarが動くそうな。pom.xmlに

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>com.example.App</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>

という感じにメインクラス名を書けばいい模様。<mainClass>の中がアプリのメインクラス名、依存jarがある場合は<addClasspath>をtrueにするだけらしい。
Apache Maven Projectの中の説明

2024年12月07日 プログラミング雑談

javaのUIテストについてググってる途中の備忘録

数年前C++でネイティブ開発こそ至高と考えていた時代にjavaのUIってWindowsでいうところのspyとかで見えないからUIテストができないと思っていました。
今年一年javaプログラミングに取り組んでみて、とりあえずswingというライブラリでGUIプログラムを一つ書いてみようかという気分になったところで改めてjavaのUIテストについてググっています。
この手の細かい話はついついtwitterに呟いてしまい、後日見つけられなくて再びググることになるので今回は自分のwebページに呟くことにします。今は簡単に呟けるようにしたし。
Windowsでネイティブアプリと同様にUIテストしたいならば、java access bridgeを有効にすると良いらしい。
Java Access Bridge の有効化とテスト
最近は私のPCはjdkのフォルダにパスが通っているので

jabswitch -enable

でよさそう。
でもspy++で見えるようになった感じがしない・・・

まだいろいろググっている途中だけれど、自分で作るjavaアプリならばjavax.accessibilityを使えば、というか、accessibilityを提供するようにGUIを作ればjavaの中からGUIを疑似的に操作できるような気がしてきました。

2024年12月22日 プログラミング雑談

java swingで画面解像度に合わせて文字サイズを設定する

24インチの4KモニタなどというAmazonで探してもLGから出ている1機種しか出てこないようなモニタを使っていると世間のチュートリアル通りにプログラムを書いていても期待通りに動作しないことがたびたび。
「Java GUIプログラミング」なるSwingを使ったチュートリアル本を読みながらヨチヨチプログラムを書いてみています。
WindowsでいうところのウインドウはJavaのSwingではJFrameに相当するようです。

JFrame frame = new JFrame("ウインドウのタイトル");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // ウインドウを閉じる処理を登録しておく
JLabel label = new JLabel("Main Text");
frame.add(label);
final int width = 260; // 幅
final int height = 260; // 高さ
frame.setTitle("ListBox"); // ウインドウのタイトル
frame.setSize(width, height); // ウインドウのサイズを設定する
setVisible(true); // 表示する

これだけでウインドウを表示するだけのプログラムになるという事で、30年前にC++でWin32 APIでWindowsアプリのHello world!書いた時よりもずいぶん簡単。多分C#で.netだともっと簡単になっているのでしょうけれど。
で、上記7行のプログラムは24インチ4Kで200%スケーリング表示しているPCだと「200%スケーリング」が反映されていないみたいで表示がちっちゃい。ウインドウの幅と高さを260ピクセルで即値で指定しているのでそれはまあプログラマの私の責任なんだけど、ウインドウの中に表示されるlabelの文字がちっちゃいのが困る。

final Font font = new Font("BIZ UDPゴシック", Font.PLAIN, 12);
label.setFont(font);

ってすれば、Fontのコンストラクタの第3引数は「size - Fontのポイント・サイズ」ですので12ポイントで文字が表示されそうなものですが、文字がちっちゃい。
フォントのポイント・サイズは、本来は1ポイント(1/72)インチのはずですが、画面の解像度に合わせて文字の大きさを制御してくれるわけではなさそう。

private static int ptScale(int point) {
    return point * Toolkit.getDefaultToolkit().getScreenResolution() / 72;
}

とか用意しておいて、

final Font font2 = new Font("BIZ UDPゴシック", Font.PLAIN, ptScale(12));

すると、期待通りの文字サイズで表示されました。
んー、ってことは、Fontのコンストラクタで指定した文字サイズはFontのピクセル・サイズみたいですね。

2024年12月29日 プログラミング雑談

Valid XHTML 1.0!Valid CSS!