ユーザーフォーム SetFocus VBA エクセル 検索 (1)

お手伝いの仕事?を楽にするため,また,簡単なVBAを作りました。簡単にできるかと思ったのですが,意外
に難航。なかなか思った動作をしてくれません。意図した動作とは,


のようなユーザーフォームで,クリックをしなくても,テキストボックスに入力できるようにするというもの
です。入力できるようにするには,TextBox1.SetFocus という表現をするのですが,どう書き換えても入力
できるようになりませんでした。ネットでくぐってもこの SetFocus のトラブルは結構あるみたいで,いく
つも出てきますが,明確な解決法には,あたりませんでした。 

最初 Private Sub TextBox1_Change() というイベントに関係することを記載していましたが,だめでした。

そこで,

Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)

のイベント処理のところに書いたら,やっと思った動作ができました。
SetFocus の命令は,どこに書いても正しい動作をするのではない,ということが,おぼろげながら分かりま
した。

思った動作とは,

 ユーザフォームを自動で表示(クリックしなくても,テキストボックスに入力できる状態に)
 入力後所定の動作が終わったら,また,テキストボックスに入力できる状態に

ということで,次のようなコードで,思った動作ができました。

Dim keyWord As String
Dim myRange As Range
Dim myObj As Range

Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    Set myRange = Range("D5:D98")
    keyWord = TextBox1.Text
    If KeyCode = vbKeyReturn Then
    Set myObj = myRange.Find(keyWord, LookAt:=xlPart)
    Label1.Caption = "検索結果=「" & myObj.Offset(0, 0).Value & "」" & myObj.Row & "行目"
    myObj.Offset(0, -3).Interior.ColorIndex = 6
    UserForm1.TextBox1.Text = ""
    UserForm1.TextBox1.SetFocus
    End If
    If KeyCode = vbKeyF1 Then
    myObj.Offset(0, -3).Interior.ColorIndex = 0
    Set myObj = Nothing
    Label1.Caption = "検索結果="
    UserForm1.TextBox1.Text = ""
    UserForm1.TextBox1.SetFocus
    End If
   End Sub

Private Sub UserForm_Initialize()
    TextBox1.Text = ""
End Sub

Private Sub UserForm_Activate()
    UserForm1.TextBox1.SetFocus
End Sub

Private Sub TextBox1_Change()
    keyWord = TextBox1.Text
End Sub

 

やっていることは,単に,テキストボックに検索する文字を入力して,検索後,あれば,あった場所の左側の
背景の色を変えるということで,なんのことはありません。エンターキーを押すと,検索して,F1 を押すと
直前に変えた背景をもとに戻すという,単純な動作です。

ただ,今回のものは,検索の対象が,複数ある場合には,対応していません。複数検索に対応させるには,検
索自体はそれほど複雑ではないのですが,背景色を変える対象も複数になるので,それをもとにに戻すとなる
と,背景を変えた場所を何らかの形で記憶していないとだめで,プロシャージャが複雑になりますので,今回
はやめようかと思います。

エクセルVBA(シート選択のエラー処理)–(5)

ファイル名を取得するのに、文字列関数を操作して取り出しましたが、一発で取り出せる関数もあるようで
す。
FSO と呼ばれるものを使う方法で、詳細は、諸兄のHPに譲りたいと思いますが,

fPath は目的のファイルまでのファイル名を含んだフルパス)
  Dim FSO, PathName As String, FileName As String
  Set FSO = CreateObject(“Scripting.FileSystemObject”)

  FileName = FSO.GetFileName(fPath)・・・・・・ファイル名だけを取り出す。
  PathName = FSO.GetParentFolderName(fPath)・・・・・・パスだけ取り出す。

ただ自分自身(マクロを記載したBOOK)の場合は次のようにして求めるようです。

  ThisWorkbook.Name・・・・自分自身のファイル名
  ThisWorkBook.FullName・・・自分自身のフルパス

ちなみに、

   FileName = FSO.GetFileName(ThisWorkbook)・・・・エラー

