2009年12月3日木曜日

.NET CSVファイルの読み込み

iniファイルのついでにCSVファイルを読み込むサンプルです。

CSVファイルの定義は以下の通りです。
1.レコードは、CRLFで区切られる。
2.フィールドの数は、同じである。
3.フィールドは、[区切文字]で区切られる。
4.フィールドに[区切文字]が含まれる場合、そのフィールドはダブルクォートで囲まれている。
 例)区切文字を「,(カンマ)」とした場合、○"field,111" ×fied,222
5.フィールドにダブルクォートが含まれる場合、そのフィールドはダブルクォートで囲まれており、
 フィールド内のダブルクォートを2つの連続するダブルクォートに置き換えている。
 例)○"field""111" ×"fied"222" ×field"333

ReadToDataTableメソッドは引数に指定したCSVファイルを
引数に指定したエンコードで読み込み、引数にしていした区切文字でフィールドに区切り、DataTabaleを返します。
引数に指定したisFirstTitleがtrueの場合、CSVファイルの先頭行はDataTableの列名になります。falseの場合はField1,Field2・・・となります。


2010/04/09
「CSVのフィールド数は同じである」としましたが、フィールド数がバラバラなCSVも存在しているのでそれらを読み込めるように修正しました。
あとバグもあったのでコッソリ修正しました。


