VisualStudio テキストエディタのカスタマイズ

テキストエディタの色を変えてみた。

オプション>環境>フォントおよび
テキスト形式 
前景色	188,188,188
背景色	51,51,51

選択されたアクティブでないテキスト
背景色	0,0,0

インジケーターマージン
背景色	51,51,51

行番号
前景色	125,125,125
背景色	51,51,51

VB XMLドキュメントタグ
前景色	64,128,128

VB XML属性
前景色	255,189,66


VB XMLコメント
背景色	255,189,66


VB XMLテキスト
背景色	255,189,66

VBユーザータイプ
前景色	238,238,238

XML キーワード
前景色	157,194,255

XMLテキスト
前景色	188,188,188

XML処理命令
前景色	188,188,188

XML区切り文字
前景色	188,188,188

XML名
前景色	157,194,255

XML属性
前景色	238,238,238

XML属性の引用符
前景色	153,227,149

XML属性値
前景色	153,227,149

XSLTキーワード
前景色	157,194,255

その他のエラー
前景色	266,121,124

キーワード
前景色	157,194,255

コメント
前景色	255,189,66

コンパイルエラー
前景色	266,121,124

コードスニペットフィールド
背景色	111,132,255

数字
前景色	147,255,0

文字列
前景色	147,255,0

警告
前景色	255,255,0

クリップボードの履歴が見れるアプリ

さっき書いた記事の内容を元に、クリップボードの履歴を監視するアプリを作ってます。こんなアプリを想定してます。

  • クリップボードの履歴をn件まで確認できる
  • 過去にクリップした内容を再びクリップできる
  • 文字をコピーしたら文字を表示
  • ファイルをコピーしたらファイルをアイコン付きで表示
  • イメージをコピーしたらイメージを表示

もうだいたい出来てるんだけど、デザインが気にくわなくてなかなか完成しません・・・。用途を考えるとウィンドウのサイズが大き過ぎない方がいいけど、クリップボードの履歴をテキストとか画像を付けて具体的に表示するんだったら結構スペース取っちゃうんですよね。うーん。

クリップボードの監視

個人的なメモ。WindowsAPIを利用してクリップボードが更新されると通知される仕組み。元の記事のほぼパクリ

元の記事との違いは拾ってこれるクリップボードの内容を単なるテキストから、IDataObjectに対応させた。これによって様々な形式のクリップボードを拾ってこれる

まずイベント引数のクラス

Public Class ClipboardEventArgs
    Inherits EventArgs
    Private _clipData As IDataObject

    Public ReadOnly Property ClipData() As IDataObject
        Get
            Return Me._clipData
        End Get
    End Property

    Public Sub New(ByVal clipData As IDataObject)
        Me._clipData = clipData
    End Sub
End Class

クリップボードを監視するためのクラス

Imports System.Runtime.InteropServices

Public Delegate Sub ClipboardEventHandler(ByVal sender As Object, _
     ByVal ev As ClipboardEventArgs)

<System.Security.Permissions.PermissionSet( _
    System.Security.Permissions.SecurityAction.Demand, _
    Name:="FullTrust")> _