のようにファイル名を求めようとするとエラーになります。VBA が良く分かっている方ならこんなことなさ
らないのでしょうがまだまだ勉強中の私にとって、ちょっと ? になります。ただ、下記のようにするとき
ちんとファイル名を求められます。でも、ThisWorkbook.Name でファイル名を求めることができるので、
意味ないですね。

   FileName = FSO.GetFileName(ThisWorkbook.FullName)・・・取得可

ただ、自分自身(マクロが書かれているファイル)のファイル名を求める場面は、それほど多くないかなと思います。

エクセルVBA(シート選択のエラー処理)–(4)

作ったプロシャージャを動かして、シートを選択している様子です。リストボックスのシート名をクリックすると、クリックしたシートに移動します。

どのシートが選ばれたかは、リストボックスの IndexID でわかります。Worksheets( IndexID).Name で、選択されたシート名を表示できます。それほど使う場面はないかとは思いますが、使う時は、便利な機能のよ
うな気がします。

エクセルVBA(シート選択のエラー処理)–(3)

以下は、VBA 標準モジュールに記載したプロシャージャです。
Sub ボタン2_Click() は、シートに貼り付けてある、マクロ起動用のものです。
Function sheets_set(Wb As Workbook) の中身は、本来ユーザーフォームの _Initialize()の項目に記入すべきでしょうが、Wb の引き渡し方法がわからないので、こちらに書きました。

---------------
Sub ボタン2_Click()
  Call Select_sheet
End Sub
---------------
Function Select_sheet()
  ‘====読み込みフルパスファイル名の取得====
  Dim fPath As Variant
  Dim fType, prompt As String

  fTyp = “Excelファイル(*.xlsm),*.xlsm,Excelファイル(*.xlsx),*.xlsx,Excelファイル(*.xls),*.xls”
  prompt = “Excelファイルを選択してください”
  fPath = Application.GetOpenFilename(fTyp, , prompt)

  If fPath = False Then
    MsgBox “ファイルが選択されていません。”
    Exit Function
  End If

  ‘====読み込みのファイル名取り出し====
  Dim STR As String
  Dim t_file_name As String

  STR = StrReverse(fPath)
  t_file_name = Right(fPath, InStr(STR, “\”) – 1)

  ‘====ファイルを開く処理====
  Dim Wb As Workbook

  If ThisWorkbook.FullName <> fPath Then
    If fPath <> “” Then

    For i = 1 To Workbooks.Count
      If Workbooks(i).Name = t_file_name Then
        BookFlag = True
      End If
    Next i

    If BookFlag <> True Then
      MsgBox “ファイルを開きます。”
      Set Wb = Workbooks.Open(fPath, UpdateLinks:=Ture, ReadOnly:=Ture)

      Call sheets_set(Wb)
      UserForm1.Show vbModeless
    Else
      MsgBox “すでに開いているファイルを開こうとしてます。”
      Exit Function
    End If
    End If
  Else
    MsgBox “自分自身を開こうとしてます。”
    Exit Function
  End If
End Function
-------------------------------------------
Function sheets_set(Wb As Workbook)
  Dim i As Integer

  With UserForm1.ListBox1
    ‘一つだけ選択
    .MultiSelect = fmMultiSelectSingle
  End With

  For i = 1 To Wb.Worksheets.Count
    UserForm1.ListBox1.AddItem (Wb.Worksheets(i).Name)
  Next

  UserForm1.ListBox1.ListIndex = 0
End Function


以下は、ユーザーフォームの方に記載したものです。

-------------------------
Private Sub CommandButton1_Click()
  ThisWorkbook.Activate
  Unload UserForm1
End Sub
-------------------------
Private Sub ListBox1_Click()
  sh_name = ListBox1.List(ListBox1.ListIndex)
  TextBox1.Text = sh_name
  Worksheets(sh_name).Activate
End Sub
----------------------------------------------
Private Sub ListBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  If KeyCode = vbKeyReturn Then
    KeyCode = 0
    ThisWorkbook.Activate
    Unload Me
  End If
