« 2018年8月 | トップページ | 2018年10月 »

2018.09.30

Naro2Mobi ver1.7

本文、前書、後書内の「行番号」タグを処理していなかったため、前書や後書内の文章や挿絵がうまく取り込めなかった不具合を修正しました。
 
 
「n2mobi170.zip」をダウンロード
 
 

| | コメント (0) | トラックバック (0)

2018.09.28

Lazarus用のレポートコンポーネントについて

過去にDelphiで作成した計測データから判定値とグラフをレポートにするアプリケーションを、今後のメンテナンスのためにLazarusに移植したのですが、レポートコンポーネントでちょっと苦労したもののうまく解決出来たので情報を共有しておきます(実は前の2つのLazarusの記事も、この作業の中で出てきた課題を解決した結果を書いています)。
 
もともとDelphi(7)ではレポート作成にLightReportコンポーネントを使用しており、その後Delphi XE2でDEKOさんのところのLightReport2コンポーネントに置換して使用していました。
一方、Lazarus1.8でのレポート作成用コンポーネントは「パッケージをインストールもしくはアンインストール」で表示されるLazReportがあるのですが、これが使いづらくて(と言いますか、使い方がよくわからない)、LightReport2からの置換が出来ませんでした。そこで何か良いレポート作成コンポーネントがないかと探したところ、Fortes Reportコンポーネントを見つけました。
このコンポーネントはLazarusだけではなくDelphiにも対応しています。配布アーカイブを解凍したフォルダ内のpackagesフォルダ内にあるfrce.lpkがLazarus用、frce.dpkがDelphi用です(Delphiでの動作確認は未実施)。
 
このFortes Reportの各コンポーネントを用いることで、今回の場合に置いてはLightReport2の必要な全てのコンポーネントを置換することが出来ました。また、レポートのデザインもLightReport2と同じ感覚で行うことが出来ますので、LazarusでLightReport2と同じようなことを実現したい方には良いのではと思います。
 
レポートデザインの様子
Designwd
 
動作状態
Sample
 
 
プロジェクトサンプル
「fortesreport.zip」をダウンロード
 
 

| | コメント (0) | トラックバック (0)

2018.09.26

Lazarusでの日本語文字コード処理について

Delphiでは文字列の入力の際に文字コードの違いを自動的に吸収(変換)してくれるのですが、Lazarusでは文字列はUTF-8前提での処理を行うため、日本語を扱う際には多少の工夫が必要になってきます。
例えば、Windows上で蓄積されてきたテキストファイルはまだまだShift-JISコードで保存されたのものが多いと思いますが、残念ながら文字コードがUTF-8前提となっているLazarusでこれらのファイルを普通に読み込むと当然のことながら文字化けを起こします。
私も実際に保存された測定データをLazarusで読み込む処理を書いたのですが、ちょっとハマってしまったので整理してみます。
 
ネット上にはShift-JISコードの文字列は、AnsiToUTF8またはSysToUTF8でUTF-8コードに変換するとの情報があるのですが、実際に試してみると現在のLazarusではShift-JISコードをUTF-8コードに変換してくれません。
 
AnsiToUTF8
Ansitoutf8
 
SysToUTF8
Systoutf8
 
そこで更に情報を探したところ2つの方法を見つけました。ひとつめはLazUTF8ユニットにあるWinCPToUTF8、もうひとつはLConvEncodingユニットにあるCP932ToUTF8です。どちらを使用しても正常にShift-JISからUTF-8にコード変換してくれます。
 
WinCPToUTF8
Wincptoutf8
 
CP932ToUTF8
Cp932toutf8
 
更に、https://torum.jp/2018/01/27/lazarus_unicode-loading-saving-utf-16-files/でCharEncStreamユニットの情報を見つけました。
このユニットを使用すると、読み込んだファイルの文字コードを自動的にUTF-8変換してくれます。Shift-JIS, Unicode(UTF-16) Big Endian/Little Endianは文字コードを自動変換してくれますし、もちろんUTF-8/UTF-8Nも読み込めます。残念ながらEUC-JPやJIS78/83コードは認識してくれませんが、現状これらの文字コードにお目にかかることはほとんどないと思いますので、機能としては十分かと思います。

CharEncStream
Charencstream
 
 

unit Encunit;
 
{$mode objfpc}{$H+}
 
interface
 
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
StdCtrls, LConvEncoding, LazUTF8, CharEncStreams;
 
type
 
{ TForm1 }

TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
OpenDialog1: TOpenDialog;
Panel1: TPanel;
ConvertBy: TRadioGroup;
procedure Button1Click(Sender: TObject);
private
 
