2008/08/30

Puppy4.00.3日本語版、再起動後のネットワーク接続の維持

再起動する度にネットワーク接続の手続きをしなければならなかったのですが。一応の解決をみました。

うちのこゐぬの場合、無線LAN×WPE接続という環境だったのですが、起動するときに次の呪文が走ればOK…、

  1. #this file called from rc.local0  
  2. #you can edit this file  
  3. #When firewall is installed, will append lines to this file...  
  4. modprobe evdev  
  5. rm /etc/dhcpc/dhcpcd-eth0.pid 2  
  6. rm /etc/dhcpc/dhcpcd-eth0.cache  
  7. rm /etc/dhcpc/dhcpcd-eth0.info  
  8.   
  9. ifconfig eth0 up  
  10. iwconfig eth0 essid "ESSID名" key s:WEPのキー  
  11. dhcpc eth0  
  12.   
  13. fi  

▲上記を[etc/rc.d/rc.local]というファイルに書き込み。

再起動してみると、無事、rc.localが走って、起動と同時にネットワークへつながりました。参考にしたのはフォーラムのこの辺の記事とか。

まぁもともとコマンドをうってネットワークに接続していたので、あれをここに書けばいいのか、という感じで意外と簡単でした。

本日のひっかかり。
  1. 多少のひっかかりとしては最後の「fi」。なんなのか解せません。fineとか終わりとか???これは書かないと終わらない、とかそういう意味なのでしょうかね?Linuxのコマンドのリファレンスを見ても見つけられませんでした…。
  2. 起動画面で[setting up network interface]をbackgroundでやっている風情の表示がでた後に、このrc.localが走るところもひっかかってはいます。backgroundでなにがしかやったあとに改めてrc.localで接続しなおし…、というのは二重手間に思えて美しくないような気がするのですが、どうなんでしょう。[setting up network interface]は不要なんじゃ?と思うわけです。ここでなにをやっているのでしょうか…。

2008/08/29

Puppy4.00.3日本語版、ブートのあとさき

Linux Swapを設定するのを忘れたなぁと思って、LiveCDからGpartedを起動して気が付きました。よくみるとそれぞれのパーティーションのヨコにフラグがたっているではありませんか。

  • /dev/hda2 (Winが入っている) boot,lba
  • /dev/hda3 (Puppyが入っている) フラグなし

これはもしや…と思い

  • /dev/hda2 (Winが入っている) lba
  • /dev/hda3 (Puppyが入っている) boot

とフラグを立て直したら、フロッピーなしでも無事hda3にインストールしたGRUBが動き出してOS選択画面が出てくるようになりました。

その他の課題

  1. LinuxSwap領域を作ったものの、 [swapon -a]とかやると「Device or resource busy」というエラー表示。…使われてない?
  2. 再起動する度にネットワーク接続やりなおし。…HDDにインストールしたのになんでだヲイ。
  3. で、Gpartedで見かけたlbaってナニ?
追記→LinuxSwapについて。

Puppyの場合、お使いのパソコンにLinuxSwapパーティションがあるとパピーはそのSwapパーティションを利用します。というのが正解でした。つまりGpartedなりでLinuxSwapパーティションを作成すれば、なーんにもしなくてもちゃんと認識してくれる。コマンドは

  1. # cat /proc/swaps  

とやると、どのパーティションがスワップに当てられているか表示してくれました。etc/fstabとかには記述しなくても大丈夫みたいで、swaponとかのコマンドも少々、世界が違っていたみたいです…。

自動で認識してくれるのはカンタンですけど、一長一短ですね。LiveCDのPuppyを起動するとやっぱりLiuxSwapを自動で認識してくれて便利は便利…、ですが同時にそれはLiveCD版PuppyのGpartedなどからは既存のLinuxSwapのリサイズとかはできないということです。なにしろLiveCD版PuppyはもうそのLinuxSwapを問答無用で使用中ですから。とりあえず、[Swapoff -a]のコマンドでは離してくれないようです。他に切り離すテクニックはありそうですが、いまのところ不明です。