End Sub
----------------------------------------------
Private Sub UserForm_Initialize()
  With ListBox1
  ‘一つだけ選択
  .MultiSelect = fmMultiSelectSingle
  End With
End Sub

エクセルVBA(シート選択のエラー処理)–(2)

エラー処理2・・・・自分自身を開こうとする。

  このエラー処理は、自分自身を開くとまずいので、ThisWorkbook.FullName と 開こうとするファイ
  ルのフルパスの fPath を比較することで、同じなら、「自分自身を開こうとしてます。」のメッセージ
  を出して、Function  を抜け出します。

  If ThisWorkbook.FullName <> fPath Then
    
    ・*開こうとするファイルとすでに開いているファイルを比較する。
    
  Else
    MsgBox “自分自身を開こうとしてます。”
    Exit Function
  End If

  次の処理のファイルを比較するに先立ち、開こうとするファイルのファイル名を取り出しておきます。い
  くつか方法をためしましたが、文字列を編集する方法がいいみたいで、フルパスを文字の後尾から ”¥” 
  を探してファイル名を取り出します。緑の”¥”を探しだせば、赤のフィル名を取り出せます。

    E:¥VBA開発¥シート選択Dummy.xlsx
                  ←←←←←

  はじめ、InStrRev を使ってみましたが、思った結果がでなかったので(後でわかりました)文字列を反転
  して、先頭から”¥”の探し出し、その文字のある手前まで切り出して、ファイル名を取得しました。なん
  と、InStrRev 関数は、後ろから文字を探すのですが、見つけた場所の位置を、後ろから数えた位置では
  なく、前から数えた位置を返すみたいでした。下記のようにして  t_file_name にファイル名を取り込
  みました。
  ‘====読み込みのファイル名取り出し====
   Dim STR As String
   Dim t_file_name As String

   STR = StrReverse(fPath)
   t_file_name = Right(fPath, InStr(STR, “\”) – 1)

エラー処理3・・・・既に開いているファイルを開こうとする。
  既に開いている Book数を Workbooks.Count で取得して、For ループの中で、開こうとしている
  ファイル名と比較し、同名のファイルがあれば、True を そうでなければ False をセットして判定し
  ます。開いているファイル名は、Workbooks(i).Name で取得できます。
  False の場合だけ(同じファイルがない),目的のファイルを開き、Call sheets_set(Wb) で、取得する
  シート名をユーザーフォームのリストボックスに、セットします。

  For i = 1 To Workbooks.Count
    If Workbooks(i).Name = t_file_name Then
      BookFlag = True
    End If
  Next i

  If BookFlag <> True Then
    MsgBox “ファイルを開きます。”
    Set Wb = Workbooks.Open(fPath, UpdateLinks:=Ture, ReadOnly:=Ture)

    Call sheets_set(Wb)
    UserForm1.Show vbModeless
  Else
    MsgBox “すでに開いているファイルを開こうとしてます。”
    Exit Function
  End If

エクセルVBA(シート選択のエラー処理)–(1)

お手伝いでしている仕事がらみの作業用に、何年かかけて、VBAのプロシャージャを作成しました。おかげ様で、短い時間でその処理ができるようになりました。

ただ、時々でるエラーを、その都度修正したりしながら、使ってきました。自分で作成したプロシャージャなので、なぜエラーが起こったのか、ちょっと流れを見ればわかるのですが、なるべく直さなくてもいいように、作り直したいなと思ってました。

やっていることは至極簡単なことですが、手作業でやると結構な時間とられるので、どうしても、プロシャージャが必要でした。継ぎ足し継ぎ足ししてきたので、結構な分量のプロシャージャになってしまってますので、全部作り直すことは、なかなかできないのですが、ある作業の一部分だけでも、考えられるエラーについての対処を十分にできるようにしたいなと、手直しをし始めました。