Public Class CsvFile

    ''' <summary>
    ''' 1行づつ読み取りString配列で返す。
    ''' </summary>
    ''' <param name="path">CSVファイルパス</param>
    ''' <param name="enc">エンコード</param>
    ''' <remarks></remarks>
    Public Shared Function Read(ByVal path As String, ByVal enc As System.Text.Encoding) As String()
        Return System.IO.File.ReadAllLines(path, enc)
    End Function

    ''' <summary>
    ''' 指定したファイルから、指定した区切文字でフィールドに区切り、DataTableで返す。
    ''' </summary>
    ''' <param name="path">読み取るファイルのパス</param>
    ''' <param name="enc">エンコード</param>
    ''' <param name="cSeparator">区切文字</param>
    ''' <param name="isFirstTitle">1行目がタイトルかどうか</param>
    ''' <param name="sTblName">DataTable名</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function ReadToDataTable(ByVal path As String, ByVal enc As System.Text.Encoding, ByVal cSeparator As Char, ByVal isFirstTitle As Boolean, ByVal sTblName As String) As DataTable

            'ファイルから読み込み
            Dim sLines As String() = Read(path, enc)

            'ファイルから読み込んだデータを分解し、リストに格納
            Dim lstRows As New List(Of String())
            For Each line As String In sLines
                '--行を分解しString配列にする。
                Dim fields As String() = LineToArray(line, cSeparator)
                lstRows.Add(fields)
            Next

            '読み込んだデータより最大列数を取得する
            Dim iMaxField As Integer
            For Each fields As String() In lstRows
                If iMaxField < fields.Length Then
                    iMaxField = fields.Length
                End If
            Next

            'テーブルに列を追加する。
            Dim tbl As New DataTable(sTblName)
            For idx As Integer = 0 To iMaxField - 1
                tbl.Columns.Add("Field" & (idx + 1), GetType(String))
            Next

            'テーブルにデータを追加する。
            For iRow As Integer = 0 To lstRows.Count - 1
                Dim fields As String() = lstRows(iRow)

                If isFirstTitle AndAlso iRow = 0 Then
                    For iCol As Integer = 0 To fields.Length - 1
                        tbl.Columns(iCol).ColumnName = fields(iCol)
                    Next
                Else
                    Dim newrow As DataRow = tbl.NewRow
                    For iCol As Integer = 0 To fields.Length - 1
                        newrow(iCol) = fields(iCol)
                    Next
                    tbl.Rows.Add(newrow)
                End If
            Next


            'Test出力
            '--------------------
            For idx As Integer = 0 To tbl.Columns.Count - 1
                If idx <> 0 Then Console.Write(",")
                Console.Write(tbl.Columns(idx).ColumnName)
            Next
            Console.WriteLine("")
            Console.WriteLine("-------------------------------")
            For Each row As DataRow In tbl.Rows
                For idx As Integer = 0 To row.ItemArray.Length - 1
                    If idx <> 0 Then Console.Write(",")
                    Console.Write(row(idx))
                Next
                Console.WriteLine("")
            Next
            '--------------------

            Return tbl
        End Function
        
        
        ''' <summary>
        ''' ファイルから読み取った1行分の文字列データを、引数に指定した区切り文字に従って分解し、String配列で返す
        ''' </summary>
        ''' <param name="line">ファイルから読み取った1行分の文字列データ</param>
        ''' <param name="cSeparator"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function LineToArray(ByVal line As String, ByVal cSeparator As Char) As String()
            Dim lstField As New List(Of String)

            For iSt As Integer = 0 To line.Length - 1
                'フィールドの開始が"で始まっているかを判定
                Dim isWQuote As Boolean = False
                If line(iSt) = Chr(34) Then
                    isWQuote = True
                    iSt += 1
                End If
                'フィールドの終了位置を検索
                Dim sFind As String
                If isWQuote Then
                    sFind = Chr(34) + cSeparator
                Else
                    sFind = cSeparator
                End If
                Dim iEd As Integer = line.IndexOf(sFind, iSt)
                If iEd = -1 Then
                    iEd = line.Length
                    If isWQuote Then
                        If line(iEd - 1) = Chr(34) Then
                            iEd = line.Length - 1
                        End If
                    End If
                End If
                'フィールドを取得
                Dim sField As String
                sField = line.Substring(iSt, (iEd - iSt))
                'フィールドから2つの連続するダブルクォートを1つのダブルクォートに置換する
                sField = sField.Replace(Chr(34) + Chr(34), Chr(34))
                'フィールドを追加
                lstField.Add(sField)
                '開始インデックスをずらす
                If isWQuote Then
                    iSt = iEd + 1
                Else
                    iSt = iEd
                End If

            Next

            Return lstField.ToArray
        End Function

End Class
使用方法
Dim path As String = System.IO.Path.Combine(Application.StartupPath, "Test.csv")
Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("Shift_Jis")

'カンマ区切り
Dim tbl As DataTable = NvTool.File.CsvFile.ReadToDataTable(path, enc, ","c, True, "Test")

'Tab区切り
Dim tbl As DataTable = NvTool.File.CsvFile.ReadToDataTable(path, enc, Chr(9), True, "Test")

.NET iniファイルの読み込み

設定ファイルの読み書きは通常xmlファイルで行うのですが
ユーザーがファイルの編集を直接行う場合、iniファイルで作ることがあります。
設定画面を設けxmlファイルに保存する事がよいのではと思うのですが
そこは大人の事情で設定画面を設けずiniファイルでとなるわけですね。

そんな自分へのメモ。

iniファイルの記述形式は以下のように、keyとvalueが「=」で区切られており「//」以降はコメントとして無視します。
項目名(key)=値(value) //コメント

iniファイルを読み込みiniSettingクラスのフィールドに値を設定します。
iniファイルは直接編集が前提ですので、書き込みメソッドはありません。
またiniSettingクラスのプロパティもReadOnlyにしています。
アプリ全体で使用するのでiniSettingクラスはシングルトンにしています。
Public Class IniSetting

    '-----定数-----

    ''' <summary>Iniファイル名</summary>
    Private Shared ReadOnly IniFileName As String = "ini.txt"
    ''' <summary>Iniファイルパス</summary>
    Private Shared ReadOnly IniFilePath As String = System.IO.Path.Combine(Application.StartupPath, IniFileName)
    ''' <summary>エンコード</summary>
    Private Shared ReadOnly ENC As System.Text.Encoding = System.Text.Encoding.GetEncoding("Shift_Jis")

    '----staticフィールド----

    ''' <summary>自分自身のインスタンス</summary>
    Private Shared _Instance As IniSetting


    '----staticプロパティ----

    ''' <summary>自分自身のインスタンスを取得します</summary>
    Public Shared ReadOnly Property Instance() As IniSetting
        Get
            Return _Instance
        End Get
    End Property

    '----staticメソッド----

    ''' <summary>
    ''' 項目名=設定値  //コメント等
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub Load()
        'iniファイルよりに記載された項目名=設定値を読み取り、DictionaryのKeyとValueに設定します。
        Dim lstIni As New Dictionary(Of String, String)
        lstIni = LoadIni(IniFilePath, ENC)

        'IniSettingクラスのインスタンスを作成しフィールドに設定する
        Dim key As String
        _Instance = New IniSetting
        '--Item1
        key = "項目1"
        If Not lstIni.ContainsKey(key) Then
            Throw New FormatException(String.Format("{0}ファイルに{1}が設定されていません。", IniFileName, key))
        End If
        _Instance._Item1 = lstIni.Item(key).ToString
        '--Item2
        key = "項目2"
        If Not lstIni.ContainsKey(key) Then
            Throw New FormatException(String.Format("{0}ファイルに{1}が設定されていません。", IniFileName, key))
        End If
        If Integer.TryParse(lstIni.Item(key), _Instance._Item2) = False Then
            Throw New FormatException(String.Format("{0}ファイルの{1}が数値に変換できません。", IniFileName, key))
        End If
    End Sub

    ''' <summary>
    ''' iniファイルよりに記載された項目名=設定値を読み取り、DictionaryのKeyとValueに設定し返します。
    ''' </summary>
    ''' <param name="path"></param>
    ''' <param name="enc"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Shared Function LoadIni(ByVal path As String, ByVal enc As System.Text.Encoding) As Dictionary(Of String, String)
        Dim fileName As String = System.IO.Path.GetFileName(path)

        Dim lstIni As New Dictionary(Of String, String)
        If Not System.IO.File.Exists(path) Then
            Throw New System.IO.FileNotFoundException(String.Format("{0}ファイルを配置してください。", path))
        End If
        Dim sr As New System.IO.StreamReader(path, enc)
        Try
            While sr.Peek() > -1
                Dim s As String = sr.ReadLine
                If Not String.IsNullOrEmpty(s) Then
                    '--コメントを削除
                    s = System.Text.RegularExpressions.Regex.Replace(s, "//.*", "")
                    '--コメントまでにタブが入る可能性があるので削除
                    s = s.Replace(vbTab, String.Empty)
                    Dim ary As String() = s.Split("="c)
                    If ary.Length <> 2 Then
                        Throw New FormatException(String.Format("{0}ファイルの設定が不正です。" & vbCrLf & "項目名=設定値 の形式で記載されているか確認してください。", fileName))
                    Else
                        lstIni.Add(Trim(ary(0)), Trim(ary(1)))
                    End If
                End If
            End While
            sr.Close()
        Finally
            sr = Nothing
        End Try

        Return lstIni
    End Function

    '----コンストラクタ----

    ''' <summary>
    ''' コンストラクタ
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub New()
        '隠匿
    End Sub

    '-----フィールド-----

    Private _Item1 As String
    Private _Item2 As Integer

    '-----プロパティ-----

    Public ReadOnly Property Item1() As String
        Get
            Return Me._Item1
        End Get
    End Property

    Public ReadOnly Property Item2() As Integer
        Get
            Return _Item2
        End Get
    End Property

End Class

使用方法
'アプリ起動時などでLoadしておく。
IniSetting.Load()

'IniSettingのInstance経由でプロパティにアクセスする。
Console.WriteLine(IniSetting.Instance.Item1)
Console.WriteLine(IniSetting.Instance.Item2)

2009年12月1日火曜日

.NET リソースファイルをプロジェクト間で共有する

リソースを管理するプロジェクトにリソースファイルを追加し画像などを追加します。
これを別のプロジェクトから利用する方法です。

リソースを管理するプロジェクト名を「ResouceProject」ととし、新しい項目の追加でリソースファイル「MyResouce」を追加します。
このリソースファイルに画像「image.jpeg」を追加しておきます。

方法その1

まず、別のプロジェクトからリソースファイルにアクセスできるように
リソースファイルのアクセス修飾子をデフォルトのFriendからPublicに変更します。



コードから利用するには以下のように記述します。
ResouceProject.My.Resouces.MyResouce.image

しかしこの方法では別のプロジェクトのプロパティウィンドウの「リソースの選択」ダイアログに表示されません。

方法その2

リソースファイルのアクセス修飾子をデフォルトのFriendのままにしておきます。

別のプロジェクトから「既存項目の追加」で「ResouceProject」プロジェクトの
「MyResouce.resx」「MyResouce.Designer.vb」を「リンクとして追加」で追加します。




コードから利用する場合は以下のように記述します。
「WindowsApplication1」はリソースを追加したプロジェクト名です。
Global.WindowsApplication1.MyResource.image

プロジェクトのプロパティウィンドウの「リソースの選択」ダイアログにも表示されます。

2009年11月25日水曜日

.NET ダイアログ画面をコントロールの位置に合わせて表示する

ダイアログ画面をテキストボックスの右上に合わせて表示します。
Using frm As New Form
 frm.StartPosition = FormStartPosition.Manual
 Dim p As Point = Me.TextBox1.PointToScreen(New Point(0, 0))
 p.X += Me.TextBox1.Width
 frm.Location = p
 frm.ShowDialog()
End Using

2009年11月12日木曜日

ASP.NET ハンドルされなかった例外を処理する

Global.asaxファイル

Global.asaxファイルをアプリケーション・ルート直下に追加します。
Application_Errorイベントにハンドルされなかった例外を処理するコードを記述します。

<%@ Application Language="VB" %>

<script runat="server">

    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' アプリケーションのスタートアップで実行するコードです
    End Sub
    
    Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
        ' アプリケーションのシャットダウンで実行するコードです
    End Sub
        
    Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
        ' ハンドルされていないエラーが発生したときに実行するコードです
        
        'ログを出力します。
        Using writer As New System.IO.StreamWriter(Server.MapPath("~/MyError.log"), True)
            Dim err As Exception = Server.GetLastError.InnerException
            If err IsNot Nothing Then
                Dim text As New System.Text.StringBuilder
                text.Append(err.Source & Chr(13))
                text.Append(err.Message & Chr(13))
                text.Append(DateTime.Now.ToString & Chr(13))
                writer.WriteLine(text.ToString)
            End If
        End Using
        
        'カスタムエラーページを表示します。
        Server.Transfer("~/MyError.aspx")
    End Sub

    Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' 新規セッションを開始したときに実行するコードです
    End Sub

    Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
        ' セッションが終了したときに実行するコードです 
        ' メモ: Session_End イベントは、Web.config ファイル内で sessionstate モードが
        ' InProc に設定されているときのみ発生します。session モードが StateServer か、または 
        ' SQLServer に設定されている場合、イベントは発生しません。
    End Sub
       
</script>

カスタムエラーページを作成

ルート直下にMyError.aspxフォームを追加します。
今回はラベルを2つ配置し、Loadイベントで例外情報を出すようにしてみます。
Partial Class MyError
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles Me.Load
        Dim ex As Exception
        ex = Server.GetLastError
        If TypeOf ex Is HttpUnhandledException AndAlso ex.InnerException IsNot Nothing Then
            ex = ex.InnerException
        End If

        Me.Label1.Text = ex.GetType.ToString
        Me.Label2.Text = ex.Message

    End Sub
End Class

ASP.NET カスタムロールプロバイダを利用したアクセス制御

前回ASP.NETカスタムメンバーシッププロバイダを利用したログイン
Memberフォルダ配下のページはログインしていないユーザのアクセスを拒否するよう設定しました。
今回は新たにAdminフォルダを作成し、Adminフォルダ配下のページはAdminロールを持っているユーザのみアクセスを許可するように設定します。

前回のコードに追加していきます。

カスタム ロール プロバイダーの作成

まずカスタムロールプロバイダを作成します。
App_Codeに「CustomRoleProvider.vb」クラスを追加します。
CustomRoleProviderクラスはRoleProviderクラスを継承します。
抽象メソッドをオーバーラドしたメソッドが追加されますのでGetRolesForUserメソッドにロールを取得するコードを書きます。
その他のメソッドはNotSupportedExceptionをスローするようにしておきます。

Public Class CustomRoleProvider
    Inherits RoleProvider

    Public Overrides Property ApplicationName() As String
        Get
            Throw New NotSupportedException
        End Get
        Set(ByVal value As String)
            Throw New NotSupportedException
        End Set
    End Property

    Public Overrides Function GetRolesForUser(ByVal username As String) As String()
        '入力されたusernameを元に、ユーザのロールを取得します。
        return new String(){"Admin"}
    End Function

    Public Overrides Sub AddUsersToRoles(ByVal usernames() As String, ByVal roleNames() As String)
        Throw New NotSupportedException
    End Sub

    Public Overrides Sub CreateRole(ByVal roleName As String)
        Throw New NotSupportedException
    End Sub

    Public Overrides Function DeleteRole(ByVal roleName As String, ByVal throwOnPopulatedRole As Boolean) As Boolean
        Throw New NotSupportedException
    End Function

    Public Overrides Function FindUsersInRole(ByVal roleName As String, ByVal usernameToMatch As String) As String()
        Throw New NotSupportedException
    End Function

    Public Overrides Function GetAllRoles() As String()
        Throw New NotSupportedException
    End Function

    Public Overrides Function GetUsersInRole(ByVal roleName As String) As String()
        Throw New NotSupportedException
    End Function

    Public Overrides Function IsUserInRole(ByVal username As String, ByVal roleName As String) As Boolean
        Throw New NotSupportedException
    End Function

    Public Overrides Sub RemoveUsersFromRoles(ByVal usernames() As String, ByVal roleNames() As String)
        Throw New NotSupportedException
    End Sub

    Public Overrides Function RoleExists(ByVal roleName As String) As Boolean
        Throw New NotSupportedException
    End Function
End Class


web.configを編集

作成したカスタムロールプロバイダを登録します。
<!--ロールプロバイダ-->
<roleManager enabled="true" defaultProvider="CustomRoleProvider">
 <providers>
  <add name="CustomRoleProvider" type="CustomRoleProvider"/>
 </providers>
</roleManager>

Adminフォルダ配下のページは非認証ユーザを拒否し、Adminロールのみ許可を与えます。
<!--adminフォルダ-->
<location path="admin">
 <system.web>
  <authorization>
   <deny users="?" />
   <allow roles="Admin" />
  </authorization>
 </system.web>
</location>

<?xml version="1.0"?>
 ・・・省略
 <system.web>
  ・・・省略
  <!--認証方法 Form認証-->
  <!--<authentication mode="Windows"/>-->
  <authentication mode="Forms">
   <forms loginUrl="Default.aspx"/>
  </authentication>
  <!--メンバシッププロバイダ-->
  <membership defaultProvider="CustomMembershipProvider">
   <providers>
    <add name="CustomMembershipProvider" type="CustomMembershipProvider"/>
   </providers>
  </membership>
  <!--ロールプロバイダ-->
  <roleManager enabled="true" defaultProvider="CustomRoleProvider">
   <providers>
    <add name="CustomRoleProvider" type="CustomRoleProvider"/>
   </providers>
  </roleManager>
     <!--すべてのユーザーにアクセス許可を与える-->
    <authorization>
   <allow users="*"/>
  </authorization>
 </system.web>
 <!--**個別フォルダ・ページのセキュリティ**-->
 <!--Memberフォルダ-->
 <location path="Member">
  <system.web>
   <authorization>
    <deny users="?" />
   </authorization>
  </system.web>
 </location>
 <!--adminフォルダ-->
 <location path="Admin">
  <system.web>
   <authorization>
    <deny users="?" />
    <allow roles="Admin" />
   </authorization>
  </system.web>
 </location>
</configuration>

2009年11月6日金曜日

ASP.NET カスタムメンバーシッププロバイダを利用したログイン

カスタム メンバーシップ プロバイダーの作成

まずカスタムメンバーシッププロバイダを作成します。
App_Codeに「CustomMembershipProvider.vb」クラスを追加します。
CustomMembershipProviderクラスはMembershipProviderクラスを継承します。
抽象メソッドをオーバライドしたメソッドが追加されますのでValidateUserメソッドに認証のコードを書きます。
その他のメソッドはNotSupportedExceptionをスローするようにしておきます。
Public Class CustomMembershipProvider
    Inherits MembershipProvider

    '-----Overridesプロパティ-----

    Public Overrides Property ApplicationName() As String
        Get
            Throw New NotImplementedException
        End Get
        Set(ByVal value As String)
            Throw New NotImplementedException
        End Set
    End Property

    Public Overrides ReadOnly Property EnablePasswordReset() As Boolean
        Get
            Throw New NotImplementedException
        End Get
    End Property

    Public Overrides ReadOnly Property EnablePasswordRetrieval() As Boolean
        Get
            Throw New NotImplementedException
        End Get
    End Property

    Public Overrides ReadOnly Property RequiresQuestionAndAnswer() As Boolean
        Get
            Throw New NotImplementedException
        End Get
    End Property

    Public Overrides ReadOnly Property RequiresUniqueEmail() As Boolean
        Get
            Throw New NotImplementedException
        End Get
    End Property

    Public Overrides ReadOnly Property MinRequiredNonAlphanumericCharacters() As Integer
        Get
            Throw New NotImplementedException
        End Get
    End Property

    Public Overrides ReadOnly Property MinRequiredPasswordLength() As Integer
        Get
            Throw New NotImplementedException
        End Get
    End Property

    Public Overrides ReadOnly Property PasswordAttemptWindow() As Integer
        Get
            Throw New NotImplementedException
        End Get
    End Property

    Public Overrides ReadOnly Property PasswordFormat() As System.Web.Security.MembershipPasswordFormat
        Get
            Throw New NotImplementedException
        End Get
    End Property

    Public Overrides ReadOnly Property PasswordStrengthRegularExpression() As String
        Get
            Throw New NotImplementedException
        End Get
    End Property

    Public Overrides ReadOnly Property MaxInvalidPasswordAttempts() As Integer
        Get
            Throw New NotImplementedException
        End Get
    End Property

    '-----Overrides メソッド-----
    ''' <summary>
    ''' ここでログイン認証のチェックを行う
    ''' </summary>
    ''' <param name="username"></param>
    ''' <param name="password"></param>
    Public Overrides Function ValidateUser(ByVal username As String, ByVal password As String) As Boolean
        'とりあえずTrueを返す。
        Return True
    End Function

    Public Overrides Function ResetPassword(ByVal username As String, ByVal answer As String) As String
        Throw New NotImplementedException
    End Function

    Public Overrides Function ChangePassword(ByVal username As String, ByVal oldPassword As String, ByVal newPassword As String) As Boolean
        Throw New NotImplementedException
    End Function

    Public Overrides Function ChangePasswordQuestionAndAnswer(ByVal username As String, ByVal password As String, ByVal newPasswordQuestion As String, ByVal newPasswordAnswer As String) As Boolean
        Throw New NotImplementedException
    End Function

    Public Overrides Function CreateUser(ByVal username As String, ByVal password As String, ByVal email As String, ByVal passwordQuestion As String, ByVal passwordAnswer As String, ByVal isApproved As Boolean, ByVal providerUserKey As Object, ByRef status As System.Web.Security.MembershipCreateStatus) As System.Web.Security.MembershipUser
        Throw New NotImplementedException
    End Function

    Public Overrides Function DeleteUser(ByVal username As String, ByVal deleteAllRelatedData As Boolean) As Boolean
        Throw New NotImplementedException
    End Function

    Public Overrides Function FindUsersByEmail(ByVal emailToMatch As String, ByVal pageIndex As Integer, ByVal pageSize As Integer, ByRef totalRecords As Integer) As System.Web.Security.MembershipUserCollection
        Throw New NotImplementedException
    End Function

    Public Overrides Function FindUsersByName(ByVal usernameToMatch As String, ByVal pageIndex As Integer, ByVal pageSize As Integer, ByRef totalRecords As Integer) As System.Web.Security.MembershipUserCollection
        Throw New NotImplementedException
    End Function

    Public Overrides Function GetAllUsers(ByVal pageIndex As Integer, ByVal pageSize As Integer, ByRef totalRecords As Integer) As System.Web.Security.MembershipUserCollection
        Throw New NotImplementedException
    End Function

    Public Overrides Function GetNumberOfUsersOnline() As Integer
        Throw New NotImplementedException
    End Function

    Public Overrides Function GetPassword(ByVal username As String, ByVal answer As String) As String
        Throw New NotImplementedException
    End Function

    Public Overloads Overrides Function GetUser(ByVal providerUserKey As Object, ByVal userIsOnline As Boolean) As System.Web.Security.MembershipUser
        Throw New NotImplementedException
    End Function

    Public Overloads Overrides Function GetUser(ByVal username As String, ByVal userIsOnline As Boolean) As System.Web.Security.MembershipUser
        Throw New NotImplementedException
    End Function

    Public Overrides Function GetUserNameByEmail(ByVal email As String) As String
        Throw New NotImplementedException
    End Function

    Public Overrides Function UnlockUser(ByVal userName As String) As Boolean
        Throw New NotImplementedException
    End Function

    Public Overrides Sub UpdateUser(ByVal user As System.Web.Security.MembershipUser)
        Throw New NotImplementedException
    End Sub

    
End Class

認証後に表示するページの作成

Memberフォルダを追加し、Top.aspxファイルを追加します。

ログインコントロールの配置