2008/08/28

Puppy4.00.3日本語版、インストール完了

Puppy4.00.3日本語版、無事SHARP PC-BJ140にインストール完了しました。Win98ESEとの共存です。

ネットワーク接続も無事完了。「WLI-PCM-L11GP」「Puppy」でぐぐってみれば、情報がでてくるわけで…。「WLI-PCM-L11GP」のPCカードのモジュールは「orinoco_cs 」を利用すればいいだけみたいでした。

ネットワーク接続の手順としては

  1. [ネットワークウィザート]-[etho0]-[ワイヤレス]で、[WEP]をクリック
  2. ProfileName、ESSID、(WEPの)Keyを設定したのち、一旦、[SAVE]、[Use This Profile]。
  3. [自動DHCP]をクリック

すれば、うちの環境の場合、本来OKみたいです。

が、GUIの設定画面からだと、どーも設定各種の認識がうまくいかないらしく、端末からもコマンドラインで呪文を書いた後、GUI設定に改めてトライした方がいいみたいです(WEPキーとかはコマンドでもやっていることは一緒だと思うんですけれど。[自動DHCP]の画面に行きつくための画面遷移の都合上、同じことをGUIでも改めてやるハメになるような…)。

呪文はこんな感じ。

  1. # ifconfig eth0 up  
  2. # iwconfig eth0 essid "ESSID名" key s:WEPキーなどの文字列  

ちなみにPuppyのHDDのインストール自体は結構簡単でした。LiveCDの段階から、PC-BJ140はXorgですんなりことが運んでいましたしね。

PuppyのLiveCDに入っている[Gparted]で、パーテッションを作成したあと(ここで女々しくWin98SEをとっておいたので、デュアルブートな状況になったわけです…)、ユニバーサルインストーラーでがんがん行けばいいだけだったので。で、ウィザートをみながら、ぽこぽこやっていたら、意図せず、フロッピーからGRUBでの起動…、みたいな状況になりました。

わかりやすいといえばわかりやすいんですが。GRUB…、ちょっと勉強する必要がありそうです。

2008/08/26

データ変換速度比較

VB.NET/.NetFramwork2で型変換の速度差、特色について気になりだしたので、実験してみました。

興味があった変換は、普段よく使う

  • Object→Int32への変換
  • String→Int32への変換

です。

実験したものはCtype、CInt、DirectCast、Convert.ToInt32、Int32.Parse、 Int32.TryParse。

実験結果としてはこんな感じです。【 】の中の数値はObjectなりStringなりのmyData変数を、それぞれのメソッドなりでの変換したものです。Int32.TryParseで【 0】となっているのは、変換できなかったということですね。

実験結果

(速度の早い順に並び替え)
  1. Dim my_Data As Object = 12345  
  2. DirectCast :        【     12345】00:00:00.0004363  
  3. CInt :              【     12345】00:00:00.0023329 'CtypeとCInt、Convert.ToInt32は順位が入れ替わるときがあります。  
  4. CType :             【     12345】00:00:00.0023815  
  5. Convert.ToInt32 :   【     12345】00:00:00.0030900  
  6. Int32.Parse :       【     12345】00:00:00.0468925 'Int32.ParseとInt32.TryParseは順位が入れ替わるときがあります。  
  7. Int32.TryParse :    【     12345】00:00:00.0475714  
  8.   
  9.   
  10. Dim my_Data As Object = 12345.5  
  11. CInt :              【     12346】00:00:00.0039555  
  12. CType :             【     12346】00:00:00.0040038  
  13. Convert.ToInt32 :   【     12346】00:00:00.0052587  
  14. Int32.TryParse :    【         0】00:00:00.0631435  
  15.   
  16.   
  17. Dim my_Data As String = "12345"  
  18. Int32.Parse :       【     12345】00:00:00.0198393  
  19. Int32.TryParse :    【     12345】00:00:00.0206115  
  20. Convert.ToInt32 :   【     12345】00:00:00.0214960  
  21. CType :             【     12345】00:00:01.7970309  
  22. CInt :              【     12345】00:00:01.7990923  
  23.   
  24.   
  25. Dim my_Data As String = "12345.5"  
  26. Int32.TryParse :    【         0】00:00:00.0198050  
  27. CInt :              【     12346】00:00:01.8433437  
  28. CType :             【     12346】00:00:01.8474300  