今回、作業の対象にしたので、他のエクセルブックを選択して開きそのブックのシートを選択する、という部分のプロシャージャです。今日、一日、かかって、ほぼ、できたので、備忘録がてら、記載します。

エラー処理1・・・・存在しないファイルを開こうとする。
  このエラーの回避は、GetOpenFilename を使って、それそれのディレクトリーを開いて、これから開こ
  うとするファイルを選択して開くということで、回避しました。ただこの画面で、キャンセルを押してし
  まうと、「ファイルが選択されてません。」のエラーとなりプロシャージャが中断してしまい、fPath に
   False がセットされますので、IF 文でFunction を抜け出すことで、回避しました。

  ‘====読み込みフルパスファイル名の取得====
   Dim fPath As Variant
   Dim fType, prompt As String

   fTyp = “Excelファイル(*.xlsm),*.xlsm,Excelファイル(*.xlsx),*.xlsx,Excelファイル(*.xls),*.xls”
   prompt = “Excelファイルを選択してください”
   fPath = Application.GetOpenFilename(fTyp, , prompt)

   If fPath = False Then
     MsgBox “ファイルが選択されていません。”
     Exit Function
   End If

 

Windows10アップデート失敗

いままでは、なかったのですが、昨日、Windowsのアップデートに失敗したようで、結局、Windowsの初期化を余儀なくされました。
 原因はよくわからないのですが、不安定なネット環境(iPhoneのテザリング接続)であれこれやっている状態で、アップデートのフィルが一部こわれた状態で保存されたのでは、と想像してます。
アップデートを先送りしてもよかったのですが、アップデートがサポート期間とも関係があるようなので、アップデートするべくもがきました。そのうち、何度も同じ状態を繰り返すPCの状態になり、Windowsが立ち上がらなくなりましたので、

ここを参考に

初期化をしました。
一時、苦労して作ったエクセルVBAスクリプトが心配で、一時真っ青になりかかりましたが、ファイル当は引き継いで初期化できるとのことで、一安心。また、慌てて、何か所かにバックアップをしました。
大事なファイルはぶじだったのですが、firefoxのブックマークがなくなったのがちょっとでした。別なPCのブックマークをエクスポート後、インポートして、完全ではないのですが、ほぼ使ってたものを再現できました。 「追記」 セットアップが終わると、削除.htmlみたいな名前のファイルが作成されてました。どうやら、既存のシステムから新しいシステムをインストールするにあたって、削除されたプログラムの一覧が記載されているようでした。気になっていたソフトがあったので、そのこ項目をクリックしたら、なんと、ウイルスが存在していたHPにアクセスしたようで、スクリーンがロックされてしまって、サポートまで、電話しろという画面が表示されてしまいました。

と同時に「あなたな個人情報のIPアドレスがなんちゃらかんちゃら」と音声の案内まででてきました。ちょっとあせりましたが、電源を切っても変化ないので、Ctrl+Alt+Dele を同時に押して、タスクマネージャを表示させると、Fire-Foxだけが動いてました。クリックしたリンク先にこのしょうもないものが設置されているようでしたので、Fire-Fox をクリックした後、タスクの終了をクリックして、終了させました。念のため、

Microsoft Defender

でフルスキャンをししまた。幸い、異常はありませんでした。このしょうもないものを表示させるプログラムも、自分のPCが動かしているので、自分のPCの方でプログラムを止めてしまえば、いいのですが、なかなかできませんよね。幸い、タスクマネージャーのことを知っていたので、この対応ができましたが・・・・。

これで、ウインドウ内の「ここをクリック」などと表示してあるところを、クリックしたりすると、さらに悪意のあるプログラムをインストールされることになるんでしょうね。クワバラ、クワバラ。

PHPヴァージョンアップ備忘録