Friend Class MyClipboardViewer
    Inherits NativeWindow

    <DllImport("user32")> _
    Public Shared Function SetClipboardViewer( _
        ByVal hWndNewViewer As IntPtr) As IntPtr
    End Function

    <DllImport("user32")> _
    Public Shared Function ChangeClipboardChain( _
        ByVal hWndRemove As IntPtr, _
        ByVal hWndNewNext As IntPtr) As Boolean
    End Function

    <DllImport("user32")> _
    Public Shared Function SendMessage( _
        ByVal hWnd As IntPtr, ByVal Msg As Integer, _
        ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
    End Function

    Private Const WM_DRAWCLIPBOARD As Integer = &H308
    Private Const WM_CHANGECBCHAIN As Integer = &H30D
    Private nextHandle As IntPtr


    Public Event ClipboardHandler As ClipboardEventHandler

    Public Sub New(ByVal parent As Form)
        AddHandler parent.HandleCreated, AddressOf Me.OnHandleCreated
        AddHandler parent.HandleDestroyed, AddressOf Me.OnHandleDestroyed

    End Sub

    Friend Sub OnHandleCreated(ByVal sender As Object, ByVal e As EventArgs)
        AssignHandle(DirectCast(sender, Form).Handle)
        ' ビューアを登録
        nextHandle = SetClipboardViewer(Me.Handle)
    End Sub

    Friend Sub OnHandleDestroyed(ByVal sender As Object, ByVal e As EventArgs)
        ' ビューアを解除
        Dim sts As Boolean = ChangeClipboardChain(Me.Handle, nextHandle)
        ReleaseHandle()
    End Sub

    Protected Overloads Overrides Sub WndProc(ByRef msg As Message)
        Select Case msg.Msg

            Case WM_DRAWCLIPBOARD
                RaiseEvent ClipboardHandler(Me, New ClipboardEventArgs(Clipboard.GetDataObject()))

                If CInt(nextHandle) <> 0 Then
                    SendMessage(nextHandle, msg.Msg, msg.WParam, msg.LParam)
                End If
                Exit Select

                ' クリップボード・ビューア・チェーンが更新された
            Case WM_CHANGECBCHAIN
                If msg.WParam = nextHandle Then
                    nextHandle = msg.LParam
                ElseIf CInt(nextHandle) <> 0 Then
                    SendMessage(nextHandle, msg.Msg, msg.WParam, msg.LParam)
                End If
                Exit Select

        End Select
        MyBase.WndProc(msg)
    End Sub
End Class

ファイルのバックアップ

自分で使うようにファイルのバックアップをとるプログラム書いてみた。あまりテストしてないので消すかも

Imports System.IO

''' <summary>
''' ファイルを簡単にバックアップ、リストアするためのクラス
''' ファイル、ディレクトリともに利用可能
'''
''' バックアップされたファイルは以下の形式で名前が付けられる
''' [元のファイル名と拡張子].backup[yyyyMMdd]_[HHmm]_[ID3桁]
''' 例えば「sample.txt」というファイルをバックアップした場合
''' 「sample.txt.backup20130702_2359_001」というファイル名になる。
''' ディレクトリの場合も同様。
''' </summary>
''' <remarks></remarks>
Public Class Backupper

    Sub New()
    End Sub

    Private ReadOnly BackupFileExpression As String = "^.backup20[0-9]{2}[01][0-9][0-3][0-9]_[0-2][0-9][0-5][0-9]_[0-9]{3}"

#Region "Public"

    ''' <summary>
    ''' 現在のディレクトリにバックアップファイルを作成
    ''' </summary>
    ''' <param name="path"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Backup(ByVal path As String) As String
        If path Is Nothing Then Throw New ArgumentNullException()
        Return Backup(path, IO.Path.GetDirectoryName(path))

    End Function

    ''' <summary>
    ''' 指定したディレクトリにバックアップファイルを作成
    ''' </summary>
    ''' <param name="path"></param>
    ''' <param name="destDir"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Backup(ByVal path As String, ByVal destDir As String) As String
        If path Is Nothing Then Throw New ArgumentNullException("path")

        Dim manager As FileOrDirManager
        Try
            manager = FileOrDirManager.Create(path)
        Catch ex As ArgumentException
            Throw ex
            Return Nothing
        End Try

        If destDir Is Nothing OrElse Not IO.Directory.Exists(destDir) Then
            Throw New ArgumentNullException("destDir")
        End If

        Dim target As String = GenerateFileName(manager, path, destDir)
        If manager.Copy(path, target) Then
            Return target
        Else
            Return Nothing
        End If
    End Function

    ''' <summary>
    ''' バックアップファイルから復元
    ''' </summary>
    ''' <param name="path"></param>
    ''' <remarks></remarks>
    Public Sub Restore(ByVal path As String)
        If path Is Nothing Then Throw New ArgumentNullException("path = Nothing")

        Dim manager As FileOrDirManager = FileOrDirManager.Create(path)

        Dim parentDirPath As String = IO.Path.GetDirectoryName(path)
        Dim nameWithoutExtension As String = IO.Path.GetFileNameWithoutExtension(path)
        Dim extension As String = IO.Path.GetExtension(path)

        If Not System.Text.RegularExpressions.Regex.IsMatch(extension, BackupFileExpression) Then
            MsgBox("指定されたパスはバックアップファイルではありません。")
            Return
        End If

        Dim targetPath As String = IO.Path.Combine(parentDirPath, nameWithoutExtension)

        '出力したい場所に既存のファイルがあるか
        If manager.IsExist(targetPath) Then
            '有るならそのファイルをバックアップファイルにする
            Dim backupFile As String = GenerateFileName(manager, targetPath, IO.Path.GetDirectoryName(targetPath))
            If String.IsNullOrEmpty(backupFile) Then Throw New InvalidOperationException
            manager.Move(targetPath, backupFile)
            MsgBox("ディレクトリ '" & targetPath & "'は既に存在するため、バックアップファイル '" & backupFile & "'として移動しました")
        End If

        manager.Copy(path, targetPath)

    End Sub


#End Region

#Region "Private"

    ''' <summary>
    ''' ファイル名を決定
    ''' </summary>
    ''' <param name="manager"></param>
    ''' <param name="path"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function GenerateFileName(ByVal manager As FileOrDirManager, ByVal path As String, ByVal destDir As String) As String

        '純粋なファイ名を取得  例「c:\temp\sample.txt」なら「sample.txt」
        Dim fileName = IO.Path.GetFileName(path)

        Dim resultPath As String
        Dim id As Integer = 0
        Do
            id += 1
            resultPath = IO.Path.Combine(destDir, GenerateNextFileName(fileName, id))
        Loop While manager.IsExist(resultPath)

        Return resultPath
    End Function

    ''' <summary>
    ''' fileNameを元に次のファイル名を生成
    ''' </summary>
    ''' <param name="fileName">純粋なファイ名  例「c:\temp\sample.txt」なら「sample.txt」</param>
    ''' <param name="id">ファイル名につける通し番号</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function GenerateNextFileName(ByVal fileName As String, ByVal id As Integer) As String

        Dim nameWithoutExtension As String = IO.Path.GetFileNameWithoutExtension(fileName)
        Dim extension As String = IO.Path.GetExtension(fileName)

        Dim prefix As String
        If System.Text.RegularExpressions.Regex.IsMatch(fileName, BackupFileExpression) Then
            'バックアップファイルが存在するとき
            prefix = nameWithoutExtension
        Else
            prefix = fileName
        End If
        Return prefix & ".backup" & DateTime.Now.ToString("yyyyMMdd_HHmm_") & id.ToString("D3")
    End Function
#End Region

End Class

もう一個クラス必要

''' <summary>
''' ファイルとディレクトリを同様に扱うためのクラス
''' </summary>
''' <remarks></remarks>
Public MustInherit Class FileOrDirManager
#Region "コンストラクタ"
    Private Sub New()
    End Sub

#End Region

#Region "共有メソッド"
    Public Shared Function Create(ByVal path As String) As FileOrDirManager

        If IO.File.Exists(path) Then
            Return New FileManager()
        ElseIf IO.Directory.Exists(path) Then
            Return New DirManager()
        Else
            Throw New ArgumentException("指定されたパスが見つかりません。path =" & path)
            Return Nothing
        End If
    End Function
#End Region

#Region "抽象メソッド"
    Public MustOverride Function CreateInfo(ByVal path As String) As IO.FileSystemInfo
    Public MustOverride Function IsExist(ByVal path As String) As Boolean
    Public MustOverride Function Copy(ByVal source As String, ByVal target As String) As Boolean
    Public MustOverride Function Move(ByVal source As String, ByVal target As String) As Boolean

#End Region


#Region "インナークラス"
    Private Class FileManager
        Inherits FileOrDirManager


        Public Overrides Function CreateInfo(ByVal path As String) As System.IO.FileSystemInfo
            Return New IO.FileInfo(path)
        End Function


        Public Overrides Function IsExist(ByVal path As String) As Boolean
            Return IO.File.Exists(path)
        End Function

        Public Overrides Function Copy(ByVal source As String, ByVal target As String) As Boolean
            My.Computer.FileSystem.CopyFile(source, target)
            Return True
        End Function

        Public Overrides Function Move(ByVal source As String, ByVal target As String) As Boolean
            IO.File.Move(source, target)
            Return True
        End Function

    End Class

    Private Class DirManager
        Inherits FileOrDirManager


        Public Overrides Function CreateInfo(ByVal path As String) As System.IO.FileSystemInfo
            Return New IO.DirectoryInfo(path)
        End Function

        Public Overrides Function IsExist(ByVal path As String) As Boolean
            Return IO.Directory.Exists(path)
        End Function

        Public Overrides Function Copy(ByVal source As String, ByVal target As String) As Boolean
            My.Computer.FileSystem.CopyDirectory(source, target)
            Return True
        End Function

        Public Overrides Function Move(ByVal source As String, ByVal target As String) As Boolean
            IO.Directory.Move(source, target)
            Return True
        End Function

    End Class
#End Region

End Class

日記にコード貼り付けたら、なんか見辛いね!
というわけで久しぶりの日記でした。

痛キックボード作った

スケートボード用の透明のデッキテープがあるらしく、それを使って痛キックボードを作ろうと思い立った。まずシールを作ってキックボードのデッキ部分に貼り、その上からデッキテープを貼る形だ。シールを貼る場合、デッキ全体に貼る「全面貼り」と一部分にだけ貼る「部分貼り」が考えられる。部分貼りのほうが簡単だが、今回は全面貼りに挑戦した。

準備

必要なものは次のとおり

  • 透明のデッキテープ
  • シール
  • キックボードを分解するための工具

スケートボードの透明のデッキテープは楽天市場で比較的安かった次の商品を購入(http://item.rakuten.co.jp/asobitai/10001694/)ただしこの商品はあまり透明ではなく、透けた時に黄色っぽくなってしまった。透明度の高いデッキテープを知ってる方は教えてください。

シールはインクジェットプリンタで印刷可能なシール用紙を使って作る。今回はデッキに全面張りするので、キックボードのサイズに合わせた場合、A4サイズ 2枚が必要。安かったのでamazonで下記の商品を購入した。

エレコム 手作りステッカー 強力粘着タイプ A4サイズ 3枚入り ホワイト EDT-STSW

エレコム 手作りステッカー 強力粘着タイプ A4サイズ 3枚入り ホワイト EDT-STSW

キックボードを分解したほうが作業をしやすいので分解するための工具も必要。キックボードの分解はなかなか骨の折れる作業なのでそこそこいい工具があったほうがいい。私のキックボード(JD Razor MS-286)を分解するには最低限スパナ、六角レンチ2本が必要。

デザインの作成

まずパソコンのグラフィックソフトでデザインを作成する。Windows標準のペイントソフトでもいいけど、レイヤー機能ついてないので大変。私は昔から愛用してるPixiaっていう無料ソフトを使った。

まず大きなデザインを作って、印刷する部分を決める。下記の画像の2つの黒枠で囲ってる部分が印刷する部分。あえて黒枠をかぶせ印刷後に重なっている部分をカットする。こんな面倒くさいことをしたのは、「用紙の縁際まで印刷するときにトラブルが起こりにくくするため」とどこかで読んだような気がするが、よく覚えてない…。多分黒枠部分を重ねなくても大丈夫だと思う。A4サイズで印刷しようと思った場合、画像の解像度は(1123*794)になるらしいので、黒枠の大きさもこれにあわせてある。
おおまかなキックボードの大きさも分かればそれも描いてやったほうが作業しやすい。

黒枠の部分をトリミングしたものがこんな感じに。

完成したら印刷する。

ちなみに私が購入したA4シール台紙にはUVカットフィルムなんてものが入っていた。貼るとシールを紫外線から守ってくれるため色褪せしにくくなる。これを使う場合は印刷後、シールをカットする前にシールの上から貼るといい。

キックボード本体の下準備

まずはキックボードをデッキ部分だけになるよう分解する。これがとても大変な作業だった。
リアタイヤ、ブレーキ、ハンドルバーとの接続部分の3箇所を外した。六角レンチの大きさが六角穴付きボルトに合ってるはずなのにうまくはまらず、無理やりハンマーで押し込んだ。ボルトを回すのも非常に硬かった。

デッキ部分だけに出来たら、次はデッキに最初から貼ってあるデッキテープを剥がす。端からはがしていくが、途中でデッキテープが破れるのでゆっくり。破れたらそのつど、マイナスドライバーのような平らなもので剥がす。デッキテープがすべて剥がれたら、デッキの上にベタベタした接着剤が残っているはず。水をかけてタワシでこすったがあまり効果なかった。その後、灯油をかけてみたら接着剤が上手く溶けてくれた。灯油をかけると接着剤がぶよぶよになったので、最後に台所用の中性洗剤で洗い落とした。スケートボードは木製だから荒いことができないけど、キックボードは金属製だから楽だね。

シールを貼っていく

シールを貼っていくのだが、シール台紙は高いので一度普通の紙に印刷して下記の手順で練習するといいと思う。まずは印刷した2枚のA4シールを絵柄を見てつなぎ合わせ、裏側でテープで止めておく。このとき絵柄が重なっている部分があると思うが、この部分を綺麗に切り落とし、再び裏側をテープで止める。

2枚をくっつけたら、このシールの上にデッキ部分を置いて、マジックで型を書く。次にマジックで引いた線にそってシールをカットしていく。このとき線よりも10mmほど内側をカットする。これは縁ギリギリまでシールを貼るとシールが剥がれやすくなるため。カッターよりもハサミで切るのがおすすめ。

切れたらシールをデッキに貼る。貼る前には大きさが合ってるかきちんと確認すること。貼り方については言及しない。私は気泡が入ったり、ずれたり、いろいろ失敗したので…。取り返しのつかない気泡は針で指して空気を抜くといいらしい。シールを貼った直後はこんな感じになった。気泡入ってるけど気にしない!


デッキテープ

シールと同様の手順でデッキテープをカットする。ただし下に貼ってあるシールを保護するため、シールの時よりも大きめにカットする。マジックで引いた線よりも5mmほど内側をカットすれば良いと思う。あとは貼る

キックボードを組み立て完成


反省点

書いた手順通りに作った訳じゃなくて、試行錯誤しながらだったので完成品は雑になった。写真を見ての通りデッキテープを貼ると黄色っぽい色になる。もしまたやる機会があれば、別のデッキテープを使う。

キックボードの正確な大きさをパソコンに取り込めればもっと作業しやすかっただろな。スキャナあればそういうことできるのかな?

キックボードのベアリングを交換してみた

ホームセンターでNachiの608ZZを買ってきて、JD Razor MS-286の標準ベアリングと交換してみた。

交換するベアリング

最初からついていた標準ベアリングはDJ(海外の企業)の608ZZでabec5。abec5っていうのは製品のクオリティみたいなものらしい。abec5っていうとそこそこ高品質な製品らしいのだが、海外製のベアリングよりも日本製のほうが優れているという話を聞いたのでどうしても交換したくなった。

今回選んだNachiは日本で第4位のベアリングメーカーらしい。本当はNSKとかNTNの製品がよかったんだけど、ホームセンターにこれしかなかったのでとりあえず購入。1つ365円で、これを4つ購入。ここに国内ベアリングメーカーの概要が書いてるので購入前に読んでみるといいかも。

ベアリングの交換方法

交換方法は、このサイトを参考にした。ただし六角レンチ1本ではまず無理だと思う。六角レンチを2本用意して、1本はウィールの反対側からネジが動かないよう固定する必要がある。また、このネジがとても固いため、2本のうち1本の六角レンチはソケット式を使ったほうが良い。ソケット式の六角レンチっていうのはこういう奴

交換してみた感想

手でウィールを回してみると、たしかに回転する時間が倍くらい違う。でも乗ってみた感じは今いち違いが分からなかった。やはりNachiじゃなくて、NSKとかNTNの製品にしておけばよかったなと後悔。キックボード購入3日目での交換なので、使い古したベアリングを交換する訳じゃないから効果が薄いのかも。まあベアリングの交換なんて元々そんなものなのかもしれない。