所感としては、Object型のときは、DirectCastを使うのが一番高速(但しDirectCastは丸め処理などは行わず、Int32に変換するのに小数などを引数に渡すとエラーを吐きます)。String型のときは、Int32.Parseが一番高速…、というところでしょうかね。現実問題としてはInt32.TryParseも、使い勝手がよさそうです。

サンプルソース

▲TextBox1に結果が出るわけです…。

※Int32.Parseの引数はもともとString型なので、Option StrictはOffにしないと走りません。

  1. Imports System.Diagnostics  
  2.   
  3.   
  4. Public Class Form1  
  5.     Private Sub Button1_Click(ByVal sender As Object, _  
  6.                               ByVal e As System.EventArgs) _  
  7.                               Handles Button1.Click  
  8.   
  9.         Dim sw As New Stopwatch  
  10.         Dim sb_Data As New System.Text.StringBuilder  
  11.         Dim bl_result As Boolean  
  12.         Dim my_Dict As New Dictionary(Of StringString)  
  13.   
  14.   
  15.         Dim my_Data As Object = 12345  '#---ここをあれこれ差し替えました。  
  16.         '                                   少数の値をセットしたりして  
  17.         '                                   エラーができるときは、  
  18.         '                                   型変換部分も  
  19.         '                                   コメントアウトします。  
  20.         Dim int_Data As Int32  
  21.   
  22.         '----------------------------------  
  23.         sw.Reset()  
  24.         sw.Start()  
  25.         For i As Int32 = 0 To 100000  
  26.             int_Data = CType(my_Data, Int32)  
  27.         Next  
  28.         sw.Stop()  
  29.         my_Dict.Add("CType" & vbTab _  
  30.                     & int_Data.ToString, _  
  31.                     sw.Elapsed.ToString)  
  32.         '----------------------------------  
  33.         sw.Reset()  
  34.         sw.Start()  
  35.         For i As Int32 = 0 To 100000  
  36.             int_Data = CInt(my_Data)  
  37.         Next  
  38.         sw.Stop()  
  39.         my_Dict.Add("CInt" & vbTab _  
  40.                     & int_Data.ToString, _  
  41.                     sw.Elapsed.ToString)  
  42.         '----------------------------------  
  43.         sw.Reset()  
  44.         sw.Start()  
  45.         For i As Int32 = 0 To 100000  
  46.             int_Data = DirectCast(my_Data, Int32)  
  47.         Next  
  48.         sw.Stop()  
  49.         my_Dict.Add("DirectCast" & vbTab _  
  50.                     & int_Data.ToString, _  
  51.                     sw.Elapsed.ToString)  
  52.         '----------------------------------  
  53.         sw.Reset()  
  54.         sw.Start()  
  55.         For i As Int32 = 0 To 100000  
  56.             int_Data = Convert.ToInt32(my_Data)  
  57.         Next  
  58.         sw.Stop()  
  59.         my_Dict.Add("Convert.ToInt32" & vbTab _  
  60.                     & int_Data.ToString, _  
  61.                     sw.Elapsed.ToString)  
  62.         '----------------------------------  
  63.         sw.Reset()  
  64.         sw.Start()  
  65.         For i As Int32 = 0 To 100000  
  66.             int_Data = Int32.Parse(my_Data)  
  67.         Next  
  68.         sw.Stop()  
  69.         my_Dict.Add("Int32.Parse" & vbTab _  
  70.                     & int_Data.ToString, _  
  71.                     sw.Elapsed.ToString)  
  72.         '----------------------------------  
  73.         sw.Reset()  
  74.         sw.Start()  
  75.         For i As Int32 = 0 To 100000  
  76.             bl_result = Int32.TryParse(my_Data, _  
  77.                                        int_Data)  
  78.         Next  
  79.         sw.Stop()  
  80.         my_Dict.Add("Int32.TryParse" & vbTab _  
  81.                     & int_Data.ToString, _  
  82.                     sw.Elapsed.ToString)  
  83.         '----------------------------------  
  84.   
  85.         Dim sorted As List(Of KeyValuePair(Of StringString)) _  
  86.                 = sortByValue(my_Dict)  
  87.   
  88.         sorted.Reverse()  
  89.   
  90.         For Each kvp As KeyValuePair(Of StringStringIn sorted  
  91.   
  92.             Dim str_SPL() As String _  
  93.                 = kvp.Key.Split(vbTab.ToCharArray)  
  94.             Dim str_Num As String _  
  95.             = Strings.StrDup(10, " ") & str_SPL(1)  
  96.   
  97.             sb_Data.Append((str_SPL(0) & " :" _  
  98.               & Strings.StrDup(20, " ")).Substring(0, 20) _  
  99.               & "【" & (str_Num).Substring(str_Num.Length - 10, 10) & "】" _  
  100.               & kvp.Value & vbCrLf)  
  101.   
  102.         Next  
  103.   
  104.         Me.TextBox1.Text = sb_Data.ToString  
  105.         sb_Data.Remove(0, sb_Data.Length)  
  106.         sb_Data = Nothing  
  107.   
  108.     End Sub  
  109.   
  110.   
  111.     Shared Function hikaku(Of TKey, TValue As IComparable(Of TValue))( _  
  112.       ByVal kvp1 As KeyValuePair(Of TKey, TValue), _  
  113.       ByVal kvp2 As KeyValuePair(Of TKey, TValue)) As Integer  
  114.   
  115.         Return kvp2.Value.CompareTo(kvp1.Value)  
  116.     End Function  
  117.   
  118.   
  119.     Shared Function sortByValue(Of TKey, TValue As IComparable(Of TValue))( _  
  120.       ByVal dict As Dictionary(Of TKey, TValue)) _  
  121.       As List(Of KeyValuePair(Of TKey, TValue))  
  122.   
  123.         Dim list As New List(Of KeyValuePair(Of TKey, TValue))(dict)  
  124.   
  125.         'Valueの大きい順にソート  
  126.         list.Sort(AddressOf hikaku)  
  127.         Return list  
  128.     End Function  
  129. End Class  

2008/08/24

Puppy4.00.3日本語版 ワイヤレスな悩み

Puppy4.00.3の日本語版のLive CDを作って、旧マシン(SHARP PC-BJ140。OSはWin98SE、メモリは119MB?本音を言えば、gOS3 Gadgetsとか入れてみたかったわけですが、ロースペックすぎて入れられなかったっス。Puppyでさえ動作条件は128MB、推奨256Bなので危うい…。PC-BJ140は増設しても最大192MBだもんなぁ。今更このマシンにメモリを積んでも推奨にどーせ届かないし…)に入れてやろうと思ったわけですが。Live CDでPuppyを起動するところまではうまくいったものの、ネットワークにつながらない。

手元にあるPC-BJ140は、PCカードつなぎの無線LAN。モジュールのロード、など試すも、全然ダメ。ちなみにメインマシン(こちらはUSBの無線LAN)でCDブート起動して試すも、こちらもネットワーク接続で挫折。無線LAN接続は敷居が高いですな。

あとはndiswrapperを試みるか…?…ああああ、infがない。○| ̄|_


Windows vs. Puppy Linux。Win、Linux、OSインストールする人は、多分笑います。ま、PC-BJ140は、XPどころではなく、98SEですが…。

PDFCreatorの文字化けをなおす2

[PDFCreatorの文字化けをなおす]でインストールしたPDFCreatorですが、ある程度日本語化しても、肝心のPDF保存の画面で化けるんですね。

▲文字化けしないところは日本語で…。化ける、化けないの違いは一体何故なんだ…。

[\PDFCreator\languages]フォルダを調べると、「TransTool.exe」というソフトがあり、どうやらこのツールで日本語ファイルを作るようです。ところが、このソフトでjapanese.iniファイルを作りなおしても、PDF保存の画面だけは、どうもうまくいかないようです。

…というわけで、文字化けする部分のみ、ひとまず英語で使いまわそうと思って処理(化けるよりはマシです)。english.iniファイルをコピーすることにしました。

  1. japanese.iniをコピーして[japanese_02.ini]ファイルを作成。
  2. [japanese_02.ini]の3行目あたりで「Languagename=Japanese (日本語)」→「Languagename=Japanese2 (日本語)」
  3. [Printing] のあたりをごそっと差し替えて保存。
  1. Author=A&uthor:  
  2. BMPFiles=BMP-Files  
  3. Cancel=キャンセル (&C)  
  4. Collect=まとめて保存 (&W)  
  5. CreationDate=Creation &Date:  
  6. DocumentTitle=Document &Title:  
  7. EMail=&eMail  
  8. EPSFiles=EPS(Encapsulated PostScript)  
  9. JPEGFiles=JPEG  
  10. Keywords=&Keywords:  
  11. ModifyDate=&Modify Date:  
  12. Now=現在日時  
  13. PCXFiles=PCX  
  14. PDFFiles=PDF  
  15. PNGFiles=PNG  
  16. PSFiles=PS  
  17. Save=保存 (&S)  
  18. StartStandardProgram=ファイル保存後、PDF文書を開く (&A)  
  19. Status=ファイル作成中...  
  20. Subject=Su&bject:  
  21. TIFFFiles=TIFF  
  1. [設定]→[言語] の[現在の言語設定]で[Japanese2 (日本語)]を設定

以上、お粗末さまでした。

2008/08/16

MySQLテーブル破損→修復

MySQLでSQLをなげたらエラーがでまくり。なんだと思ったら、こんなエラー。

ERROR 1030: Got error 127 from table handler

リファレンスマニュアルをみると、テーブルの破損。error 127なので、レコードがクラッシュしているらしい。

破損しているテーブルを選択してphpAdminでいうところの[テーブルを復旧する]を実行したらなおりました。

なんで破損したかは調べていません…。○| ̄|_

Access DoEvents

Acccess2003で久しぶりにバッチ処理を書いていたら、DoEventsにハマりました。○| ̄|_

一つのフォームの中に、作業1ボタンと作業2ボタンを準備し、作業1ボタンをクリックし、作業1のプロシージャーが走っている間に作業2ボタンをクリックすると、作業2がどうやら走っている…。

ええーー、そうだったっけ?

と思って調べてみると、作業1のプロシージャー内のDoEventsが原因らしい。ヘルプを見ると、

DoEvents 関数を使ってオペレーティング システムに制御を渡しています。

DoEventsでOSに一旦制御を返しているせいで、ボタンクリックのイベントを拾ってこれるようになるわけですね。そりゃそうか。こいつを利用してキャンセルボタンを実行させることもできる、と。

作業1が終了するまでロックをかけたいわけですが、その方法はあとまわしにするとして、ちょっと面白い動きをしていたので実験してみました。

まず、作業1ボタンと作業2ボタンを準備し、次のようなサンプルソースを準備。

  1. Private Sub cmd作業1_Click()  
  2.   
  3. Dim i As Long  
  4.   
  5. For i = 0 To 10000  
  6.     Me.lbl_Count1.Caption = Format(i, "#,##0")  
  7.     DoEvents  
  8. Next  
  9.   
  10. End Sub  
  1. Private Sub cmd作業2_Click()  
  2.   
  3. Dim i As Long  
  4.   
  5. For i = 0 To 10000  
  6.     Me.lbl_Count2.Caption = Format(i, "#,##0")  
  7.     DoEvents  
  8. Next  
  9.   
  10. End Sub  

そして

  1. 作業1ボタンをクリック
  2. 作業1が走っている間に作業2ボタンをクリック

してみると、次のような順序で作業を終了しました。

  1. 作業1をクリック→作業1が走り出す。
  2. 作業1の途中で作業2をクリック→作業1を中断して、作業2が走り出す。
  3. 作業2が完了した後、作業1が再開される。

▲その1 作業1をクリック

▲その2 作業2をクリック

▲その3 作業1が再開される

うーん、作業1の途中で作業2がはじまるのは、OSへ制御が戻っている部分が如実で面白いなぁ。そして作業2が終わると作業1を再開する…(これはちょっと予想外)。

ちなみにDoEventsを書いていなければ、自動的にそのイベントのプロシージャーを抜けるまでAccessはロックがかかっています。しかし、ロジックの中でDoEventsを書きたいし、作業の間は各種ボタンイベント等にはロックをかけたい、というときどうすれば良いか?

Accessの場合、フォーカスをもっているコントロールには、ロックをかけられません。つまり作業1ボタンをクリックした場合、作業1ボタンにフォーカスがありますから、作業2ボタンなど他のコントロールにはロックをかけられても、作業1ボタン自身にはロックをかけられないのですね。よって、小技テクニック「透明ボタンを作る」(…なんでボタンにこんなプロパティがあるんだろー…。やっぱりこの為?)。

  1. 新しくダミーのボタンをフォーム上作成する。
  2. ダミーボタンの[プロパティ]→[書式]→[透明]で[はい]に設定する。
  3. で、このダミーボタンにフォーカスをとりあえず、移動させてしまう。

作業1ボタンのイベントプロシージャーの場合だと、こんな感じ。

  1. Private Sub cmd作業1_Click()  
  2. Me.cmdダミー.SetFocus  
  3. Me.cmd作業1.Enabled = False  
  4. Me.cmd作業2.Enabled = False  
  5. Dim i As Long  
  6.   
  7. For i = 0 To 10000  
  8.     Me.lbl_Count1.Caption = Format(i, "#,##0")  
  9.     DoEvents  
  10. Next  
  11. Me.cmd作業1.Enabled = True  
  12. Me.cmd作業2.Enabled = True  
  13. End Sub  

こんなんで回避できちゃうんですねぇ。まぁグローバル変数とかを使って判定するのもテだとは思いますが。ロックをかけたほうが、ユーザーも見た目でわかりますものね。

2008/08/12

Acces2003のセキュリティ警告

▲こんなイヤンな警告でまくり。ちなみにJet4.0を入れても解決しないような…。

古の技術、Accessネタですいません。

このような警告がデフォルト設定で出るようになったのはAccess2003あたりからであろうと思うのですが、Access2000モードでVBA書きまくりのmdbファイルを、WinXP×Access2003のマシンで動作確認してみようと思ったところ、警告吐きまくり…だったわけなのですね。

「安全でない式がブロックされていません」とかなんとか。

で、ブロックされる関数の一覧なぞを眺めて見ると…。ブロックされる関数使いまくり…。今更排除できないってば。

というわけでセキュリティ・レベルを下げて警告を出さないようにするのが、一番お手軽な方法なので、手順をメモ。

  1. [ツール]→[マクロ]→[セキュリティ]
  2. [セキュリティレベル]で[低]を選択。

[ツール]のメニューになまじっか、[セキュリティ]項目がダイレクトにあるだけに、意外とAccessのこの項目は見つけられないんですよね…。

2008/08/05

JavaFX × Eclipse3.4 Ganymede

▲プラグイン、お手軽!

なーんにも考えずに、Eclipse Ver3.4.0──Ganymedeを入れてしまったので、若干ヲロヲロ。

プラグインは[ヘルプ]-[ソフトウェアの更新およびアドオン]でちゃちゃっとできるので、JavaFXの環境も入れてみたよ。ベンリですねぇ。

  1. [ソフトウェアの更新およびアドオン]-[Manage Sites]-[追加]-[ロケーション]にhttp://download.java.net/general/openjfx/plugins/eclipse/site.xmlを登録して[OK]-[OK]。
  2. http://download.java.net/general/openjfx/plugins/eclipse/site.xmlの左の「+」をクリックしてJavaFXのチェックボックスをチェック。
  3. [インストール]で完了。

サンプルソースの動かし方としては、

  1. [パッケージ・エクスプローラ]を右クリック。
  2. [新規]-[Javaプロジェクト]
  3. [プロジェクト名]に「JavaFXsample」とか。[終了]
  4. [src]-右クリック-[新規]-[その他]
  5. [JavaFX]-[JavaFX File]を選択-[次へ]
  6. [ファイル名]に「FXtest01.fx」などと登録。-[終了]
  7. [FXtext01]のファイルにサンプルソースを書く。
  8. 「JavaFXsample」を選択して右クリック-[実行]-[実行の構成]
  9. [メイン]-[プロジェクト名]には、[参照]から「JavaFXsample」を選択。
  10. [引数]-[プログラムの引数]にfxのファイル名でである「FXtest01」-[実行]

ポイントは[実行の構成]の引数のところで、ファイル名を登録するところかな?(クラス名を入れるのかと思いましたが、違うんですねー。ファイル名=クラス名にしておけば問題ありませんが)

JavaVMで実行されるクラスはFXShellで、このShellに対して実行するべきJavaFX Scriptファイル名を引数として渡す、という理屈みたいです。

コマンドラインだとこんな感じなので…。

  1. java net.java.javafx.FXShell スクリプトファイル名  

2008/08/02

JavaFX GUI記述法

なんとなくJavaFX Scriptの言語仕様読み始め。

Javaのジョーシキも知らないのに、読み出すと面白いわぁ。まず目を引くのは、GUIの記述法ですな。

JavaなヒトがSwingがどうとか言っているのは知っているけど、非Javaな私としてはこれまで、「なにソレ?」くらいの感じだったわけです。今回はからずもSwingのサンプルソースをみていて、"JavaFX での GUI 作成は「宣言」式で行うことができる、ワー、拍手喝采!!"みたいなJavaFX界隈のノリを理解できました。下記がJava のクラスのインポートでGUIを実装した場合のソース。

  1. import javax.swing.JFrame;  
  2. import javax.swing.JButton;  
  3. import java.awt.event.ActionListener;  
  4. import java.lang.System;  
  5.   
  6. var frame = new JFrame();  
  7. var button = new JButton("Press me");  
  8. frame.getContentPane().add(button);  
  9. button.addActionListener(new ActionListener() {  
  10. operation actionPerformed(event) {  
  11.     System.out.println("You pressed me");  
  12. }  
  13.     });  
  14. frame.pack();  
  15. frame.setVisible(true);  

うげげ。面倒くさ…。

.Netの場合だったら、Winフォーム作るとき、普段IDE環境で済ませちゃっていているわけですが。VB.Netの吐くソースをみると、Formクラスを継承して自分自身のフォームのクラスを書いていくわけなんですよね。理屈的には、わかりやすい。Javaはなんで継承して使わないんだろ?せめて土台となるJFrameくらい継承すればいいのに(と思ってウロウロしてサンプルソースを探していたら、JFrameを継承する書き方も、やっぱり王道みたいでした。ということは、.NetもJavaもGUIの記述法は似たり寄ったりってことですね。VS環境以外で.Net開発をしようと思ったことがない私が、さほど記述の手間については気にしたことがなかっただけだってことですね)。

もっともPanelとかのコントロールの中にTextBoxをおくときには、結局

  1. Me.Panel1 = New System.Windows.Forms.Panel  
  2. Me.TextBox1 = New System.Windows.Forms.TextBox  
  3. Me.Panel1.SuspendLayout()  
  4. Me.SuspendLayout()  
  5.   
  6. Me.Panel1.Controls.Add(Me.TextBox1)  

とか、書いていくわけなんですけどね。

基本的にはあくまでも土台となるFormクラスのサブクラスを書いているイメージが濃厚デス。さらに各種コントロールについては、コンストラクタでプロパティやなんやかんやの初期値がほぼ設定され済みで。ソレ故に、変えたいところのプロパティだけ設定していっているイメージが強かったんですよね。このイメージの由来は、IDEでの操作感覚からきているのかも。

で、やっと本題です。Javaや.Netでのコントロールのレイヤー感覚等の記述の面倒くささに比べて、JavaFXでの書き方はこうなるそうだ。

  1. Frame {  
  2.              content: Button {  
  3.                   text: "Press Me"  
  4.                   action: operation() {  
  5.                        System.out.println("You pressed me");  
  6.                   }  
  7.              }  
  8.              visible: true  
  9.         }  

おおお、なんてエレガント。Swing、VB.Netでの書き方に比べて、なんてシンプル。この「うれしさ」はわかるなぁ。

この書き方だったら{}の構造で、どのコントロールがどう重なっているか、一発で見当がついちゃうし。問答無用にスッキリ、大雑把。でもこの大雑把な感じはアリだなぁ。結局初期値を設定しておいて、変えたいプロパティとかだけ呼びだした後、設定しなおしてあげればいいだけの話なんだし。

Excel 二つの列に値の入っている行をカウントする IF文の中でのAND条件OR条件 及び フィルター機能とSUBTOTAL関数テク

今回のお題はExcelに二つの列があり、A列、B列、ともに値の入っている行の数をカウントしたいというもの。

IFのネスト構造でも書けますが、AND関数を使った方がエレガントですね。プログラマの方の場合、論理演算子をパッと思い浮かべるところでしょうが、Excelのセルの中で

=IF((A2<>"") AND (B2<>"")),0,1)