旧の掲示板は,「画像掲示板plus」というPHPで書かれたものを使ってました。このプログラム(スクリプト)は,「LEMON-S PHP」というHPに掲載されていたものです。あまり需要がないのか,更新が途絶えているようで,サポート掲示板も,2016年の作者の書き込みを最後に,更新されてないようです。2016年は,PHP7になった頃でしょうか,サポートにもPHP7で「画像掲示板plus」を動かすにはどうすればいいか,ちょっとだけ記述がありました。
この旧掲示板は,私にとってもいろいろな情報が残ってるので,表示だけは残したかったので,PHPの初心者の私が,ネットサーフィンをたよりに,V5⇒V7にアップデートしても動くように,無謀な挑戦をしたところです。
「LEMON-S PH」には,まだ,PHPのスクリプトが残ってますので,2015年に更新されたv2.36をDLしました。このファイルは,このままだと文字化けを起こしますので,

    SHIFT-JIS⇒⇒UTF-8

のように変換して,保存しました。また,サーバー上に残ってる,「imglog.log」というCSV形式のデータもUTF-8で保存しなおしました。
一方,最低限必要なPHPとアパッチをどうするか迷いましたが,それぞれにインストールすると細かい設定が面倒そうで,デバック環境を作るだけでも時間がかかりそうなので,諸兄のHPを見ながら,「XAMPP」という,PHPプログラム作成の環境を一括インストールで作成できるものを導入しました。

導入後早速その環境で,該当するプログラムを動作させ,あれこれ始めました。また,公開しているHPのようにまっしろかなと思いましたが,

    Warning: Use of undefined constant

という警告が20以上でてきました。

意味がわからなかったのですが,ネットくぐってみると,該当の行の該当の項目に「’ ‘」の記述がないことが原因であることがわかりました。そこで,

    修正前・・・・・・define(LOGFILE, ‘imglog.log’);
    修正後・・・・・・define(‘LOGFILE’, ‘imglog.log‘);

のように変更しました。defineの括弧の後半(赤字部分)が数字の場合,シングルクーテーションがあるところとないところがあり,その違いが分かりませんでしたが,下記のように統一しました。

    修正後・・・・・・define(‘MAX_KB’, 500)

これで,「Warning」はほとんどなくなりました。PHP5では,このシングルクオーテーションがなくても,きちんと動いてた様で,PHP7では,そのチェックが一層厳しくなったそうで,この結果になってるようです。

まだ消えないエラー表示を見てみると

    Fatal error: Uncaught Error: Call to undefined function eregi()

というのがあり,これも調べてみると,PHP5で使われていた備え付けの関数がPHP7では,廃止になったとのことで,代替えの関数として,

    preg_match

が使えるとのことなので,

    修正前・・・・・・eregi($value,$ref)
    修正後・・・・・・preg_match(‘/$value/i’,$ref)

のように変更。このFatal error:があるとプログラムはそこで,止まってしまうようで,もう一カ所修正箇所がありました。