public
 
end;
 
var
Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.Button1Click(Sender: TObject);
var
line: TStringList;
enc: TCharEncStream;
begin
with OpenDialog1 do
if Execute then
begin
if ConvertBy.ItemIndex = 4 then
begin
// CharEncStreamを使用する
enc := TCharEncStream.Create; // CharEncStreams
try
enc.LoadFromFile(FileName);
Memo1.Lines.Text := enc.UTF8Text;
finally
enc.Free;
end;
end else begin
line := TStringList.Create;
line.LoadFromFile(FileName);
try
case ConvertBy.ItemIndex of
0: Memo1.Lines.Text := AnsiToUTF8(line.Text); // System
1: Memo1.Lines.Text := SysToUTF8(line.Text); // LazUTF8
2: Memo1.Lines.Text := WinCPToUTF8(line.Text); // LazUTF8
3: Memo1.Lines.Text := CP932ToUTF8(line.Text); // LConvEncoding
end;
finally
line.Free;
end;
end;
end;
end;
 
end.


 
 
「lazcode.zip」をダウンロード
 
 


| | コメント (0) | トラックバック (0)

2018.09.25

Lazarusでの多言語化

Lazarusでの多言語化ですが、ネット上にであまり詳しい情報が見つけられませんでしたので、私が確認した結果を簡単にまとめで見ます。
 
結論から言うと、一部注意しなければならないところはあるものの、意外と簡単に多言語化を実装することが出来ます。
 
多言語化するプロジェクトのオプションダイアログの国際化にある「国際化を有効にする」をチェックし、「PO出力ディレクトリ」に言語翻訳定義ファイルであるPOファイルを保存するためのフォルダを指定します(ここではLanguageを指定)。
Projoption
 
あとは「.lfmを保存する際に~」をチェックしておけば、フォームを保存するタイミングでPOファイルがPO出力ディレクトリ内に自動的に作成されます。
ここで作成されるPOファイル名はプロジェクト名.POとなります。
 
次に、作成されたPOファイルをPOEdit等の編集アプリケーションを使用して他の言語に翻訳します(編集の仕方はネット上を検索してみて下さい)。
尚、準備したPOフォルダファイルはファイル名を「プロジェクト名.PO」から「プロジェクト名.言語名.PO」に変更する必要があります。
例えば、元の名前がProject1.POで翻訳言語が英語の場合には、Project1.en.POとします。
Poediten
  
プロジェクト多言語化のための翻訳ファイルの準備が整ったら、言語を切り替えるための処理をプログラムソース内に記述していきます。
 
手順は簡単で、
・uses節にLCLTranslator世ニットを追加する。
・言語切替イベント処理を追加する。
・必要に応じて、終了時に現在の言語情報を保存する処理や、起動時に言語情報を読み込んで切替える処理を追加する。
となります。
 
言語の切替はSetDefaultLang(言語(, POファイルフォルダ名(, 強制的に書き換えるか)))を使用します。尚、2つ目以降の引数は省略可能です。
 
実際に言語を切替える処理ですが、言語定義ファイルが英語でサブフォルダLanguageにある場合は、
SetDefaultLang('en', ExtractFilePath(Application.ExeName) + 'Language');
の一行で表示言語が英語に切り替わります。
 
以下は注意が必要な点です
 
多言語化したアプリケーションを一旦日本語以外の言語に切り替えた後に日本語に戻そうとして、
SetDefaultLang('ja', ExtractFilePath(Application.ExeName) + 'Language');
としたり、
SetDefaultLang('');
としても日本語には戻りません。

他の言語に切り替えた後に日本語に戻す場合には、アプリケーションを終了して再起動する必要があります。
または、どうしてもリアルタイムで日本語に戻したい場合は、日本語の言語定義ファイル(Project1.ja.PO)を準備して、
SetDefaultLang('ja', ExtractFilePath(Application.ExeName) + 'Language');
を実行するようにします。
POファイルから日本語の定義を作成するのは面倒ですが、POEditを使用する場合は翻訳元の項目を選択してCtrl+Bを押すと、ソーステキストが翻訳後にそのままコピーされるので効率よく作業できます。
とはいっても、翻訳元の情報量が多いと大変なので、その場合には日本語に切替えた際にはダイアログボックスで「日本語表示は再起動後に有効になります」などとメーッセージを表示するだけにしたほうが楽かもしれません。
Poeditja
 
  
プログラムソース中に埋め込まれた文字列はPOファイルに反映されず、言語切替の対象にも出来ません。
対応ですが、ソース中に埋め込む文字列はresourcestring節を追加して、