などとやると即エラーです。ExcelにはAND関数、OR関数という関数が用意されていて、ワークシート上ではこの関数を使うわけですね。使い方は簡単。

上記のネタであれば

=IF(AND(A2<>"",B2<>""),1,0)

と書いてやれば、A2、B2のセルの二つがそろって空ではない場合のときのみAND関数からはTRUEがかえってきます。よって上記式では2つのセルに値が入っているときのみ、それ以外はすべて0を返してきます。これを最終行でSUMすれば、二つの列に値が入っている行数がでてきますね。

Ω Ω Ω

▲まずSUBTOTAL関数を仕込みます。

また、別解としてフィルター機能とSUBTOTAL関数での調べ方も紹介します。SUBTOTAL関数とフィルター機能は意外とベンリなんですね。フィルターで抽出したもののみを対象にSUBTOTAL関数は集計作業を行ってくれるから。

書式
SUBTOTAL(集計方法, 範囲1, 範囲2, ...)

集計方法は1~11までの数値で指定します。

集計方法関数
1AVERAGE関数
2COUNT関数
3COUNTA関数
4MAX関数
5MIN関数
6PRODUCT関数
7STDEV関数
8STDEVP関数
9SUM関数
10VAR関数
11VARP関数

ですから、ここではたとえばB列の末尾に

=SUBTOTAL(3,B2:B24)

▲フィルター機能で抽出したものを対象に集計結果を返しています。

と入力したおきます。集計方法は3なのでCOUNTA関数、つまり引数リストの各項目に含まれるデータの個数の合計を返す関数ですね。で、フィルター機能でA列、B列の条件に「空白以外のセル」をいれてあげればSUBTOTAL関数が反応してくれるわけですね。