Default.aspxにログインコントロールを配置します。
ログインコントロールのDestinationPageUrlプロパティに「~/Member/Top.aspx」を指定します。
これで正しくログインできたときにMember/Top.aspxが表示されます。

web.configを編集

認証方法をフォーム認証に設定し、loginUrl要素にログインコントロールを配置したDefault.aspxを指定します。
<!--<authentication mode="Windows"/>-->
<authentication mode="Forms">
    <forms loginUrl="Default.aspx"/>
</authentication>

作成したカスタムメンバーシッププロバイダを登録します。
<!--メンバシッププロバイダ-->
<membership defaultProvider="CustomMembershipProvider">
 <providers>
  <add name="CustomMembershipProvider" type="CustomMembershipProvider"/>
 </providers>
</membership>

すべてのユーザにアクセス許可を与えるように設定します。
<!--すべてのユーザーにアクセス許可を与える-->
<authorization>
 <allow users="*"/>
</authorization>

Memberフォルダ配下のページは認証していないユーザのアクセスは拒否します。
<!--Memberフォルダ 非認証ユーザを拒否する-->
<location path="Member">
 <system.web>
  <authorization>
            <deny users="?"/>
     </authorization>
 </system.web>
</location>
authorization要素の
allow要素は「許可を与える」
deny要素は「拒否する」
users="*"は「すべてのユーザ」
users="?"は「認証していないユーザ」
となります。
<allow users="*"/>で、すべてのユーザにページアクセスの許可を与え
<deny users="?"/>で、非認証ユーザを拒否します。
user1に許可を与え、非認証ユーザを拒否するようにするには以下のように記述します。
<authorization>
    <allow user="user1"/>
    <deny user="?"/>
</authorization>

<?xml version="1.0"?>
    …省略
    <system.web>
        …省略
  <!-- 
            <authentication> セクションは、ユーザーを識別するため
            に、ASP.NET で使用されるセキュリティ認証モードの構成
            を有効にします。-->
  <!--認証方法 Form認証-->
  <!--<authentication mode="Windows"/>-->
  <authentication mode="Forms">
   <forms loginUrl="Default.aspx"/>
  </authentication>
  <!--メンバシッププロバイダ-->
  <membership defaultProvider="CustomMembershipProvider">
   <providers>
    <add name="CustomMembershipProvider" type="CustomMembershipProvider"/>
   </providers>
  </membership>
  <!--すべてのユーザーにアクセス許可を与える-->
  <authorization>
   <allow users="*"/>
  </authorization>
 </system.web>
 <!--**個別フォルダ・ページのセキュリティ**-->
 <!--Memberフォルダ 非認証ユーザを拒否する-->
 <location path="Member">
  <system.web>
   <authorization>
        <deny users="?"/>
   </authorization>
  </system.web>
 </location>
</configuration>

以上で設定は終了です。
IEでMember/Top.aspxにアクセスするとログインページにリダイレクトされます。
ログインページでユーザー名、パスワードを入力するとMember/Top.aspxに遷移します。

2009年10月22日木曜日

.NET 定数ファイルを作成する~その3~

定数ファイルを作成する~その3~

定数ファイルを作成する~その1~
定数ファイルを作成する~その2~

改良して、今はこんな感じで落ち着いてます。


定数アイテムリストの基底クラスです。
Namespace Constant
    
    Public MustInherit Class ConstItemBase

        '-----フィールド-----

        'コード
        Private _iCd As Integer
        '名前
        Private _sName As String
        '別名
        Private _sAliasName As String

        '-----Publicプロパティ-----

        'コードを取得します
        Public ReadOnly Property Cd() As Integer
            Get
                Return Me._iCd
            End Get
        End Property
        '名前を取得します
        Public ReadOnly Property Name() As String
            Get
                Return Me._sName
            End Get
        End Property
        '別名を取得します
        Public ReadOnly Property AliasName() As String
            Get
                Return Me._sAliasName
            End Get
        End Property

        '-----コンストラクタ-----
        
        '引数を取らないコンストラクタ
        Private Sub New()
        End Sub
        
        'コードと名前を引数に取るコンストラクタ
        Public Sub New(ByVal cd As Integer, ByVal name As String)
            Me._iCd = cd
            Me._sName = name
        End Sub
        
        'コードと名前と別名を引数に取るコンストラクタ
        Public Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            Me.New(cd, name)
            Me._sAliasName = aliasname
        End Sub

    End Class
End Namespace

定数リストを検索するためのフィルタクラスです。
Namespace Constant
    Friend Class ConstItemFilter(Of TValue)

        '-----インスタンス変数-----

        '検索する値です  
        Private _FilterValue As TValue

        '-----コンストラクタ-----

        'コンストラクタ  
        Public Sub New(ByVal filterValue As TValue)
            Me._FilterValue = filterValue
        End Sub

        '-----メソッド-----

        '引数に指定した定数アイテムのCDと検索値が一致するかを取得します。  
        Public Function IsMatchCd(ByVal item As ConstItemBase) As Boolean
            If (Me._FilterValue Is Nothing) Then Return False
            Return (Me._FilterValue.Equals(item.Cd))
        End Function

    End Class
End Namespace

曜日をあらわす定数アイテムリストです
Namespace Constant

    Public NotInheritable Class WeekDayKbn : Inherits ConstItemBase
        Private Shared _items As New List(Of WeekDayKbn)

        Public Shared ReadOnly Sun As New WeekDayKbn(1, "日曜日", "日")
        Public Shared ReadOnly Mon As New WeekDayKbn(2, "月曜日", "月")
        Public Shared ReadOnly Tue As New WeekDayKbn(3, "火曜日", "火")
        Public Shared ReadOnly Wed As New WeekDayKbn(4, "水曜日", "水")
        Public Shared ReadOnly Thr As New WeekDayKbn(5, "木曜日", "木")
        Public Shared ReadOnly Fri As New WeekDayKbn(6, "金曜日", "金")
        Public Shared ReadOnly Sat As New WeekDayKbn(7, "土曜日", "土")

        Private Sub New(ByVal cd As Integer, ByVal name As String, ByVal aliasname As String)
            MyBase.new(cd, name, aliasname)
            _items.Add(Me)
        End Sub

        Public Shared Function GetValues() As List(Of KinshuCd)
            Return _items
        End Function

        Public Shared Function GetItem(ByVal cd As Integer) As KinshuCd
            Dim filter As New ConstItemFilter(Of Integer)(cd)
            Return _items.Find(AddressOf filter.IsMatchCd)
        End Function
        
    End Class
End Namespace

実際の使用方法
'月曜日の別名をラベルに表示
Me.Label1.Text = Constant.WeekDayKbn.Mon.AliasName

'曜日コード1に該当する曜日名をラベルに表示
Me.Label1.Text = Constant.WeekDayKbn.GetItem(1).Name

'コンボボックスのデータソースに設定
Me.ComboBox1.ValueMember = "Cd"
Me.ComboBox1.DisplayMember = "Name"
Me.ComboBox1.DataSouce = Constant.WeekDayKbn.GetValues

2009年10月19日月曜日

.NET(Mobile) 回避できなかった問題

リンクコントロールを継承したカスタムコントロールを作成し、デザイナでフォームに配置すると描画が正しく行われない。

リンクコントロールでTabStopプロパティをデザイナでFalseに設定しても、ビルドするとTrueに戻ってしまう。

リンクコントロールのTabStopプロパティをコードでFalseに設定しても、下矢印キーでFocus移動させるとFocus出来てしまう。

TextBoxのValidatingイベントやLostFocusイベントでTextBoxにFocusさせると、SIPから数字以外の入力を受け付けなくなる。(X04HT限定?)

2009年10月13日火曜日

.NET(Mobile) フォームのActiveControlを探す

CompactFrameworkでフォームのActiveControlを探す方法です。
ComapactFrameworkではFormクラスのActiveControlプロパティがサポートされていません。


Public Class MyForm
    Inherits System.Windows.Forms.Form

    Public Overridable Property ActiveControl() As Control
        Get
            Return GetFocusedControl(Me)
        End Get
        Set(ByVal Value As Control)
             If (Not (Value.Focused)) Then
                Value.Focus()
             End If
        End Set
    End Property


    Private Function GetFocusedControl(ByRef parent As Control) As Control
        If (parent.Focused) Then
            Return parent
        End If

         For Each ctrl As Control In parent.Controls
             Dim temp As Control = GetFocusedControl(ctrl)
             If (Not (temp Is Nothing)) Then
                 Return temp
             End If
         Next

        Return Nothing
    End Function
End Class

.NET(Mobile) コントロールの移動

CompactFrameworkでコントロール間をEnterキーと上下矢印キーで移動する方法です。

まず通常のコントロールでEnterキーと上下矢印キーのデフォルト操作をまとめました。
使用した機種はX04HTです。機種によりデフォルト操作が異なります。
コントロールEnterキー上下矢印キー
TextBox動作なし動作なし
ComboBoxドロップダウンリストの展開リストアイテムの選択
DateTimePickerカレンダーの表示値のインクリメント
NumericUpDown動作なし値のインクリメント
CheckBoxチェックON/OFFコントロールの移動
RadioButton動作なしコントロールの移動
LinkLabelClickイベント発生コントロールの移動
ButtonClickイベント発生コントロールの移動

TextBoxではMultiLineプロパティがFalseであればコントロールを移動するようにします。
Enterキーではモバイル開発 TextBoxのTextAlignプロパティの対策を入れる必要もあります。

ComboBox、DateTimePickerではEnterキーのデフォルト操作「ドロップダウンリストの展開」は残し、上下矢印キーはドロップダウンリストが展開していない場合はコントロールを移動とすると操作性が良いと思います。
ドロップダウンが展開しているかどうかはモバイル開発 Controlのドロップダウンが展開されているかを取得するを見てください。

NumericUpDownはどうしますか・・・

コントロールをEnterキーで移動するサンプル
Private Sub KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs)
    Select Case e.KeyChar
     Case Chr(Keys.Enter)
        Call Api.keybd_event(Api.VK_TAB, 0, 0, 0)
        Call Api.keybd_event(Api.VK_TAB, 0, Api.KEYEVENTF_KEYUP, 0)
        e.Handled = True
    End Select
End Sub


コントロールを上下矢印キーで移動するサンプル
Private Sub KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs)
    Select Case e.KeyCode
     Case Keys.Up
         Call Api.keybd_event(Api.VK_SHIFT, 0, 0, 0)
         Call Api.keybd_event(Api.VK_TAB, 0, 0, 0)
         Call Api.keybd_event(Api.VK_TAB, 0, Api.KEYEVENTF_KEYUP, 0)
         Call Api.keybd_event(Api.VK_SHIFT, 0, Api.KEYEVENTF_KEYUP, 0)
         e.Handled = True

     Case Keys.Down
        Call Api.keybd_event(Api.VK_TAB, 0, 0, 0)
        Call Api.keybd_event(Api.VK_TAB, 0, Api.KEYEVENTF_KEYUP, 0)
        e.Handled = True
    End Select
End Sub


API
Public Class Api
    Public Const VK_SHIFT As Integer = &H10
    Public Const VK_TAB As Integer = &H9
    Public Const KEYEVENTF_KEYUP As Integer = &H2

     _
    Public Shared Function keybd_event(ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer) As Integer
    End Function
End Class

.NET(Mobile) Controlのドロップダウンが展開されているかを取得する

CompactFrameworkでComboBoxやDateTimePickerのドロップダウンリストが展開されているかどうかを取得するサンプルです。
CompactFrameworkではDroppedDownプロパティがサポートされていないのでAPIを使用します。

Dim isDroppedDown As boolean
Dim cbo As ComboBox = Me.ComboBox1
If Api.SendMessage(cbo.Handle, Api.GETDROPPEDSTATE, 0, 0) = 1 Then
    isDroppedDown = True
Else
    isDroppedDown = False
End If


API
Public Class Api
    Public Const GETDROPPEDSTATE As Integer = &H157
     _
    Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
    End Function
End Class

.NET(Mobile) メモリ使用量を表示する

ComactFrameworkでモバイルのメモリ使用量を表示するサンプルです。