resourcestring
 Str001 = 'ほにゃらら';
 Str002 = 'ほげほげ';

などと宣言することで作成されるPOファイル内にこれらの定義が保存されますので、後はPOEdit等で翻訳・保存すれば言語切替の対象にすることが出来ます。
尚、これらの宣言はプログラムの中で
 
 Label1.Caption := Str001:
 ShowMessage(Str002);
 
などと通常の変数のように使用できます。
 
 
 
フォームに配置するコンポーネントでTStringsで格納されている文字列はPOファイルに反映されず、言語切替の対象にも出来ません。
対応ですが、上記と同様にコンポーネントに格納するTStringsをコンマテキスト形式でresourcestring内で宣言して、
 
FormCreate等のイベント内でコンポーネントに動的に追加することで、言語切替の対象にすることが出来ます。
 
resourcestring
 RadioGroup1Str = '一番,二番,三番';
 
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
 // 言語切替の初期化
 RadioGroup1.Items.CommaText := RadioGroup1Str;
end;
 
 
DelphiもCommunityEditionが公開されて、無償でほぼフル機能を使用することが出来るようになり、GnuGetTextの出番も無くなるかもしれませんが、Lazarusでも多少注意するところはあるものの、その辺りを克服すると手軽に多言語化が出来るということがわかりました。
自動的に作成されるPOファイルも、既に翻訳済みの部分を保持したまま変更点だけを更新してくれますので、メンテナンス性も高くて好感が持てます。
 
Lazarusも日本語の扱いがこなれつつあるとは言うものの、まだ文字コード処理には癖があるようですので、この辺りももう少し何とかなるといいなと思う次第です。

unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Menus,
  ExtCtrls, StdCtrls,
  LCLTranslator; // 言語切替ユニット
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Edit1: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    MainMenu1: TMainMenu;
    MenuItem1: TMenuItem;
    MenuItem2: TMenuItem;
    MenuItem3: TMenuItem;
    MenuItem4: TMenuItem;
    RadioGroup1: TRadioGroup;
    RadioGroup2: TRadioGroup;
    ToggleBox1: TToggleBox;
    ToggleBox2: TToggleBox;
    procedure FormCreate(Sender: TObject);
    procedure MenuItem4Click(Sender: TObject);
    procedure RadioGroup1Click(Sender: TObject);
    procedure ToggleBox1Change(Sender: TObject);
    procedure ToggleBox2Change(Sender: TObject);
  private
 
  public
 
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
// 文字列をそのままプログラムソース内に埋め込むとPOファイルに反映されないので
// resourcestringで文字列を定義して、プログラムソース内で使用する
resourcestring
  Str1 = 'これはプログラムソース中の文字列です。';
  // コンポーネント内にTStringsで格納されている文字列もPOファイルに反映されない
  // のでresourcestringで定義しておいて、コンポーネントに動的に反映させる
  // RadioGroup1はアイテムを静的に設定しているのでPOファイルに反映されず、言語
  // 切替で変更できない
  Str2 = '日本語(&J),英語(&E)';
 
 
procedure TForm1.MenuItem4Click(Sender: TObject);
begin
  Close;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  // RadioGroup内のアイテムを動的に追加する
  RadioGroup2.Items.CommaText := Str2;
end;
 
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
  inherited;
 
  case RadioGroup1.ItemIndex of           // サブフォルダLanguageを指定
    0: SetDefaultLang('ja', ExtractFilePath(Application.ExeName) + 'Language');
    1: SetDefaultLang('en', ExtractFilePath(Application.ExeName) + 'Language');
  end;
  RadioGroup2.Items.CommaText := Str2;
  RadioGroup2.ItemIndex := RadioGroup1.ItemIndex;
end;
 
procedure TForm1.ToggleBox1Change(Sender: TObject);
begin
  Edit1.Text := Str1;
end;
 
procedure TForm1.ToggleBox2Change(Sender: TObject);
begin
  ShowMessage(Str1);
end;
 
end.

「project1.zip」をダウンロード
 
 
 


| | コメント (0) | トラックバック (0)

2018.09.23

Naro2Mobi ver1.6

N2m

クリップボードを監視して、URLがコピーされたら自動でダウンロードリストに追加する機能を搭載しました。なにげに便利です・・・何でもっと早く気付かなかったのかと今更ながらに思いました。
 
 
「n2mobi160.zip」をダウンロード


| | コメント (0) | トラックバック (0)

« 2018年8月 | トップページ | 2018年10月 »