修正前・・・ereg_replace(“(https?|ftp|news)(://[[:alnum:]\+\$\;\?\.%,!#~*/:@&=_-]+)”,”<a href=\”\\1\\2\” target=\”_blank\”>\\1\\2</a>”,$proto);
修正後・・・preg_replace(“/(https?|ftp|news)(://[[:alnum:]\+\$\;\?\.%,!#~*/:@&=_-]+)/“,”<a href=\”\\1\\2\” target=\”_blank\”>\\1\\2</a>”,$proto);
再修正・・・preg_replace(“/(https?|ftp|news)(:\/\/[[:alnum:]\+\$\;\?\.%,!#~*\/:@&=_-]+)/”,”<a href=\”\\1\\2\” target=\”_blank\”>\\1\\2</a>”,$proto);

 

修正後,懐かしい画面の片割れがでてきましたので,ここでも少し「やった。」になりました。懐かしい画面と一緒にでてきたのは,書き込みの表題だけでした。

修正したものを見ると,再修正が必要で,最終的に,青で示したエスケープシーケンスを挿入すると,コメントまで表示できました。

PHP側で,正規表現のはじめ「/」と,終わのりを意味する「/」の他にあるスラッシュを区別する必要があり,区切りでないスラッシュは,「¥/」とする必要がありました。

表題・コメントが表示できたのはいいのですが,それと同時に大量のNOTICEがでてきました。

   Notice: Undefined variable: r_com

調べてみると,定義してない(NULL)状態の変数に操作をしているために起きるようで,それぞれの変数の直前に

    r_com=””

という記述で,変数は空(何も入ってないですよということらしい)ということを代入して,このNotice:を消しました。

その後,どうしても画像を表示できず,画像を操作していると思われるところを一つ一つ確認していきました。結局,WINDOWSの環境でデバックをしていましたので,ドライブの指定が間違っていて,小文字を大文字に変えたら,あっけなく表示できました。思わず,そばにいた妻に「やっった。」と叫んで,そのわけを説明しました。という訳で長い道のりでしたが表示だけできました。

でも,どうしても消せないNotice:があるので,あれこれこも調べましたが,プログラムで表示させなくできるということで,PHPのファイルの冒頭に,

error_reporting(E_ALL & ~E_NOTICE);

を記入することで,消すことにしました。しかし,消してみると新たに,

Deprecated: Function get_magic_quotes_gpc()

というエラー出てきました。これも調べてみると,PHP7では,実装されてなくて,常にFALSEを返すということで,該当の部分には,

 if(get_magic_quotes_gpc()) $gazoubbs = stripslashes($gazoubbs);

のような記述で,get_magic_quotes_gpc()が有効なら$gazoubbs = stripslashes($gazoubbs)を実行するということでした。常にFALSEを返すことから,$gazoubbs = stripslashes($gazoubbs)は実行されないので,ここは,削除することにしました。

これで,やっと,エラーも表示されなくなり,閲覧だけできるようになりました。

{追記}PHPのプログラムを追っていくなかでいくつか分からない表現にであいました。
      .$value.
    のような表現で,これも調べてみると,文字の結合を表す表現でした。分かったのもありますが,
        $dat.=’     のような表現が所々に,あり,このシングルクオ-テンションの意味が未だに不明です。単に$datに    「`」を結合するものなんでしょうか。

---本家のBlogn+が閉鎖に---

 このブログの本家というか,このブログのプログラムの大本が
 閉鎖になりました。
 何年か前から,更新がなく,どうしたのかなと思っていました。
 
 しばらくは,このまま使っても大丈夫だと思いますが,Windowsと
 かのアップデート等で,不具合がでてもこまるので,ぼちぼち
 他のシステムに乗り換える必要がありそうです。
 使う条件が,システムを自分でいじれることと,基本,無料が
 条件です。
 ネットをあさってみると,
    WordPress
    Movable Type
 あたりが適当なようですが,このブログを動かしている
 サクラのサーバーでは,WordPressが標準で簡単にインストール
 できるようになっているので,それを使ってみようかなと思います。
 乗り換えにあたっては,
      今までのブログをそっくり移行する
      今までのブログはそのままに新しい記事を移行する
 等でしょうが,ある時期をさかいに移行するのは,難しそうなので,
 とりあえず,平行して,徐々に,移行しようかなと思います。
 そのために,いろろ情報を収集します。

---Windows10の起動時のナンバーロック---

 久しぶりにWindows10の設定を見直しました。
 といっても,起動時にテンキーが使えないが不便で,前にも
 設定をしたのですが,ナンバーロックがされないままで,
 立ち上がる状態でした。
 久しぶりに検索をしましたら,諸兄のHP
 に行き着いて,
   
  1 regeditを起動
  2 HKEY_USERS \ .DEFAULT \ Control Panel \ Keyboard を開く
  3 「InitialKeyboradIndicators」の値を「2147483650」に変更する。
  4 regeditを終了する。

 をやればいいとのことでしたので設定を変更いたしました。
 結果,大丈夫でした。
 前にもここいじったことあるみたいでしたが,
   「InitialKeyboradIndicators」
 の値が,
   2147483650
 ではなくて
   2147483648
 でした。
 起動時のパスワードの入力にテンキーが使えます。

“---Windows10の起動時のナンバーロック---” の続きを読む