Public Class Memory
    Public Structure MEMORYSTATUS
         Public dwLength As Integer
         Public dwMemoryLoad As Integer
         Public dwTotalPhys As Integer         '合計 物理メモリ
         Public dwAvailPhys As Integer         '空き 物理メモリ
         Public dwTotalPageFile As Integer
         Public dwAvailPageFile As Integer
         Public dwTotalVirtual As Integer      '合計 仮想メモリ
         Public dwAvailVirtual As Integer      '空き 仮想メモリ
    End Structure

     _
    Public Shared Function GlobalMemoryStatus(ByRef ms As MEMORYSTATUS) As Integer
    End Function

     _
    Public Shared Function GetSystemMemoryDivision(ByRef lpdwStorePages As Integer, ByRef ldpwRamPages As Integer, ByRef ldpwPageSize As Integer) As Integer
    End Function


    Public Shared Sub ShowMemory()
        Dim storePages As Integer
        Dim ramPages As Integer
        Dim pageSize As Integer
        Dim res As Integer = GetSystemMemoryDivision(storePages, ramPages, pageSize)

        Dim memStatus As New MEMORYSTATUS
        GlobalMemoryStatus(memStatus)

        Dim MemoryInfo As New System.Text.StringBuilder
        MemoryInfo.AppendLine("合計物理メモリ: " & memStatus.dwTotalPhys.ToString("#,##0"))
        MemoryInfo.AppendLine("使用物理メモリ: " & (memStatus.dwTotalPhys - memStatus.dwAvailPhys).ToString("#,##0"))
        MemoryInfo.AppendLine("空き物理メモリ: " & memStatus.dwAvailPhys.ToString("#,##0"))
        MemoryInfo.AppendLine("使用率:" & CInt(((memStatus.dwTotalPhys - memStatus.dwAvailPhys) / memStatus.dwTotalPhys) * 100) & "%")
        MemoryInfo.AppendLine()
        MemoryInfo.AppendLine("合計仮想メモリ: " & memStatus.dwTotalVirtual.ToString("#,##0"))
        MemoryInfo.AppendLine("使用仮想メモリ: " & (memStatus.dwTotalVirtual - memStatus.dwAvailVirtual).ToString("#,##0"))
        MemoryInfo.AppendLine("空き仮想メモリ: " & memStatus.dwAvailVirtual.ToString("#,##0"))
        MemoryInfo.AppendLine("使用率:" & CInt(((memStatus.dwTotalVirtual - memStatus.dwAvailVirtual) / memStatus.dwTotalVirtual) * 100) & "%")
        MemoryInfo.AppendLine()
        MemoryInfo.AppendLine("GC.GetTotalMemory:" & GC.GetTotalMemory(False).ToString("#,##0"))
        System.Windows.Forms.MessageBox.Show(MemoryInfo.ToString())
    End Sub
End Class



Memory.ShowMemory()

.NET(Mobile) TextBoxのTextAlignプロパティ

CompactFramework標準のTextBoxではTextAlignプロパティの選択肢はLEFTしかありません。
これはTextBoxのMultiLineをTrueにすることでTextALignプロパティの選択肢がLEFT、RIGHT、CENTERになります。
もちろんEnterキー押下時に改行しないようにしなければなりません。

雑記 腰痛対策のイス

みなさんはどんなイスでお仕事してますかー?

私は自宅で仕事をしているのですが、仕事部屋にクーラーがないのです。
今年の夏はクーラーのある部屋で座イスで仕事をしていました。
その頃から胃の調子が悪くなり1日中気分が悪くて食事もあまりできませんでした。
病院に行って胃の検査をしてもらわないと・・・と考えていました。

秋になりクーラーも必要なくなったので仕事部屋でPC用のイスで仕事を始めたところ
胃の不快感が良くなってきたのです。
たぶん座イスでは姿勢が悪いので胃が圧迫されていたのでしょう。

しかーし、PC用のイスで仕事をしだして2週目ぐらいのとき仕事もピークで1日12時間も座っていると
腰が痛くて歩くのも立つのも痛い!!
やっぱり3,980円の安物イスではダメですね。

おもいきって5万円のイスに変えたら、とても快適です(*´∀`*)
イスって大事ですね~

ちなみに私が買ったイスはコレです。
DUOREST DR-7900

.NET(Mobile) おすすめコントロール集

久しぶりの更新です。
モバイルの開発がちょっと忙しかったので、JAVAの試験勉強とブログの更新をサボっていました(いいわけ)。
年内の仕事はあるけれど(・・・年明けの仕事はない・・・・)かな~り暇なので、ブログ更新と試験勉強の再開です。


まずはモバイル開発(CompactFramework)のメモから

モバイル開発で最初につまづくのはコントロールのショボサです。
こういうことしたいのに、コントロールがない!
自分で作るには時間もないし面倒・・・


そんなときはコレがお勧めです!!
Resco MobileForms Toolkit

お値段はStandard Editionで$599.95。
今は円高なので購入のチャンスです。


今回はこのコントロール集のSmartGridコントロール、AdvanceListコントロール、ImageButtonコントロールを使用しました。

SmartGridは入力可能で、行選択モードなどもあり、画像も表示出来ます。
標準での入力はテキストボックス、チェックボックスですが、カスタムでWindowsFormsControlが使用できます。
自由自在にカスタマイズできるとは言い難いですが、標準のグリッドに比べれば大変優秀です。
タッチスクロールが可能で、スクロール方向、スクロールスピードを調整できます。



AdvanceListコントロールは展開可能なアコーディオンコントロールみたいな感じです。
モバイルの画面は小さいので一覧画面で使用すると効果的です。
選択していないときは最小限の情報だけを表示し、行を選択すると展開し詳細な情報を表示できます。
標準でリンクコントロールやボタンコントロール、画像を配置できますが、基本的に表示のみのコントロールです。
入力可能のセルを配置することも一応は可能です。
タッチスクロールが可能で、スクロール方向、スクロールスピードを調整できます。



ImageButtonコントロールは画像を配置できるコントロールです。
画像ボタンだけでなく、通常のボタン、リンクコントロールの代用もできます。
画像と文字の配置を調整できるのがうれしいです。




まったく問題がないかといえばウソになりますが、WindowsFormsControlに比べれば
非常に優秀ですっ!!


問題はサポートが英語なこと。
そして購入すると英語で電話がかかってきます。ヽ(д`ヽ)。。オロオロ。。(ノ´д)ノ

2009年6月15日月曜日

Java スレッドの一時停止、再開、終了

スレッドの終了方法


runメソッドを終了すると、そのスレッドは解放されなくなります。
ですのでrunメソッドを停止するフラグ変数を用意して、その変数を変更することによって、runメソッドが終了するようにします。

class MyThread extends Thread {
boolean end = false;

public void run() {
while(!end){
//end変数がfalseの間処理を繰り返す。
}
}
}


スレッドの休止方法


スレッドを一時停止するにはwaitメソッドを使用します。
※wait、notify、notifyAllはsynchronized指定がされたメソッド・ブロックでのみ使用できます。

スレッドの再開方法


一時停止したスレッドを再開するにはnotifyメソッドを使用します。
※wait、notify、notifyAllはsynchronized指定がされたメソッド・ブロックでのみ使用できます。

synchrnonizedメソッド・synchrnonized構文


synchronized 修飾されたメソッド/ブロックは、1つのスレッドからしか実行されません。他のスレッドがアクセスしようとすると先に実行しているスレッドの処理が終了するまで待機します。
つまり、複数のスレッドが同じ変数にアクセスすると不整合が発生する可能性がありますが、synchronized 修飾されたメソッド/ブロックはマルチスレッドによる同時アクセスを行わない為、不整合の発生を防ぐことができます。

synchronized 修飾されたメソッド
メソッドの処理を行っている間、そのメソッドに外部からアクセスできないようにします。


synchronized 構文
ブロック内の処理を行っている間、引数に指定したインスタンスに外部からアクセスできないようにします。
synchronized(ブロックするインスタンス){
//実行する処理
}




以下のサンプルはRunボタンでスレッドを開始し、Waitボタンでスレッドの一時停止/再開、Endボタンでスレッドを終了します。
package multiThreadSample;

import java.awt.Button;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ThreadSample03 extends Frame implements ActionListener{

private static final long serialVersionUID = 1L;

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

Label lbl1;
Button btnRun1;
Button btnWait1;
Button btnEnd1;

MyThread3 t1 = null;

public ThreadSample03(){ 
this.setTitle("ThreadSample01");
this.setSize(300,300);
this.setLayout(new GridLayout(2,1));

lbl1 = new Label();
this.add(lbl1);
Panel p1 = new Panel();
btnRun1 = new Button("Run");
btnRun1.addActionListener(this);
btnWait1 = new Button("Wait");
btnWait1.addActionListener(this);
btnEnd1 = new Button("End");
btnEnd1.addActionListener(this);
p1.add(btnRun1);
p1.add(btnWait1);
p1.add(btnEnd1);
this.add(p1);

this.setVisible(true);
}

public void actionPerformed(ActionEvent e) {
if (e.getSource() == btnRun1){
t1 = new MyThread3(lbl1,500);
t1.start();
}else if (e.getSource() == btnWait1){
t1.setStop();
}else if (e.getSource() == btnEnd1){
t1.stopRun();
}
} 
}

class MyThread3 extends Thread {
boolean end = false; 
boolean stop = false;
Label lbl;
int time;  


public MyThread3(Label lbl, int time){
this.lbl = lbl;
this.time = time;   
}

public void run() {
int i = 0;
while(!end){
lbl.setText("Count:" + i);
i++;
try {
Thread.sleep(time);
synchronized(this){
if (stop) wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public void stopRun(){
stop = true;
}

public synchronized void setStop() {
stop = !stop;
if (!stop) {
notify();
}

}


}

2009年6月14日日曜日

Java マルチスレッド

スレッドとはプログラムの処理単位のことです
マルチスレッドとは同時に複数の処理を並行して行うことを言います。
マルチスレッドを実現するにはjava.lang.Threadクラスを継承する方法と、java.lang.Runnableインターフェースを実装する方法があります。


java.lang.Threadクラスを継承する方法


Threadを継承するクラスはrunメソッドをオーバーライドします。
package multiThreadSample;

import java.awt.Button;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ThreadSample01 extends Frame implements ActionListener{

private static final long serialVersionUID = 1L;

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

Label lbl1;
Label lbl2;
Button btnRun;

public ThreadSample01(){
this.setTitle("ThreadSample01");
this.setSize(300,300);
this.setLayout(new GridLayout(4,1));

lbl1 = new Label();
this.add(lbl1);
lbl2 = new Label();
this.add(lbl2);

Panel p1 = new Panel();

btnRun = new Button("Run");
btnRun.addActionListener(this);
p1.add(btnRun);

this.add(p1);

this.setVisible(true);
}

public void actionPerformed(ActionEvent arg0) {
MyThread t1 = new MyThread(lbl1,500);
t1.start();

MyThread t2 = new MyThread(lbl2,1000);
t2.start();

}
}


class MyThread extends Thread{
Label lbl;
int time;

public MyThread(Label lbl, int time){
this.lbl = lbl;
this.time = time;
}

public void run() {
for (int i = 0; i < 100; i++){
lbl.setText("Count:" + i);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}


}

java.lang.Runnableインターフェースを実装する方法

Runnableインターフェースをを実装するクラスもrunメソッドをオーバーライドします。
class MyClass implements Runnable {
public void run(){
//マルチスレッドで実行する処理を記述します。
}
}
ThreadクラスのインスタンスするコンストラクタにRunnableインターフェースをを実装するクラスのインスタンスを指定し、 Threadクラスのstartメソッドを実行することによって、Runnableインターフェースをを実装するクラスのrunメソッドが呼び出されスレッドが起動します。
Thread t = new Thread(new MyClass());
t.start();
以下の例では1つめのスレッドでラベル1に500ミリ秒間隔で数字をカウントアップした値を表示し、2つめのスレッドでラベル2に1000ミリ秒間隔で数字をカウントアップした値を表示します。
package multiThreadSample;

import java.awt.Button;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ThreadSample02 extends Frame implements ActionListener{

private static final long serialVersionUID = 1L;

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

Label lbl1;
Label lbl2;
Button btnRun;

public ThreadSample02(){
this.setTitle("ThreadSample02");
this.setSize(300,300);
this.setLayout(new GridLayout(3,1));

lbl1 = new Label();
this.add(lbl1);
lbl2 = new Label();
this.add(lbl2);

Panel p1 = new Panel();
btnRun = new Button("Run");
btnRun.addActionListener(this);
p1.add(btnRun);
this.add(p1);

this.setVisible(true);
}

public void actionPerformed(ActionEvent arg0) {
Thread t1 = new Thread(new MyThread(lbl1,500));
t1.start();

Thread t2 = new Thread(new MyThread(lbl2,1000));
t2.start();

} 
}

class MyThread implements Runnable{
Label lbl;
int time;

public MyThread(Label lbl, int time){
this.lbl = lbl;
this.time = time;
}

public void run() {
for (int i = 0; i < 100; i++){
lbl.setText("Count:" + i);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

}

2009年6月10日水曜日

Java XMLEncoder、XMLDecoderを使用したオブジェクトの保存(シリアライズ/デシリアライズ)その1

オブジェクトの状態をXMLファイルに保存(シリアライズ)したり、XMLファイルかデータを読み込みオブジェクトを復元(デシリアライズ)したりするには
java.beans.XMLEncoderクラスとjava.beans.XMLDecorderクラスを使用します。
※Javaではシリアライズ/デシリアライズを行うためにjava.io.ObjectOutputStream とjava.io.ObjectInputStreamを使用してバイナリファイルに読み書きを行っていたらしいのですが、色々問題があったようでJDK 1.4からシリアライズの新たな機能としてXMLファイルにオブジェクトの状態を読み書きするjava.beans.XMLEncoder、java.beans.XMLDecoderクラスが追加されたそうです。



まずはFrameに配置したTextAreaの状態(入力内容や色、フォントなど)をXMLファイルに読み書きします。

package FileAccess;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class SerializableSample01 extends Frame implements ActionListener{

private static final long serialVersionUID = 1L;

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

Button btnSave;
Button btnLoad;
TextArea ta;

public SerializableSample01(){
this.setTitle("SerializableSample01");
this.setSize(300, 300);

ta = new TextArea();
this.add(ta,BorderLayout.CENTER);

Panel p1 = new Panel();
btnSave = new Button("Save");
btnSave.addActionListener(this);
btnLoad = new Button("Load");
btnLoad.addActionListener(this);
p1.add(btnSave);
p1.add(btnLoad);
this.add(p1,BorderLayout.SOUTH);

this.setVisible(true);
}


public void actionPerformed(ActionEvent arg0) {
if (arg0.getSource() == btnSave){
save();
}else if (arg0.getSource() == btnLoad){
load();
}
}

/*
* テキストエリアの状態をXMLファイルに書き込みます。
*/
private void save(){
FileOutputStream fos = null;
BufferedOutputStream bos = null;
XMLEncoder encoder = null;

try {
fos = new FileOutputStream("D:/SerializableSample01.xml");
bos = new BufferedOutputStream(fos);
encoder = new XMLEncoder(bos);

encoder.writeObject(ta);

} catch (FileNotFoundException e) {
e.printStackTrace();
} finally { 
if (encoder != null){
encoder.close();
}
}

//テキストエリアを削除します。
this.remove(ta);
ta = null;
this.validate();   
}

/*
* テキストエリアの状態をXMLファイルから読み取ります。
*/
private void load(){
FileInputStream fis = null;
BufferedInputStream bis = null;
XMLDecoder decoder = null;

try {
fis = new FileInputStream("D:/SerializableSample01.xml");
bis = new BufferedInputStream(fis);
decoder = new XMLDecoder(bis);

ta = (TextArea)decoder.readObject();

} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (decoder != null){ 
decoder.close();
}
}

//テキストエリアを追加します。
this.add(ta,BorderLayout.CENTER);
this.validate();
}

}


まずテキストエリアに書き込みます。


saveボタンでテキストエリアの状態をシリアライズして、フレームからテキストエリアを削除します。


loadボタンでテキストエリアの状態を復元し、フレームに追加します。



テキストエリアの状態を保存したXMLファイルの内容です。
 
 
 
 
 
255 
255 
255 
255 
 
 
 
28 
 
 
text0 
 
 
28 
 
 
28 
 
 
シリアライズ

デシリアライズ

サンプルです。 
 
 
 


XMLEncoderクラス、XMLDecoderクラスで読み書きできるオブジェクト



XMLEncoderクラス、XMLDecoderクラスで読み書きできるオブジェクトは
デフォルトコントラスタが必ずあること。
インスタンス変数にアクセスするためのアクセッサが定義されていること。
アクセッサの名前はset変数名、get変数名(booleanを返す場合is変数名でもOK)であること。



簡単なクラスを作成し、そのオブジェクトをXMLEncoderクラス、XMLDecoderクラスで読み書きしてみます。


名前と年齢をフィールドに持つEmployeeクラス
package FileAccess;

public class Employee {
private String _name;
private int _age;

public Employee(){
_name = "No Name";
_age = 0;
}

public Employee(String name, int age){
_name = name;
_age = age;
}

public void setName(String value){ _name = value; }
public String getName(){ return _name; }

public void setAge(int value){ _age = value; }
public int getAge(){ return _age; }

}


EmployeeクラスをXMLに書き込み、再度そのXMLを読み込みEmployeeクラスを復元して名前と年齢をコンソールに出力します。
package FileAccess;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class SerializableSample02 {

public static void main(String args[]){

Employee emp = new Employee("yan",25);

FileOutputStream fos = null;
BufferedOutputStream bos = null;
XMLEncoder enc = null;
try {
fos = new FileOutputStream("D:/Employee.xml");
bos = new BufferedOutputStream(fos);
enc = new XMLEncoder(bos);

enc.writeObject(emp);
enc.flush();

} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (enc != null){
enc.close();
}
}

FileInputStream fis = null;
BufferedInputStream bis = null;
XMLDecoder dec = null;

try {
fis = new FileInputStream("D:/Employee.xml");
bis = new BufferedInputStream(fis);
dec = new XMLDecoder(bis);

Employee newEmp = (Employee)dec.readObject();

System.out.println(newEmp.getName());
System.out.println(newEmp.getAge());

} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (dec != null){
dec.close();
}
}
}
}

Java DataInputStreamクラス、DataOutputStreamクラスを使用してバイナリファイルの読み書きを行う

DataInputStreamクラス、DataOutputStreamクラスを使用してバイナリファイルの読み書きを行います。

DataInputStreamはint型やboolean型といったプリミティブ型およびString型の値としてバイナリファイルのバイトデータを読み込みます。

boolean readBoolean()
1 バイトの入力データを読み込んで、そのバイトがゼロ以外の場合は true、そのバイトがゼロの場合は false を返します。
byte readByte()
1 バイトの入力データを読み込んで返します。
char readChar()
入力データの char を読み込んで、char 値を返します。
double readDouble()
8 バイトの入力データを読み込んで、double 値を返します。
float readFloat()
4 バイトの入力データを読み込んで、float 値を返します。
void readFully(byte[] b)
入力ストリームから数バイトを読み込み、それをバッファー配列 b に格納します。
void readFully(byte[] b, int off, int len)
入力ストリームから len バイトを読み込みます。
int readInt()
4 バイトの入力データを読み込んで、int 値を返します。
String readLine()
入力ストリームから、次の行のテキストを読み込みます。
long readLong()
8 バイトの入力データを読み込んで、long 値を返します。
short readShort()
2 バイトの入力データを読み込んで、short 値を返します。
int readUnsignedByte()
1 バイトの入力データを読み込んで、int 型にゼロ拡張して結果を返します。
int readUnsignedShort()
2 バイトの入力データを読み込んで、0 0 65535 の範囲の int 値を返します。
String readUTF()
修正 UTF-8 形式でエンコードされた文字列を読み込みます。





DataOutputStreamクラスも同じくint型やboolean型といったプリミティブ型およびString型の値をバイナリファイルのバイトデータとして書き込みます。

void write(byte[] b)
出力ストリームに配列 b のすべてのバイトを書き込みます。
void write(byte[] b, int off, int len)
配列 b から len バイトを順番に出力ストリームに書き込みます。
void write(int b)
引数 b の下位 8 ビットを出力ストリームに書き込みます。
void writeBoolean(boolean v)
1 つの boolean 値を出力ストリームに書き込みます。
void writeByte(int v)
引数 v の下位 8 ビットを出力ストリームに書き込みます。
void writeBytes(String s)
文字列を出力ストリームに書き込みます。
void writeChar(int v)
2 バイトから構成される char 値を出力ストリームに書き込みます。
void writeChars(String s)
文字列 s 内の各文字を、1 文字ごとに 2 バイトずつ出力ストリームに順番に書き込みます。
void writeDouble(double v)
8 バイトから構成される double 値を出力ストリームに書き込みます。
void writeFloat(float v)
4 バイトから構成される float 値を出力ストリームに書き込みます。
void writeInt(int v)
4 バイトから構成される int 値を出力ストリームに書き込みます。
void writeLong(long v)
8 バイトから構成される long 値を出力ストリームに書き込みます。
void writeShort(int v)
引数の値を表す 2 バイトを出力ストリームに書き込みます。
void writeUTF(String str)
長さ情報の 2 バイトを出力ストリームに書き込みます。


DataInputStreamクラスで読み取れるバイナリファイルはDataOutputStreamクラスを使用して作成したファイルだけです。
そのためアプリケーション独自で読み書きするバイナリファイルに限られます。

package FileAccess;

import java.awt.Button;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class BinaryFileSample03 extends Frame implements ActionListener{

private static final long serialVersionUID = 1L;

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


Button btnWrite;
Button btnRead;

public BinaryFileSample03(){
this.setTitle("BinaryFileSample03");
this.setSize(300,100);

btnWrite = new Button("Write");
btnWrite.addActionListener(this);
btnRead = new Button("Read");
btnRead.addActionListener(this);
Panel p1 = new Panel();
p1.add(btnWrite);
p1.add(btnRead);
this.add(p1);

this.setVisible(true);
}

public void actionPerformed(ActionEvent arg0) {
if (arg0.getSource() == btnWrite){
write();
}else if (arg0.getSource() == btnRead){
read();
}
}

/*
* 書込み
*/
private void write(){
FileOutputStream fos = null;
BufferedOutputStream bos = null;
DataOutputStream dos = null;

try {
fos = new FileOutputStream("D:/BinaryFileSample03.txt");
bos = new BufferedOutputStream(fos);
dos = new DataOutputStream(bos);

dos.writeBoolean(false);
dos.writeInt(50);
dos.writeBoolean(true);
dos.writeUTF("文字列1");
dos.writeInt(100);
dos.writeUTF("文字列2");

dos.flush();

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dos != null){
dos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}  
}

/*
* 読込み
*/
private void read(){
FileInputStream fis = null;
BufferedInputStream bis = null;
DataInputStream dis = null;

try {
fis = new FileInputStream("D:/BinaryFileSample03.txt");
bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);

boolean b1 = dis.readBoolean();
int i1 = dis.readInt();
boolean b2 = dis.readBoolean();
String s1 = dis.readUTF();
int i2 = dis.readInt(); 
String s2 = dis.readUTF();

System.out.println(b1);
System.out.println(b2);
System.out.println(i1);
System.out.println(i2);
System.out.println(s1);
System.out.println(s2);

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dis != null){
dis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

Java バイナリファイルを効率的に読み書きする

BufferedInputStreamとBufferedOutputStreamを使用してバイナリファイルより効率的にデータを読み書きします。

BufferdInputStreamは使用方法はFileInputStreamと同じですが、FileInputStreamはreadメソッドが呼ばれるたびにファイルアクセスするのに対し
BufferedInputStreamは1回のreadメソッドで数バイトをあらかじめ取得しバッファに保存します。そのバッファから値を取り出し返します。

BufferdOutputStreamのwriteメソッドはバッファに対し書き込みを行い、flushメソッドでファイルに書き込みます。


バイナリファイルから1バイトづつ読み込み、1バイトづつ書き込みますで使用したコードを
BufferedInputStreamとBufferedOutputStreamを使用して書き換えます。

下記のコードはBufferedInputStreamとBufferedOutputStreamを使用して「D:/Sample1.jpg」より1バイト読み込み、「D:/CopySample1.jpg」に1バイト書き込みます。
package FileAccess;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class BinaryFileSample02 {
public static void main(String args[]){
new BinaryFileSample01();
}

public BinaryFileSample02(){
FileInputStream fip = null;
BufferedInputStream bis = null;

FileOutputStream fos = null;
BufferedOutputStream bos = null;

try {
fip = new FileInputStream("D:/Sample1.jpg");
bis = new BufferedInputStream(fip);

fos = new FileOutputStream("D:/CopySample1.jpg");
bos = new BufferedOutputStream(fos);

int data;
while ((data = bis.read()) != -1){
bos.write(data);
}
bos.flush();

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{

try {
if (bis != null){
bis.close();
}
} catch (IOException e) {
e.printStackTrace();
}

try {
if (bos != null){
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}

}

}
}

Java バイナリファイルから1バイトづつ読み込み、1バイトづつ書き込みます。

バイナリファイルから1バイトづつ読み込むには
FilreInputStreamクラスのreadメソッドを使用します。
readメソッドはファイルの最後に達すると-1を返します。

int read()
入力ストリームから 1 バイトを読み込みます。
int read(byte[] b)
入力ストリームから最大 b.length バイトをバイト配列に読み込みます。
int read(byte[] b, int off, int len)
入力ストリームからバイト配列へ最大 len バイトのデータを読み込みます。



1バイトづつバイナリファイルへ書き込むにはFileOutputStreamクラスのwriteメソッド使用します。

void write(int b)
指定されたバイトデータをファイル出力ストリームに書き込みます。
void write(byte[] b)
指定されたバイト配列の b.length バイトをこのファイル出力ストリームに書き込みます。
void write(byte[] b, int off, int len)
指定されたバイト配列からのオフセット位置 off から始まる len バイトをこのファイル出力ストリームに書き込みます。


参考:テキストファイルの場合とほとんど同じです。
テキストファイルから1文字づつ文字を読み込む
テキストファイルに文字を書き込む

下記のコードは「D:/Sample1.jpg」より1バイト読み込み、「D:/CopySample1.jpg」に1バイト書き込みます。
package FileAccess;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;


public class BinaryFileSample01{

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

public BinaryFileSample01(){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("D:/Sample1.jpg");
fos = new FileOutputStream("D:/CopySample1.jpg");
int data;
while ((data = fis.read()) != -1){
fos.write(data);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{

try {
if (fis != null){
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}

try {
if (fos != null){
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}

}

}
}

2009年6月9日火曜日

Java テキストファイルに文字をまとめて書き込む

バッファに文字を書き込み、書き込んだ文字をまとめてファイルに書き込みます。
ますFileWriterクラスのコンストラクタに書き込むファイルのパスを指定し、FileWriterインスタンスを作成します。
つぎにBufferedWriterクラスのコンストラクタにFileWriterインスタンスを指定し、BufferedWriterインスタンスを作成します。
BufferedWriterクラスのwriteメソッドを使用し、バッファに文字列を書き込んでいきます。
BufferedWriterクラスのflushメソッドを使用し、ファイルに書き込みを行います。
最後に使い終わったBufferedWriterはcloseメソッドを使用して、ファイルを閉じます。
closeメソッドでもflushメソッドが呼ばれます。

またBufferedWriterクラスのnewlineメソッドはOSの標準改行文字を出力します。

package FileAccess;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class FileWriteSample02 extends Frame implements ActionListener{
private static final long serialVersionUID = 1L;

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

Frame frm = this;
TextArea txtBody;
Button btnSave;

public FileWriteSample02(){
this.setTitle("FileWriteSample02");
this.setSize(300,300);


txtBody = new TextArea();
this.add(txtBody,BorderLayout.CENTER);

btnSave = new Button("Save");
btnSave.addActionListener(this);

Panel pnl = new Panel();
pnl.add(btnSave);  
this.add(pnl,BorderLayout.SOUTH);

this.setVisible(true);
}

public void actionPerformed(ActionEvent ev){
SaveFile();
}

/*
* ファイルを保存します。
*/
private void SaveFile(){
//名前を付けて保存ダイアログを表示します。
String path = null;
FileDialog fd = new FileDialog(this , "名前を付けて保存" , FileDialog.SAVE);
try{
fd.setVisible(true);
if (fd.getFile() != null){
path = fd.getDirectory() + fd.getFile();
}
}finally{
fd.dispose();
}
//ファイルパスがnullの場合は処理を中止します。
if (path == null){
return; 
}
//テキストエリアの内容をファイルに書き込みます。
FileWriter fw = null;
BufferedWriter bw = null;
try {
fw = new FileWriter(path);
bw = new BufferedWriter(fw);
bw.write(txtBody.getText());
bw.newLine();
bw.append("追加書き込み");
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if (bw != null){
bw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}



PrintWriterクラスを使用する


PrintWriterクラスのprintメソッドやprintlnメソッドを使用してファイルへの書き込みを行います。
BufferedWriterクラスのwriteメソッドは、引数として文字列しか受け取れませんが
PrintWriterクラスのprintメソッドや、printlnメソッドは引数として文字列以外にもint型やboolean型などのプリミティブ型を受け取ることができ、それをそのまま文字列として出力します。
printlnメソッドの場合は最後に改行を行います。
また、PrintWriterクラスのcloseメソッドは例外をスローしません。

package FileAccess;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class FileWriteSample03 extends Frame implements ActionListener{
private static final long serialVersionUID = 1L;

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

Frame frm = this;
TextArea txtBody;
Button btnSave;

public FileWriteSample03(){
this.setTitle("FileWriteSample03");
this.setSize(300,300);


txtBody = new TextArea();
this.add(txtBody,BorderLayout.CENTER);

btnSave = new Button("Save");
btnSave.addActionListener(this);

Panel pnl = new Panel();
pnl.add(btnSave);  
this.add(pnl,BorderLayout.SOUTH);

this.setVisible(true);
}

public void actionPerformed(ActionEvent ev){
SaveFile();
}

/*
* ファイルを保存します。
*/
private void SaveFile(){
//名前を付けて保存ダイアログを表示します。
String path = null;
FileDialog fd = new FileDialog(this , "名前を付けて保存" , FileDialog.SAVE);
try{
fd.setVisible(true);
if (fd.getFile() != null){
path = fd.getDirectory() + fd.getFile();
}
}finally{
fd.dispose();
}
//ファイルパスがnullの場合は処理を中止します。
if (path == null){
return; 
}
//テキストエリアの内容をファイルに書き込みます。
FileWriter fw = null;
BufferedWriter bw = null;
PrintWriter pw = null;
try {
fw = new FileWriter(path);
bw = new BufferedWriter(fw);
pw = new PrintWriter(bw);

pw.println(txtBody.getText());
pw.println(10);
pw.println(true);
pw.println("文字列");
pw.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
if (pw != null){
pw.close();
}
}
}
}

Java テキストファイルに文字を書き込む

FileWriterクラスのwriteメソッドを使用してファイルに文字を書き込みます。
FileWriterクラスのコンストラクタには書き込むファイルのパスを指定します。
コンストラクタの第2引数にtrueを指定すると、ファイルへの追加書き込みを行います。

package FileAccess;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileWriter;
import java.io.IOException;


public class FileWriteSample01 extends Frame implements ActionListener{
private static final long serialVersionUID = 1L;

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

Frame frm = this;
TextArea txtBody;
Button btnSave;

public FileWriteSample01(){
this.setTitle("FileWriteSample01");
this.setSize(300,300);


txtBody = new TextArea();
this.add(txtBody,BorderLayout.CENTER);

btnSave = new Button("Save");
btnSave.addActionListener(this);

Panel pnl = new Panel();
pnl.add(btnSave);  
this.add(pnl,BorderLayout.SOUTH);

this.setVisible(true);
}

public void actionPerformed(ActionEvent ev){
SaveFile();
}

/*
* ファイルを保存します。
*/
private void SaveFile(){
//名前を付けて保存ダイアログを表示します。
String path = null;
FileDialog fd = new FileDialog(this , "名前を付けて保存" , FileDialog.SAVE);
try{
fd.setVisible(true);
if (fd.getFile() != null){
path = fd.getDirectory() + fd.getFile();
}
}finally{
fd.dispose();
}
//ファイルパスがnullの場合は処理を中止します。
if (path == null){
return; 
}
//テキストエリアの内容をファイルに書き込みます。
FileWriter fw =null;
try {
//fw = new FileWriter(path);
//追加書き込みする場合は、第2引数にtrueを指定します。
fw = new FileWriter(path,true);
fw.write(txtBody.getText());
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if (fw != null){
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}






ファイルへ追加書き込みを行います。


Java テキストファイルから1行づつ文字を読み込む

ファイルから1行づつ文字を読み込むにはFileReaderクラスとBufferedReaderクラスを使用します。
FileReaderクラスのコンストラクタに読み込むファイルのパスを指定し、FileReaderクラスのインスタンスを作成します。
BufferedReaderクラスのコンストラクタにFileReaderクラスのインスタンスを指定し、BufferedReaderクラスのインスタンスを作成します。
BufferedReaderクラスのreadLineメソッドを使用してファイルから1行づつ文字を読み込みます。
readメソッドはファイルの終わりに達するとnullを返します。

package FileAccess;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class FileReadSample04 extends Frame implements ActionListener{
private static final long serialVersionUID = 1L;

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

Frame frm = this;
TextArea txtBody;
Button btnOpen;

public FileReadSample04(){
this.setTitle("FileReadSample04");
this.setSize(300,300);


txtBody = new TextArea();
this.add(txtBody,BorderLayout.CENTER);

btnOpen = new Button("Load");
btnOpen.addActionListener(this);

Panel pnl = new Panel();
pnl.add(btnOpen);  
this.add(pnl,BorderLayout.SOUTH);

this.setVisible(true);
}

public void actionPerformed(ActionEvent ev){
OpenFile();
}

/*
* ファイルを開きます。
*/
private void OpenFile(){
//ファイルを開くダイアログを表示します。
String path = null;
FileDialog fd = new FileDialog(this , "ファイルを開く" , FileDialog.LOAD);
try{
fd.setVisible(true);
if (fd.getFile() != null){
path = fd.getDirectory() + fd.getFile();
}
}finally{
fd.dispose();
}
//ファイルパスがnullの場合は処理を中止します。
if (path == null){
return; 
}
//ファイルから1行づつ読み込みます。
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(path);
br = new BufferedReader(fr);

StringBuilder sb = new StringBuilder();
String str;
while((str = br.readLine()) != null){
sb.append(str +"\r\n");
}

txtBody.setText(sb.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
try {
if (br != null){
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

2009年6月8日月曜日

Java テキストファイルから1文字づつ文字を読み込む

FileReaderクラスのreadメソッドを使用してファイルから1文字づつ文字を読み込みます。
readメソッドを使用して読み込んだ値は文字コードを表すint型の値として取得でき、char型にキャストすることで文字に変換します。
readメソッドはファイルの終わりに達すると-1を返します。

package FileAccess;

import java.awt.*;
import java.awt.event.*;
import java.io.*;

public class FileReadSample01 extends Frame implements ActionListener{



private static final long serialVersionUID = 1L;

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

Frame frm = this;
TextArea txtBody;
Button btnOpen;

public FileReadSample01(){
this.setTitle("FileReadSample01");
this.setSize(300,300);

txtBody = new TextArea();
this.add(txtBody,BorderLayout.CENTER);

btnOpen = new Button("Load");
btnOpen.addActionListener(this);

Panel pnl = new Panel();
pnl.add(btnOpen);  
this.add(pnl,BorderLayout.SOUTH);

this.setVisible(true);
}

public void actionPerformed(ActionEvent ev){
OpenFile();
}

/*
* ファイルを開きます。
*/
private void OpenFile(){
//ファイルを開くダイアログを表示します。
String path = null;
FileDialog fd = new FileDialog(this , "ファイルを開く" , FileDialog.LOAD);
try{
fd.setVisible(true);
if (fd.getFile() != null){
path = fd.getDirectory() + fd.getFile();
}
}finally{
fd.dispose();
}
//ファイルパスがnullの場合は処理を中止します。
if (path == null){
return; 
}
//ファイルから1文字づつ読み込みます。
FileReader fr = null;
StringBuffer sb = null;
try {
fr = new FileReader(path);
sb = new StringBuffer();
int ch;
while ((ch = fr.read()) != -1){
sb.append((char)ch);
}
txtBody.setText(sb.toString()); 
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
try {
if (fr != null){
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}


readメソッドは他にもいくつかのオーバーロードがあります。
int read()単一文字を読み込みます。
int read(char[] cbuf)引数に指定した配列に文字を読み込みます。
abstract int read(char[] cbuf,int off,int len)文字を読み込んでcbufのoffに指定したオフセット位置からlenバイト分を格納します。


ファイルの最初から10バイト分のデータを取得するするには、int read(char[] cbuf)を使用します。
FileReader fr = null;
char[] buff = new char[10];
try {
fr = new FileReader(path);
fr.read(buff);
txtBody.setText(new String(buff));
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
try {
if (fr != null){
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}


read(char[] cbuf,int off,int len)はファイルの先頭から文字を読み込んでcbufのoffに指定したオフセット位置からlenバイト分を格納します。
ファイルの先頭から文字を読み込み、buff配列のオフセットが3の位置から7バイト分を読み込みます。
FileReader fr = null;
char[] buff = new char[10];
try {
fr = new FileReader(path);
fr.read(buff,3,7);

System.out.println(new String(buff));
txtBody.setText(new String(buff,3,7));
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
try {
if (fr != null){
fr.close(); 
}
} catch (IOException e) {
e.printStackTrace();
}
}

Java AWT ファイルを開くダイアログ/名前を付けて保存ダイアログ

ファイルを開くダイアログを表示するにはFileDialogクラスを使用します。
同じく名前を付けて保存ダイアログもFileDialogクラスを使用します。

FileDialogクラスのコンストラクタ

FileDialog(Frame parent)
FileDialog(Frame parent, String title)
FileDialog(Frame parent, String title, int mode)

引数 parent
オーナーとなるフレームを指定します。
引数 title
ダイアログタイトルを指定します。
引数 mode
ファイル開くダイアログの場合は FileDialog.LOAD を指定します。
ファイルを保存ダイアログの場合は FileDialog.SAVE を指定します。


package FileAccess;

import java.awt.*;
import java.awt.event.*;

public class FileDialogSample extends Frame implements ActionListener{

private static final long serialVersionUID = 1L;

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

Label lblPath;
Button btnOpen;
Button btnSave;

public FileDialogSample(){
this.setTitle("FileDialogSample");
this.setSize(300,300);
this.setLayout(new GridLayout(2,1));

lblPath = new Label();
this.add(lblPath);

btnOpen = new Button();
btnOpen.setLabel("ファイルを開くダイアログを表示");
btnOpen.addActionListener(this);

btnSave = new Button();
btnSave.setLabel("名前を付けて保存ダイアログを表示");
btnSave.addActionListener(this);

Panel pnl1 = new Panel();
pnl1.add(btnOpen);
pnl1.add(btnSave);
this.add(pnl1);

this.setVisible(true);
}

public void actionPerformed(ActionEvent e) {
if (e.getSource() == btnOpen){
FileOpenDialog();
}else if (e.getSource() == btnSave){
FileSaveDialog();
}
}

private void FileOpenDialog(){
String path = null;
FileDialog fd = new FileDialog(this , "ファイルを開く" , FileDialog.LOAD);
try{
fd.setVisible(true);
if (fd.getFile() != null) {
path = fd.getDirectory() + fd.getFile();
}
}finally{
fd.dispose();
}
if (path != null){
lblPath.setText(path);
}else{
lblPath.setText("");
}  
}

private void FileSaveDialog(){
String path = null;
FileDialog fd = new FileDialog(this , "名前を付けて保存" , FileDialog.SAVE);
try{
fd.setVisible(true);
if (fd.getFile() != null) {
path = fd.getDirectory() + fd.getFile();
}
}finally{
fd.dispose();
}
if (path != null){
lblPath.setText(path);
}else{
lblPath.setText("");
} 
}
}

2009年6月6日土曜日

Java AWT 描画処理 まとめ

paintメソッド以外からの描画


ボタンクリックやマウスクリックなどpaintメソッド以外からの描画処理を行います。

下記のコードはマウスクリックした座標に円を描画します。
GraphicsインスタンスはコンポーネントのgetGraphicsメソッドで取得します。
getGraphicsメソッドで取得したGraphicsインスタンスは、使用後disposeします。

package graphicsSample;

import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class GraphicSample03 extends Frame{

private static final long serialVersionUID = 1L;

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

public GraphicSample03(){
this.setTitle("GraphicSample03");
this.setSize(300,300);
this.addMouseListener(new MyMouseAdapter());
this.setVisible(true);
}

private class MyMouseAdapter extends MouseAdapter{

public void mouseClicked(MouseEvent arg0) {
Graphics g = getGraphics();
try{
g.setColor(Color.darkGray);
g.drawOval(arg0.getX(), arg0.getY(), 50, 50);
}finally{
g.dispose();
}

}
} 

}






しかし、画面をリサイズすると描画が消えてしまいます。

ダブルバッファリングを利用して画面をリサイズしても描画が消えないようにする


対応策としてよく用いられているのが「ダブルバッファリング」です。
これは描画処理用のイメージ領域を別に作成し、まず必要な描画を全てそのイメージ領域に行っておいてから、最後にイメージ領域をフレームにまとめて描画します。

まずイメージ領域をインスタンスフィールドに用意します。
マウスクリックではこのイメージ領域に描画を行います。
paintメソッドでそのイメージ領域を描画します。

リサイズされるとpaintメソッドが実行されイメージ領域から再描画されます。
package graphicsSample;

import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class GraphicSample04 extends Frame{

private static final long serialVersionUID = 1L;

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

//バッファ用イメージ
Image Img = null;

public GraphicSample04(){
this.setTitle("GraphicSample04");
this.setSize(300,300);
this.addMouseListener(new MyMouseAdapter());  
this.setVisible(true);
}

public void paint(Graphics g) {
//バッファ用イメージとグラフィックを作成します。
//コンストラクタではcreateImageインスタンスを作成できないのでココで初期化する。
if (Img == null){
Img = this.createImage(this.getWidth(),this.getHeight());
}
//イメージを描画します。
g.drawImage(Img,0,0,this);
}

private class MyMouseAdapter extends MouseAdapter{
public void mouseClicked(MouseEvent arg0) {
//バッファ用イメージに描画
Img.getGraphics().setColor(Color.darkGray);
Img.getGraphics().drawOval(arg0.getX(), arg0.getY(), 50, 50);
//paintを呼び出します。
repaint();
}
}
}



これで画面をリサイズしても描画は消えません。

しかし、画面を大きくしても描画領域は大きくならないため、大きくなった部分をマウスクリックしても円が描画されません。

画面のサイズに合わせて描画領域を変更する


componentResizedイベントで画面サイズに合わせて描画領域を変更します。
package graphicsSample;

import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;


public class GraphicSample05 extends Frame{

private static final long serialVersionUID = 1L;

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

//バッファ用イメージ
Image backImg = null;
//バッファ用グラフィック
//Graphics backGraphic =null;

public GraphicSample05(){
this.setTitle("GraphicSample05");
this.setSize(300,300);
this.addMouseListener(new MyMouseAdapter());
this.addComponentListener(new MyComponentListener());
this.setVisible(true);
}

public void paint(Graphics g) {
//バッファ用イメージとグラフィックを作成します。
//コンストラクタではcreateImage、getGraphicsインスタンスを作成できないのでココで初期化する。
if (backImg == null){
backImg = this.createImage(this.getWidth(),this.getHeight());
//backGraphic = backImg.getGraphics();
}
//ブッファイメージを描画します。
g.drawImage(backImg,0,0,this);
}

private class MyMouseAdapter extends MouseAdapter{
public void mouseClicked(MouseEvent arg0) {
//ブッファ用イメージに描画
//backGraphic.setColor(Color.darkGray);
//backGraphic.drawOval(arg0.getX(), arg0.getY(), 50, 50);
backImg.getGraphics().setColor(Color.darkGray);
backImg.getGraphics().drawOval(arg0.getX(), arg0.getY(), 50, 50);
//paintを呼び出します。
repaint();
}
}

private class MyComponentListener extends ComponentAdapter{
public void componentResized(ComponentEvent arg0) {
//リサイズ後の現在サイズを取得します
Rectangle rec = getBounds(); 
//イメージのサイズより現在のサイズが大きい場合
if ((backImg.getWidth(null) <= rec.width ) | (backImg.getHeight(null) <= rec.height)){
//新たなイメージを作ります。
Image newImg = createImage(rec.width, rec.height);
//新たなイメージに古いイメージを描画します。
newImg.getGraphics().drawImage(backImg, 0, 0, null);
//新たなイメージをインスタンス変数に保存します。
backImg = newImg;
}
}
}
}

2009年6月5日金曜日

Java クラス名を変更するには

名前を変えたいクラスを選択し
eclipseの「りファクタリング」メニューの「名前の変更」を選択します。


やっとクラス名を変える方法がわかった・・・

javaよりeclipseの使い方を習得する方がしんどいよ~。・゚・(ノД`)・゚・。

Java AWT 実行ファイルに埋めこれたリソースファイルから画像を表示する

画像やテキストファイルを実行ファイルに埋め込むにはで埋め込んだ画像ファイルを表示します。


ClassクラスのgetResouceメソッドを使用しリソースファイルのURLインスタンスを取得します。
ComponentクラスのcreateImageメソッドを使用し、URLインスタンスからImageインスタンスを作成します。

そしてFrameクラスのpaintメソッドで作成したImageインスタンスを描画します。

package graphicsSample;

import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ImageProducer;
import java.net.URL;

public class GraphicSample02 extends Frame{

private static final long serialVersionUID = 1L;

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

Image img = null;

public GraphicSample02(){
this.setTitle("GraphicSample02");
this.setSize(500,500);

//リソースよりイメージ画像を取得します。
URL url = this.getClass().getResource("Sample1.jpg");
try{
img = this.createImage((ImageProducer)url.getContent());
}catch(Exception ex){}


this.setVisible(true);
}

public void paint(Graphics g) {
//イメージ画像を描画します。
g.drawImage(img,50,50,this);
}

}

Java 画像やテキストファイルを実行ファイルに埋め込むには

画像やテキストファイル(リソースファイル)を実行ファイルに埋め込むには
パッケージエクスプローラでパッケージを選択し、「ファイル」メニューの「インポート」を選択します。
起動した画面で「一般」ノードの「ファイルシステム」を選択して次へをクリックします。



参照ボタンをクリックし、画像ファイルのあるフォルダを選択します。
フォルダ内のファイルの一覧が表示されるので、埋め込むファイルを選択します。



パッケージエクスプローラでファイルが追加されていることを確認します。

雑記 ツレがリストラにあいまして

うちのツレ(夫)が3月末で会社をリストラされました。
ツレは39歳。IT系で組み込み一筋です。
高スキルも高学歴もありませんw

この大不況でIT業界でも組み込み系は特に厳しいようです。
転職活動も厳しく社員数15名の会社で1名の採用枠に対し応募者は50名を超えるそうです。
履歴書を送り求人に応募するも、予想外の応募者に処理しきれず書類選考に1か月かかった会社もありました。
転職サイトに公開されたらすぐに応募しないと、後半は書類すら見てもらえない可能性もあります。

ツレの転職活動は3か月間。7月から就職先が決まりました。
転職サイトから応募した会社は20社。
うち2社の面接をし、そのうち1社に採用していただきました。
あとはいつもお世話になっている知り合いの社長からの紹介で2社の面接をしました。
採用して頂いた会社からはスキルや経歴より、何かビビビと感じるものがあったから採用したと言われたそうです(*´∀`*)アッタカーイ

本当の所は20社程度の応募で決まるとは思わなかったです。
100社ぐらい応募しないとダメなんじゃないかと。
実際ツレにも100社まであきらめずに応募しろと言ってましたし。

しかし、今回リストラされて本当にラッキーでした。
不況で厳しい組み込み業界の中、3次受け、4次受けで偽装請負や多重派遣だけで成り立っているような会社は、採用を控えているでしょう。
今求人を出している会社は不況でフィルタされ優良企業である可能性が高いです。
ツレも給料こそ下がったものの、久しぶりに底辺から抜け出せたようです。

その上、ツレも私も今回のリストラは自分自身を見直す良い機会になりました。
最近モチベーションが下がり気味だった私も、新たな目標を設定しモチベーションが復活しましたし、
ツレも色々反省しなければいけない点に気づいてくれたようです。

ここまでは新しい就職先が決まったから言えるキレイ言ですが。
実際の転職活動はやはり精神的にしんどかったです。




今回はそんなツレが吐いた名言集をご紹介。



俺の人格を全否定する気か!!


( ̄д ̄) つまんない。想定の範囲内。













本を読むのは嫌いなんだよ!!



Σ(´∀`;) おまえは小学生か!!











おまえは俺を鬱にさせる気か!!



.∵・(゚ε゚ )ブッ!!
「親父にもブタレタ事ないのにぃ!」と被って面白かった。
プロポーズの言葉はわすれたけれど、これは一生覚えてると思うwww







ツレより優秀な人たちはたくさんいると思います。
転職活動は「あせらず、あわてず、あきらめず!」

2009年6月4日木曜日

.NET(Mobile) SIPパネルを切り替えるには

Touch Diamond (X04HT)のSIPはデフォルトで以下の5種類があります。
・10キー
・ひらがな/カタカナ
・ローマ字/かな
・手書き入力
・手書き検索

このSIPパネルを切り替えます。
方法は2つあります。

Microsoft.WindowsCE.Forms.InputMethodクラスを使用する方法です。
フォームにInputPanelを配置し、以下のコードを実行する。
Public Class Form1

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim im As Microsoft.WindowsCE.Forms.InputMethod
For Each im In Me.InputPanel1.InputMethods
Me.ListBox1.Items.Add(im.Name)
Next im

End Sub

Private Sub ListBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) Handles ListBox1.SelectedIndexChanged
Dim strIM As String
strIM = ListBox1.SelectedItem.ToString()

Dim im As Microsoft.WindowsCE.Forms.InputMethod
For Each im In Me.InputPanel1.InputMethods
If im.Name = strIM Then
InputPanel1.CurrentInputMethod = im
End If
Next im
End Sub

End Class


こちらはAPI「SipSetCurrentIM」を使用します。
フォームにInputPanelを配置する必要はありません。
Imports System.Runtime.InteropServices

Public Class Form1

Private _InputMethod As New Dictionary(Of String, Guid)

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
For Each im As Microsoft.WindowsCE.Forms.InputMethod In Me.InputPanel1.InputMethods
_InputMethod.Add(im.Name, im.Clsid)
Me.ListBox1.Items.Add(im.Name)
Next im
End Sub

Private Sub ListBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) Handles ListBox1.SelectedIndexChanged
Dim strIM As String = ListBox1.SelectedItem.ToString()
Dim guid As Guid = Me._InputMethod(strIM)

SipSetCurrentIM(guid.ToByteArray)
End Sub

 _
Private Shared Function SipSetCurrentIM(ByVal clsid As Byte()) As Boolean
End Function

End Class

.NET(Mobile) Touch Diamond (X04HT)のデフォルト10キーSIPの入力モードを切り替える

Touch Diamond (X04HT)のデフォルト10キーSIPの入力モードを切り替えるには
レジストリ「HKEY_CURRENT_USER\Software\Keytouch\Multiplay」の値を操作します。

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
SetKey10InputMode(CType(Me.ComboBox1.SelectedIndex, Key10ModeType))
End Sub

Public Enum Key10ModeType
NumHalf = 0
NumFull = 1
AlphaHalf = 2
AlphaFull = 3
Hiragana = 4
KatakanaHalf = 5
KatakanaFull = 6
End Enum

Private Sub SetKey10InputMode(ByVal mode As Key10ModeType)
Dim sReg As String = "HKEY_CURRENT_USER\Software\Keytouch\Multiplay"

Select Case mode
Case Key10ModeType.NumHalf
Microsoft.Win32.Registry.SetValue(sReg, "ShiftModeEx", 9)
Microsoft.Win32.Registry.SetValue(sReg, "ShiftMode", 8)
Microsoft.Win32.Registry.SetValue(sReg, "ActiveIME", 1)
Microsoft.Win32.Registry.SetValue(sReg, "NumericMode", 0)
Microsoft.Win32.Registry.SetValue(sReg, "PasswordMode", 0)

Case Key10ModeType.NumFull
Microsoft.Win32.Registry.SetValue(sReg, "ShiftModeEx", 8)
Microsoft.Win32.Registry.SetValue(sReg, "ShiftMode", 7)
Microsoft.Win32.Registry.SetValue(sReg, "ActiveIME", 1)
Microsoft.Win32.Registry.SetValue(sReg, "NumericMode", 0)
Microsoft.Win32.Registry.SetValue(sReg, "PasswordMode", 0)

Case Key10ModeType.AlphaHalf
Microsoft.Win32.Registry.SetValue(sReg, "ShiftModeEx", 7)
Microsoft.Win32.Registry.SetValue(sReg, "ShiftMode", 6)
Microsoft.Win32.Registry.SetValue(sReg, "ActiveIME", 1)
Microsoft.Win32.Registry.SetValue(sReg, "NumericMode", 0)
Microsoft.Win32.Registry.SetValue(sReg, "PasswordMode", 0)


Case Key10ModeType.AlphaFull
Microsoft.Win32.Registry.SetValue(sReg, "ShiftModeEx", 6)
Microsoft.Win32.Registry.SetValue(sReg, "ShiftMode", 5)
Microsoft.Win32.Registry.SetValue(sReg, "ActiveIME", 1)
Microsoft.Win32.Registry.SetValue(sReg, "NumericMode", 0)
Microsoft.Win32.Registry.SetValue(sReg, "PasswordMode", 0)

Case Key10ModeType.Hiragana
Microsoft.Win32.Registry.SetValue(sReg, "ShiftModeEx", 0)
Microsoft.Win32.Registry.SetValue(sReg, "ShiftMode", 0)
Microsoft.Win32.Registry.SetValue(sReg, "ActiveIME", 202)
Microsoft.Win32.Registry.SetValue(sReg, "NumericMode", 0)
Microsoft.Win32.Registry.SetValue(sReg, "PasswordMode", 0)

Case Key10ModeType.KatakanaHalf
Microsoft.Win32.Registry.SetValue(sReg, "ShiftModeEx", 3)
Microsoft.Win32.Registry.SetValue(sReg, "ShiftMode", 2)
Microsoft.Win32.Registry.SetValue(sReg, "ActiveIME", 202)
Microsoft.Win32.Registry.SetValue(sReg, "NumericMode", 0)
Microsoft.Win32.Registry.SetValue(sReg, "PasswordMode", 0)

Case Key10ModeType.KatakanaFull
Microsoft.Win32.Registry.SetValue(sReg, "ShiftModeEx", 2)
Microsoft.Win32.Registry.SetValue(sReg, "ShiftMode", 1)
Microsoft.Win32.Registry.SetValue(sReg, "ActiveIME", 202)
Microsoft.Win32.Registry.SetValue(sReg, "NumericMode", 0)
Microsoft.Win32.Registry.SetValue(sReg, "PasswordMode", 0)

End Select
End Sub



ちなみに

W-ZERO3[es]本体表面の10キーを制御するのは
レジストリ「HKEY_CURRENT_USER\Software\Sharp\PhoneStatus」を操作します。

DT5200は本体表面の10キーを制御するのは
カシオのAPI「Calib.SystemLibNet.Api.SysSetInputMode」を使用します。
CASIOシステムライブラリマニュアル

モバイルのレジストリはVisualStudioの付属ツール「リモートレジストリエディタ」で見ることができます。

.NET(Mobile) コントロールのIMEモードを設定する

WindowsアプリであればテキストボックスのImeModeプロパティがありますが
CompactFrameworkのテキストボックスにはImeModeプロパティがありません。

CompactFrameworkのテキストボックスのImeModeを設定するにはAPIを使用します。
Imports System.Runtime.InteropServices

Public Class Form1

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
Call SetImeMode(Me.TextBox1, ImeMode.HIRAGANA)
End Sub

Public Enum ImeMode
NOCONTROL = 0
OFF = 1
[ON] = 2
DISABLE = 3
HIRAGANA = 4
KATAKANA = 5
KATAKANAHALF = 6
ALPHAFULL = 7
ALPHA = 8
End Enum

Private Const ALPHANUMERIC As Int32 = &H0   '半角英数
Private Const NATIVE As Int32 = &H1         '直接入力
Private Const KATAKANA As Int32 = &H2       'カタカナ
Private Const FULLSHAPE As Int32 = &H8      '全角
Private Const ROMAN As Int32 = &H10

 _
Private Shared Function ImmGetContext(ByVal hWnd As IntPtr) As IntPtr
End Function

 _
Private Shared Function ImmReleaseContext(ByVal hWnd As IntPtr) As Boolean
End Function

 _
Private Shared Function ImmSetConversionStatus(ByVal hIMC As IntPtr, ByVal fdwConversion As Int32, ByVal fdwSentence As Int32) As Boolean
End Function

 _
Private Shared Function ImmSetOpenStatus(ByVal hIMC As IntPtr, ByVal fOpen As Int32) As Boolean
End Function

 _
Private Shared Function ImmAssociateContext(ByVal hWnd As IntPtr, ByVal hIMC As Int32) As Int32
End Function


Private Sub SetImeMode(ByVal ctrl As Control, ByVal mode As ImeMode)
Dim himc As IntPtr = ImmGetContext(ctrl.Handle)

Try
Select Case mode
Case ImeMode.DISABLE
ImmAssociateContext(himc, 0)

Case ImeMode.OFF
ImmAssociateContext(himc, 1)
ImmSetOpenStatus(himc, 0)

Case ImeMode.ON
ImmAssociateContext(himc, 1)
ImmSetOpenStatus(himc, 1)

Case Else

ImmAssociateContext(himc, 1)
ImmSetOpenStatus(himc, 1)

Dim dwConversion As Int32

Select Case mode
Case ImeMode.HIRAGANA
dwConversion = NATIVE Or FULLSHAPE Or ROMAN
Case ImeMode.KATAKANA
dwConversion = NATIVE Or FULLSHAPE Or KATAKANA Or ROMAN
Case ImeMode.KATAKANAHALF
dwConversion = NATIVE Or KATAKANA Or ROMAN
Case ImeMode.ALPHAFULL
dwConversion = FULLSHAPE Or ALPHANUMERIC
Case ImeMode.ALPHA
dwConversion = ALPHANUMERIC
End Select
ImmSetConversionStatus(himc, dwConversion, 0)



End Select
Finally
ImmReleaseContext(ctrl.Handle)
End Try

End Sub


End Class

.NET(Mobile) アプリのメモリ使用量について

CompactFrameworkアプリでフォームを開いたり閉じたりしていると、メモリ使用量がどんどん増えていきます。

Microsofrフィードバックによると
Inherits Componentしているコントロール(Timer、ToolTipなど)を使用する際に.Netが自動生成するコードが
CompactFrameworkでは自動生成されないためフォームの参照が解放されず、ガーベッジに収集されないらしいのです。

具体的にはCompactFrameworkのMainMenuコントロールはInherits Componentされているにもかかわらず、Desiner.vbでcomponentsに追加されずfinalizaで解放されないということです。
このコードの★部分が本来ならmainMenu1 = New System.Windows.Forms.Mainmenu(components)となる。
 _
Partial Public Class Form1
Inherits System.Windows.Forms.Form

'フォームがコンポーネントの一覧をクリーンアップするために dispose をオーバーライドします。
 _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
MyBase.Dispose(disposing)
End Sub

'Windows フォーム デザイナで必要です。
Private components As System.ComponentModel.IContainer
Private mainMenu1 As System.Windows.Forms.MainMenu

'メモ: 以下のプロシージャは Windows フォーム デザイナで必要です。
'Windows フォーム デザイナを使用して変更できます。  
'コード エディタを使って変更しないでください。
 _
Private Sub InitializeComponent()
components = New System.ComponentModel.Container
'★本来ならmainMenu1 = New System.Windows.Forms.Mainmenu(components)
mainMenu1 = New System.Windows.Forms.Mainmenu()
Me.Menu = mainMenu1
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi
Me.Text = "Form1"
Me.AutoScroll = True
End Sub
End Class



しかし、それでもメモリは増え続けていきます・・・・


ダイアログフォームを起動し、ダイアログフォームを閉じる処理を1000回行い100回ごとにメモリ使用量を計測する処理を
以下の7種類のコードで試してみました。

コード1
Form2を起動し、Form2のActivatedでForm2を閉じます。
Form2にはmainMenuコントロールを1つ配置しています。
Using句を使用します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Using frm As New Form2
frm.ShowDialog()
End Using
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next


コード2
Form2を起動し、Form2のActivatedでForm2を閉じます。
Form2にはmainMenuコントロールを1つ配置しています。
Using句を使用します。
GC.Collectを1回実行します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Using frm As New Form2
frm.ShowDialog()
End Using
GC.Collect()
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next


コード3
Form3を起動し、Form3のActivatedでForm3を閉じます。
Form3にはmainMenuコントロールを1つ配置しています。
Form3のmainMenuコントロールはmainMenu1 = New System.Windows.Forms.Mainmenu(components)とします。
Using句を使用します。
GC.Collectを1回実行します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Using frm As New Form3
frm.ShowDialog()
End Using
GC.Collect()
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next


コード4
Form2を起動し、Form2のActivatedでForm2を閉じます。
Form2にはmainMenuコントロールを1つ配置しています。
Try~finally句を使用します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Dim frm As New Form2
Try
frm.ShowDialog()
Finally
frm.Dispose()
End Try
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next


コード5
Form2を起動し、Form2のActivatedでForm2を閉じます。
Form2にはmainMenuコントロールを1つ配置しています。
Try~finally句を使用します。
GC.Collectを1回実行します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Dim frm As New Form2
Try
frm.ShowDialog()
Finally
frm.Dispose()
End Try
GC.Collect()
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next


コード6
Form2を起動し、Form2のActivatedでForm2を閉じます。
Form2にはmainMenuコントロールを1つ配置しています。
Try~finally句を使用します。
Form2にNothingを設定します。
GC.Collectを1回実行します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Dim frm As New Form2
Try
frm.ShowDialog()
Finally
frm.Dispose()
frm = Nothing
End Try
GC.Collect()
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next


コード7
Form3を起動し、Form3のActivatedでForm3を閉じます。
Form3にはmainMenuコントロールを1つ配置しています。
Form3のmainMenuコントロールはmainMenu1 = New System.Windows.Forms.Mainmenu(components)とします。
Try~finally句を使用します。
GC.Collectを1回実行します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Dim frm As New Form3
Try
frm.ShowDialog()
Finally
frm.Dispose()
End Try
GC.Collect()
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next




コード1、コード4はメモリ使用量はほぼ同じですが、他のコードと比べGC.Collectを実行していないので、最もメモリ使用量が高いです。
コード6以外のその他のコードはメモリ使用量はほぼ同じです。
圧倒的にメモリ使用量が少なく、メモリ増加量も少ないのがコード6でした。

う~ん・・・?ナゼ?