パソコンカレッジ スタッフのひとりごと

パソコンスクールのスタッフが、
初心者から上級者まで役立つ情報をお伝えします。

宛名を変えて自動的に連続印刷する方法(Excel2000以降)

2017-05-15 10:45:37 | ExcelVBA
今日は、先日いただきましたリクエストを取り上げます。

『昔仕事で、「申込書」「名簿」「許可書」に名簿の名前をいっぺんにうちこんで同時にプリントアウトする、
という高度なことを先輩がやってまして、(中略)あれはどういったプログラムだったのでしょう?』

多分こういう質問だろうと僕は解釈しました。
つまり、「別シートにある名簿から名前を取り込んで、その都度、印刷しては、次の名前を取り込む、
という繰り返しをプログラムで行う方法を教えてほしい」と。

解釈が違っていたら、また取り上げますので、ご連絡ください・・・


さて、以下のような発注書があるとします。







注目してほしいのは、A4(A列4行目)の数字です。この数字は、顧客Noなのです。
この数字に対応した顧客名がA6に読み込まれます。





実は、別シートに顧客名簿があるのです。ご覧いただきましょう。






さて、A6には、関数を設定してあります。
A4の値に対応した顧客名を名簿から参照する関数です。そうです、VLOOKUP関数ですね。






さて、さっそくコードを書いてみましょう。


ALT + F11 で、VisualBasicEditorを起動します。

「挿入」→「標準モジュール」をクリックします。

そこに、次のようにコードを記述してください。


Sub 連続印刷()
    Dim i As Integer
    Dim LastRow As Integer
    
    Worksheets("発注書").Select
    
    With Worksheets("名簿")
        LastRow = .Range("A65536").End(xlUp).Row
        For i = 2 To LastRow
            Range("A4").Value = .Range("A" & i).Value
            ActiveSheet.PrintPreview
        Next
    End With
End Sub



一応、画像も掲載しておきます。





名簿の顧客が増えても全員印刷できるように、名簿の最終行は、プログラムで判断しています。
また、この段階では、実際に印刷するわけではなく、確認のために印刷プレビューするコードになっていますので、
ご了承ください。


それでは、実行してみましょう。

Excelに切り替えて、Excel2003までは、「ツール」→「マクロ」→「マクロ」とクリックします。
Excel2007は、Altキーを押しながらF8キーを押してください。
実行ボタンをクリックします。






プレビュー画面が表示されますね。
この画面を閉じると、即座に次の顧客名でプレビューされます。
うまくいってますね。






実際に連続印刷する場合は、
ActiveSheet.PrintPreview
を、以下のように変更します。
ActiveSheet.PrintOut

ただし、顧客の人数が多い場合には、若干注意が必要です。
というのも、プリンタによっては、対応できずにエラーになることがあるからです。

この場合、対応するコードを追加したほうが安全です。
このコードについては、改めてご紹介しますね。



VBAって奥が深いですね。

奥が深いと言えば、エクセルって色々な機能があって、使い方によってはまるで手品(マジック)のようになるんですよね。

VBAをからめると、さらにドッキリ度がアップします。親子のやり取りを通じて、そんなエクセルの面白さが満載の本が、

子どもの“プログラミング的思考"をグングン伸ばす本

この本、おすすめですよ(^^)


だい
コメント (8)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

複数のコントロールのイベントを一つのプロシージャにまとめる(ExcelVBA)

2017-05-15 10:41:11 | ExcelVBA
今回は、VBAを取り上げます。

現在、生徒のU君は、VBAを勉強しています。基礎的なスキルを身につけたので、実践編へと進んでいます。
今取り組んでいる課題は、「VBAで電卓を作る」です。

みなさんも、一緒に考えてみませんか?



エクセルを起動して、ALTキー + F11キー を押します。
Visual Basic Editorが起動したら、「挿入」→「ユーザーフォーム」とクリックします。

画面に、フォームが表示されたら、以下の様にコントロールを配置します。


上部に、テキストボックス、
その下に、計20個のコマンドボタンを整然と配置します。
なお、フォーム名は、「frmCalc」としました。




このとき、注意してほしいことがあります。
数字の表示されているコマンドボタンの名前についてです。
今後の作業のために、ボタンの名前は、「任意の名前」+表示される数字 としてください。

例えば、
0と表示されたボタンは、「btn0」、
1と表示されたボタンは、「btn1」、
2と表示されたボタンは、「btn2」、
3と表示されたボタンは、「btn3」・・・という感じです。
数字の前の部分は、お好きな文字列で構いません。

今回は、b0, b1, b2, b3・・・と名前を付けてみました。

なお、数字以外のボタンは、分かりやすい名前なら何でもいいです。



さて、今日は、まず、手始めに、数字のボタンをクリックすると、
上部のテキストボックス窓に、数字を表示するところまで頑張りましょう。


普通に考えると、0~9までの数字のボタンのクリック時イベントに
コードを書くようになります。

下のような感じですね。






上の図のようなプロシージャが、9つ必要になりますね。

でも、よく見ると、各プロシージャのコードは、=の右辺が異なるだけです。

そうです。どれもみな、処理の内容は同じなのです。ただ、表示する数字だけが異なるのです。

それならば、この10個のプロシージャの処理内容を一つにまとめてしまい、
10個のどのボタンからも、この一つにまとめられたプロシージャを呼び出せば、全体がシンプルになります。

実は、そんな事が出来るのです。

Visual Basic 6 までは、この機能を「コントロール配列」と呼んでいました。

書き方は全く異なりますが、Visual Basic .NET 以降ももちろん同様の処理ができます。

ExcelVBAは、バージョン的には、VB6.x ですから、コントロール配列が使えればいいのですが、
残念ながら、この機能は搭載されていません。
従って、別の方法で実現します。その方法とは、「クラスモジュールを活用する」です。


それでは、クラスモジュールを追加しましょう。
「挿入」→「クラスモジュール」とクリックします。
(クラス名は、初期設定のClass1 のままでいきます。)

以下のようにコードを記述します。


'イベントを持つコマンドボタン型の変数を宣言
Private WithEvents Btn As MSForms.CommandButton
'ボタンの数字を格納する変数を宣言
Private Index As Integer

Public Sub NewClass(ByVal c As MSForms.CommandButton, _
ByVal i As Integer)
  'いわゆるコンストラクタ処理

  '引数のコマンドボタンを変数に格納
  Set Btn = c
  'コマンドボタンの数字を変数に格納
  Index = i
End Sub

Private Sub Btn_Click()
  'frmCalcフォームのTextBox1に、
  '変数Indexの中身を表示する

  frmCalc.TextBox1.Text = Index
End Sub


一応、画像も載せておきます。





クラスというのは、いわゆるオブジェクトの原型で、このクラスからインスタンスを生成して使用します。
(VB.NET以降は、オブジェクト指向言語になっていますので、クラスの使い方がとても重要です)

VB6でも、一応クラスは用意されているんですね。

このクラスは、コマンドボタンのイベントプロシージャを持っています。
クリック時に、フォームのテキストボックスに数字を表示する機能を持っています。

あとは、このクラスを10個の数字のコマンドボタンにひもづけてあげればいいのです。

そのためのコードを、ユーザーフォームに記述します。

以下のように記述してください。

Option Explicit

Private NumBtn(0 To 9) As New Class1


Private Sub UserForm_Initialize()
  'インスタンスの生成

  Dim i As Integer
  For i = 0 To 9
    NumBtn(i).NewClass Controls("b" & i), i
  Next

End Sub

一応、画像も載せておきます。




モジュールレベルの変数NumBtnを宣言します。型は、Class1 となっております。
このClass1は、先程つくったクラスのことですよ。
でも、よく見ると、As のあと、Class1 の前に Newというキーワードがあります。
これが重要です。このNew を付けることによって、クラスは実体をもつようになります。(インスタンスと言います)

なお、NumBtn(0 To 9) の、かっこの部分は配列を示しています。
つまり、この変数は、10個の部屋を持つ変数なのです。
配列にしたのは、このインスタンスにボタンを登録する際に、コードを効率的に記述するためです。
(インスタンスを一つ生成するだけなら、配列にする必要はありません)


UserFormの初期化イベントの際に、このインスタンスに数字のコマンドボタンを登録しています。
UserForm_Initialize() の中をご覧ください。

NumBtn(0)には、コマンドボタンb0 を登録します。
コードで書くと、
NumBtn(0).NewClass Controls("b0"), 0
となります。

NewClass によって、コマンドボタンb0 と 数字の 0 をインスタンスに登録し、
ボタンをクリックしたときに、クラスで記述したクリック時イベントが実行されるようになります。


今回は、繰り返し処理によって、コマンドボタンのb0 から b9 までをインスタンスに登録しています。

これで、仕込みは終了です。

このフォームには、各数字ボタンのクリック時イベントが記述されていないことを確認してください。





それでは、フォームを表示して、数字のボタンを押してみましょう。

1 のボタンを押すと、上部のテキストボックスに 1 と表示されます。
同様に、2 のボタンを押せば、 2 と表示されます。






VBAって奥が深いですね。

奥が深いと言えば、エクセルって色々な機能があって、使い方によってはまるで手品(マジック)のようになるんですよね。

VBAをからめると、さらにドッキリ度がアップします。親子のやり取りを通じて、そんなエクセルの面白さが満載の本が、

子どもの“プログラミング的思考"をグングン伸ばす本

この本、おすすめですよ(^^)



だい
コメント (28)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

ExcelVBAの練習 ユーザーフォームのボタンをクリックした時に別のブックを開きましょう

2017-05-11 19:09:35 | ExcelVBA
こんにちは。今日の上田はとてもいい天気。こんな日はワンコと一緒に

山菜採りにでも行きたいなぁ。今はこごみにタラの芽、こしあぶらなど

天ぷらにしたらおいしい食材が、お山でタダで手に入る素晴らしい時期なのです(^^♪


しかしお仕事も大好き!山は週末に行くことにして

今日も生徒さんからの質問を取り上げます。

「せんせーい、私『アプリ作成で学ぶ ExcelVBAプログラミング
ユーザーフォーム&コントロール』
買ったんですよ」

まぁありがとう。で?

「練習でユーザーフォームを作りました」
「ユーザーフォームにボタンを配置して、クリックしたら別のブックを開くようにコードを書いてみました」
「でもそのあとが・・・」

こおゆうことね↓

【Book1にユーザーフォームを作成し、ここからBook2を開くようにする】

ではExcelを起動します 私はExcel2010を使用しています

開発タブを選択(※開発タブが非表示の場合は、ファイルタブ→オプションより設定)

そしてVisualBasicを選択するとエディタが開きます




挿入→ユーザーフォームよりユーザーフォームが作成されます このフォームの名前は
「UserForm1」です。Excelのほうで勝手につけてくれた名前です もちろん変更もできますが
このまま使います



ツールボックスからボタンを選択してユーザーフォームに配置



プロパティウィンドウでオブジェクト名を「Btn_book2」
Captionを「Book2を開く」にする
※オブジェクト名は自分で好きな名前をつけてOK。私は「Btn_book2」にしましたよ
※Captionはボタン上に表示したいもの



いったんここで任意の場所に名前をつけて保存しておきましょう

ブックウィンドウに切り替えるためにエディタの左上のエクセルマークをクリックします



「名前を付けて保存」ダイアログを表示しましょう

保存時の注意ですが今回はコードを含んだファイルとして保存したいので、
ファイルの種類を「マクロ有効ブック」にします
名前は最初に表示されている「Book1」のままでいいです
では保存しましょう



出来たファイルは「Book1.xlsm」になります。


さて
次は先ほど作成したユーザーフォームの起動のチェックをしましょう。

エディタに切り替えます。開発タブ→VisualBasic

挿入メニュー→標準モジュール



ユーザーをフォームを起動させるためのコードを記述します

以下のように記述↓



「UserForm1.show」は「UserForm1を表示しなさい」という意味です

このコードをワークシート上にボタンを作って登録していきますよ

ブックウィンドウに切り替えます(エディタ左上のエクセルマークをクリック)

開発タブ→挿入→フォームコントロールのボタンをクリック



ワークシート上で右斜め下にドラッグしてボタンを作成する と同時にマクロの登録ダイアログが表示
されるので「ShowForm」を選択して→OK



「ボタン1」というボタンが作成されました 一度セルをクリックし、ボタンの編集を解除したあと
「ボタン1」をクリックしてみましょう

おっユーザーフォームが表示されました。



さて、このユーザーフォームの「Book2を開く」ボタンをクリックしてみましょう

ボタンは押せるけど何も動作しません。そうです。だってまだこのボタンの動作を
登録していませんから(^^

「Book2というファイルを開く」という動作を登録していきましょう。

おっと、Book2というファイルを作成しておかなければなりませんね。

いったんBook1を閉じてもいいし、このまま新規作成でもいいので
適当なデータを入れたBook2.xlsxを作成しましょう。(ファイル名はBook2、ファイルの種類は
Excelブックですよ)

私はこんなBook2にしました↓




ではBook2ファイルは閉じておきましょう

さてBook1.xlsmを開き、続きをやっていきましょう

エディタを開きます(Altキー+F11キーがショートカットです)

表示されているユーザーフォームのボタンをダブルクリックします

ここに「Book2というファイルを開く」コードを記述していきます
画像のとおりに記述しましょう ただし"C:\Users~~"はPCごと違いますので、Book2ファイルのあるパスを記入しましょう




このコードは「Workboooks.Open」 まさに「あるワークブックを開きなさい」という意味です。そして
そのあとに書いてあるファイルのパスで、ファイルの場所と名前を指定しています

ユーザーフォームのボタンをクリックしたときの動作の登録はこれで以上です

ブックウィンドウに切り替えて、ワークシート上のボタンからユーザーフォームを表示し、
さらに「Book2を開く」ボタンをクリックしましょう

ほら!ユーザーフォームの後ろにBook2が開いています



はぁ

ここまで長々ありがとうございました。

「せんせーい」
「せんせーい」

え?Book2の前のユーザーフォームが邪魔?

まぁ確かにそうね・・これじゃBook2の操作ができませんね・・汗

「それなんですよ!理想はBook2を開いたときにユーザーフォームを閉じたいんです」

はい!もう一度エディタに切り替えますよ(今開いているユーザーフォームは×ボタンで閉じ、Book2も閉じてから)

ユーザーフォームのボタンをダブルクリックし、先ほどのコードの下に1行追加しましょう



「Unload Me」は「私(UserForm1)を閉じます」という意味です

これでもう一度やってみましょう
(ブックウィンドウに切り替えて、ワークシート上のボタンからユーザーフォームを起動)

「お~これですよ♪」
「でもーついでにBook1も閉じたいなぁ」

了解
ではBook2を閉じて、Book1のエディタに戻ってさらにもう一行追加ね



「ThisWorkbook.close」は「このワークブック(Book1のこと)を閉じなさい」という意味です。
(フォームとブックでは 閉じるときの書き方が違うのでややこしいですね)

これでOK

「はーい では練習しまーす」

うんがんばって(^^♪


エクエルって奥が深いですね。

奥が深いと言えば、エクセルって色々な機能があって、使い方によってはまるで手品(マジック)のようになるんですよね。

子どもの“プログラミング的思考"をグングン伸ばす本

この本、おすすめですよ(^^)

mihoりん

他にも色んな本を書いています。

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

ExcelVBAで参照設定をおこなう

2015-05-20 13:19:09 | ExcelVBA
ExcelVBAの参照設定の方法について説明します。

僕の著書「知識ゼロから学ぶExcelVBAプログラミングユーザーフォーム&コントロール」を買っていただいた方から
メールで質問があり、その回答です。


例えば、FileSystemObjectというクラスを使ってファイルの操作を行う場合には
このクラスを使用できるように予め参照の設定をおこなっておくことが必要です。※1
そこで、FileSystemObjectを例にとって設定をしてみます。

※1 実は、参照設定をおこなわないでクラスを使用することもできますが、その説明は次回とします。

なお、この参照設定は現在開いているブック(ファイル)に対して行われます。
従って、FileSystemObjectを使いたいExcelファイルを最初に開いておいてください。

Visual Basic Editorを開きます。

次に「ツール」メニューの「参照設定」をクリックします。





参照設定ダイアログボックスが表示されます。
現時点で有効になっている(使用可能な)ライブラリファイルにはチェックがついています。
(なお下の画像でチェックの入っているファイルについては、チェックをはずしてはいけません。)
ライブラリファイルにはそれぞれクラス(機能の設計図みたいなもの)が格納されています。

※チェックされた項目の中に「参照不可」がある場合は注意が必要です。必ずその項目のチェックを外してください。
そのままにしておくとVBAのコードが正しく実行されません。






FileSystemObjectというクラスを使用するために、「Microsoft Scripting Runtime」というファイルを有効にします。
つまり、チェックを入れます。なお一覧はアルファベット順にファイルが並んでいるので、かなりスクロールしてくださいね。




チェックを入れたら「OK」をクリックします。参照設定ダイアログボックスが閉じられます。

以上で参照設定が完了しました。

ちゃんと設定されているのか確認したいときは、再度「ツール」メニューの「参照設定」をクリックしてください。
今回追加した「Microsoft Scripting Runtime」にチェックが入っていることが分かります。
(かくにんしたら「OK」で閉じておいてください。)






ちなみに正しく参照設定をおこなっておくと、コーディングの際に入力候補が表示されます。







だい
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

リストボックスの最大列数について(Excel VBA)

2013-03-17 13:45:20 | ExcelVBA
拙著「ExcelVBAプログラミング ユーザーフォーム&コントロールパネル」に関して
リストボックスの列数の設定についての質問をしばしばいただきます。

リストボックスの列数の設定は、ColumnCountプロパティでおこないます。

今回は、最大何列まで可能なのか、検証してみたいと思います。

Excelを起動したら、Visual Basic Editorを開き、ユーザーフォームを挿入します。
任意の大きさにしたら、コマンドボタンとリストボックスを追加します。
それぞれ、「btn1」と「ListBox1」という名前にします。




このユーザーフォームのInitializeイベントに、列数と列幅の設定をコーディングします。
なお、画像にはコメントアウトしてしてあるコードがありますが、
これはあとで検証するためのコードです。今は気にしないでください。


今回は、リストボックスの列数を25列にしました。
そして、各列の幅を全て30ptにしました。
列幅を狭くすることによって、できるだけ横スクロールしないですむようにしたつもりです。
Private Sub UserForm_Initialize()
    With ListBox1
        .ColumnCount = 25   '列数を25に設定 次の行で列幅を設定
        .ColumnWidths = "30;30;30;30;30;30;30;30;30;30;30;30;30;30;30;30;30;30;30;30;30;30;30;30;30"
    End With
End Sub

続いて、btn1をクリックしたときの処理をコーディングします。

リストボックスに1行追加し、
その後ループ処理で、その行の各列に値を設定していきます。
もし、エラーが発生したら、その時のカウンター変数 i の値と
エラーメッセージを表示するようにします。

なお、画像のループ回数が15になっていますが、大目に見てください。


Private Sub btn1_Click()
Dim i As Integer
ListBox1.AddItem
On Error GoTo eh
For i = 0 To 25
ListBox1.List(0, i) = i & "列目"
Next
Exit Sub
eh:
Dim msg As String
msg = "変数 i の値: " & i & vbNewLine
msg = msg & Err.Number & ":" & Err.Description
MsgBox msg
End Sub







さて、このユーザーフォームを表示し、ボタンをクリックすると

次の画像のようにエラーメッセージが表示されます。




列数は25と指定しているのに、10列しか表示できないことになります。
このことから、最大10列という制約があると考えられます。


ちなみに、もう一つ実験をしてみましょう。

シートの1行目に値を入力しておきます。分かりやすいように0から始まる数字に「列」をつけておきます。
今回は、Y列まで入れておきました。





次に、ユーザーフォームのInitializeイベントに、次の1行コードを追加します。

ListBox1.RowSource = "A1:Y1"

リストボックスのRowSource プロパティにセル範囲を指定しています。
リストボックスに値を表示するには、このようにRowSource プロパティを使うこともできます。
RowSource プロパティのセル範囲がリストボックスに表示されます。




改めてユーザーフォームを表示してみましょう。

今度は、25列までリストボックスに表示されました。




このように、RowSource プロパティを使うと、10行の制約は無視されます。
このあたりが、リストボックスの不思議なところだと感じてしまいます。

ただし、最大何列まで表示されるかは、まだ僕も試していません。

よろしかったら、皆さんもお試しください。結果を教えていただけると幸いです。


だい

コメント (1)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

大文字小文字を区別して検索するVlookup関数の改良版

2012-05-23 09:00:23 | ExcelVBA
これも、生徒さんからの質問です。

セルB3に入力された商品CDに対応する商品名を、
セル範囲B8:D14の商品リストから見つけ出してセルC3に表示したいとのこと。



仕事をしていると、よく遭遇する場面ですよね。
こういう場面では、Vlookup関数を使うのが定石です。

しかし、今回は、少しばかり勝手が違うのです。

商品リストをよく見ると、商品CDにはある特徴があるのです。
それは、「大文字と小文字で分けられている」ということです。
つまり、「A001」と「a001」は、別の商品CDなのです。

さて、このような場合でVlookup関数を使うと、事件が起きます。
商品CDに「a002」を指定すると、答えが「ホットケーキ」になってしまうのです。
商品リストを見ると、商品名は、「ホットケーキ(バター付)」ですよね。





なぜ間違った答えが出てしまうのかというと、Vlookup関数は、
「A002」と「a002」を同じデータとみなすからです。
Vlookupは、セル範囲B9:B14の値を、上から順番に検索値(つまりセルB3の値)と一致するかをチェックします。
その際、セルB10の「A002」と検索値が一致していると判断し、答えがセルC10の「ホットケーキ」になってしまうのです。

そんなわけで、大文字と小文字を別の文字として検索する新たな関数「VLookupSpecial」を作ることにしましょう。

Altキーを押しながらF11キーを押して、Visual Basic Editorを起動します。
挿入メニューの「標準モジュール」をクリックします。
コード画面に、以下のようにコーディングします。

Public Function VLookupSpecial(ByVal 検索値 As String, _
                          ByVal 範囲 As Range, _
                          ByVal 列番号 As Integer) _
                          As String
  '大文字と小文字の区別をして検索する
  '見つからなかったら、「見つかりません」という答えにする
  Dim r As Integer
  '選択範囲の行数を取得
  r = 範囲.Rows.Count
  Dim i As Integer
  For i = 1 To r
    '引数「範囲」の1列目を順次チェック
    If 範囲.Cells(i, 1).Value = 検索値 Then
      VLookupSpecial = 範囲.Cells(i, 列番号).Value
      Exit Function
    End If
  Next
  VLookupSpecial = "見つかりません"
End Function

画像も載せておきます。




この関数は、VLookup関数と同じような引数構成にしましたが、第4引数はなしにしました。
処理の内容は、VLookup関数の内部で行われているであろう処理に合わせました。

文法的に押さえておきたいのは、IF構文に登場する
範囲.Cells(i, 1).Value
です。これは、「引数のセル範囲において、その中のi行1列目のセルの値」を指しています。
セル範囲の中でのセルの位置を指定するには、このように書くんですね。

さあ、コードを入力できたら、エクセルに切り替えて、さっそくこのVLookupSpecial関数を使ってみましょう。





どうです?
今度は、ちゃんと答えが出ましたね。

えっ?そもそもこんな風に大文字と小文字を区別して商品CDに設定すること自体が、NGだって?

おっしゃることは分かりますが、そこは、会社によって色々と事情があるということで・・・


だい


コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

IF構文を使わないで条件分岐を実現する

2012-04-07 09:01:07 | ExcelVBA
たとえば、以下のような表があるとします。



B列には、商品コードが入力されています。
C列には、在庫数が入力されています。

さて、ここで次のような要望があったとしましょう。

「C列の在庫数が0の場合は、B列の商品コードを太字にしたい。
ただし、在庫数が0でなければ、B列の商品コードの文字は太字にしない。」

さあ、どう対処しましょうか?
なお、商品数は固定とします。

条件付き書式を使えば簡単ですね。
でも、折角ですから、VBAで対応してみましょう。

普通に考えれば、以下のサンプルコードのようになるでしょう。



Sub Test()
  Dim i As Integer
  For i = 3 To 12
    If Cells(i, 3).Value = 0 Then
      Cells(i, 2).Font.Bold = True
    Else
      Cells(i, 2).Font.Bold = False
    End If
  Next
End Sub

条件分岐を使って、C列の在庫数が0のときは、B列の値を太字にします。
太字にするには、BoldプロパティにTrueを代入します。

もちろん、これで、まったく問題はありません。
でも、今回は、IF構文(条件分岐)を使わないでコーディングする方法を紹介します。


Sub Test2()
  Dim i As Integer
  For i = 3 To 12
    Cells(i, 2).Font.Bold = Not CBool(Cells(i, 3).Value)
  Next
End Sub


解説をします。

太字にするには、BoldプロパティをTrueにし、太字にしない場合はFalseにするという特性を
十分に活かしているコードです。

CBool関数は、引数をBoolean型に変換します。
Boolean型とは、TrueもしくはFalseの2つしか値をとれない型です。
引数にはC列の値を指定していますから、数値(在庫数)をBoolean型に変換しています。

実は、数値の0は、Falseを意味し、0以外の数値は、全てTrueと解釈されます。
C言語は、そのあたりをふまえてコーディングする場面が多いのですが、
もちろん、VBAでもそのテクニックは使えます。

また、Not演算子は、否定を意味します。
在庫数が0の場合は、Falseと解釈されますので、Not演算子を使ってTrueにしています。

このようにBoolean型の値を設定するプロパティに対しては、
Cbool関数と、場合によってはNot演算子を使うことによって
条件分岐をすることなくコーディングすることができます。

実行結果を載せておきます。



だい
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

エクセルの全画面の切り替え(Excel2000以降)

2012-02-22 09:03:51 | ExcelVBA
今日は、ExcelVBAを取り上げます。

さて、エクセルには全画面モードがあるのをご存知でしょうか。
今回は、Excel2010で、全画面モードの切り替えプログラムを作成します。

エクセルを起動したら、Altキー+F11で、Visual Badic Editorを起動します。

挿入メニューの「標準モジュール」をクリックして、モジュールを新規作成します。

そこに、次のように記述してください。


Sub main()
  With Application
    .DisplayFullScreen = Not .DisplayFullScreen
  End With
End Sub

画像も載せておきます。




以上です。えらく短いプロシージャですが、
このプロシージャを実行するごとに、全画面表示と通常表示が切り替わります。
ちなみに、ApplicationオブジェクトのDisplayFullScreen プロパティにTrueを代入すると
全画面表示となります。

あとは、エクセルに切り替えて、マクロの実行をしてください。

下の画像のように、ボタンにマクロを登録するのもいいでしょう。




ボタンを押すごとに、画面モードが切り替わります。




えっ?それがどうした?

それを言っちゃあおしめいよ!(寅さん風に)



だい
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

セルのイルミネーション?

2011-12-28 09:00:32 | ExcelVBA
クリスマスも過ぎ、今年もあとわずかになりました。皆さん、お変わりありませんか?

さて、今日は、エクセル上でイルミネーションのようなものを作ってみましょう。
何の役にも立ちませんが、クリスマスの余韻ということで大目に見てください。

エクセルを起動して、Visual Basic Editorを表示します。
「挿入」、「標準モジュール」とクリックして、さあ、コーディング開始です。

Sub main()
  Dim r As Range
  Randomize
  For Each r In Range("A1:J10")
    r.Interior.Color = RGB(Int(Rnd() * 255), Int(Rnd() * 255), Int(Rnd() * 255))
    DoEvents
    ThreadSleep 1000000
    r.Interior.ColorIndex = 0
  Next
End Sub

Private Sub ThreadSleep(ByVal n As Long)
  '時間稼ぎのプロシージャ
  Dim i As Long, a As Long
  For i = 0 To n
    a = Sqr(i) * Sqr(i)
  Next
End Sub

画像も載せておきます。



結果がどうなるかは、実際にプログラムを実行してください。

コードの簡単な解説です。

For each Next構文で、セル範囲A1:J10のセルを順にrに代入しています。
rの塗りつぶしの色をRGB関数で指定しています。
引数は、左から順番に赤の割合、緑の割合、青の割合を0~255で指定します。

この値を、Rnd関数で指定しています。
Rnd関数は、乱数を発生させる関数で、0~1未満の数をランダムに発生させます。

ただし、本当にランダムにするには、事前にRandomizeステートメントを記述しておく必要があります。
DoEventsは、面白いステートメントで、客観的に自分を見直す役割をします。
繰り返し処理の描画がうまくいかない場合には、この一文を入れます。

ThreadSleep は、時間稼ぎのためのプロシージャです。引数を大きくすると動きが遅くなります。
反対に小さくすると早くなります。
私のPCでは、1000000がいい感じでした。適宜調整してください。
そのあと、セルの塗りつぶしをなしにしています。


今年一年、お世話になりました。
来年も実りのある一年になることを祈っています。

新年にまたお会いしましょう。


だい
コメント (18)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

模様を作って遊ぶ

2011-12-14 12:52:27 | ExcelVBA
今日は、エクセル上で、模様みたいなものを作って遊びましょう。

こんな感じです。



はっきり言って、遊びです。ご了承ください。

この模様は、直線という図形をたくさん使って表現されています。

そのようなプログラムを作成する必要があります。

エクセルを起動し、Altキーを押しながらF11キーを押して、Visual Basic Editorを表示します。

「挿入」メニュー、「標準モジュール」とクリックし、コード画面を表示したら、以下のように書きましょう。

Sub main()
  'きれいな模様を書く
  Dim x1 As Double, x2 As Double, y1 As Double, y2 As Double
  Dim i As Integer
  For i = Selection.Left To Selection.Left + Selection.Width Step 5
    x1 = i
    y1 = Selection.Top
    x2 = (Selection.Left + Selection.Width) - (i - Selection.Left)
    y2 = Selection.Top + Selection.Height
    Call DrawLine(x1, y1, x2, y2)
  Next
  Range("A1").Select
End Sub

Private Sub DrawLine(ByVal x1 As Double, _
                  ByVal y1 As Double, _
                  ByVal x2 As Double, _
                  ByVal y2 As Double)
  '直線を引く
  With ActiveSheet.Shapes.AddLine(x1, y1, x2, y2).Line
    .ForeColor.RGB = RGB(0, 0, 255)
    .Style = msoLineThickThin
  End With
End Sub


Sub DeleteShapes()
  Dim s As Shape
  For Each s In ActiveSheet.Shapes
    s.Delete
  Next
End Sub

画像も載せておきます。



mainプロシージャをご覧ください。
繰り返し処理をおこなっています。その中で呼ばれているDrawLineが直線を引くためのプロシージャです。
引数に、開始点のx座標とy座標、終了点のx座標とy座標、都合4つを指定すると直線を引くことができます。
選択されたセル範囲に関して、開始点と終了点を巧みにずらして直線を引いているのです。
線の色は、RGB関数で指定しています。

エクセルに切り替えたら、適当なセル範囲を選択して、mainを実行してみてください。
何回も実行してみてください。
直線を消したいときは、DeleteShapesプロシージャを実行してください。すべての直線が削除されます。




だい
コメント (3)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

ひと月を30日間として経過日数を計算する方法(ExcelVBA)

2011-11-16 09:02:16 | ExcelVBA
今日は、オリジナル関数を作成します。

というのも、変則的な計算をする必要が出てきたからです。

下の表を見てください。




開始日から終了日までの日数を計算したいのです。
ただし、
1.開始日も含める。
2.ひと月を30日として計算する。
という制約があるのです。


普通に求めるには、DATEDIF関数を使います。
=DATEDIF(B3,C3,"D")
と入力すれば、答えが出てきます。
これが正しい答えなのですが、今回の制約を満たしてはいません。

そこで、ExcelVBAを使って、ユーザー定義関数を作ります。

その名も!DateDiffSpecial関数です!(・・・|)

結果として、下のようになります。








ポイントは、「ひと月を30日として計算する」です。
たとえば12月は31日あります。また、2月は28日であったり29日であったりします。(閏年ですよ)

考え方は、いろいろあるでしょうが、今回は、以下のように攻めます。





つまり、開始日と終了日が同じ月なのか、1月だけ違うのか、それとももっと離れているのか、
この3つに分けて考えれば答えが出そうです。
その際、ひと月が30日になるように工夫をします。


さっそく、コーディングに入りましょう。

エクセルを起動したら、Altキーを押しながらF11キーを押して、VisualBasicEditorを表示します。

「挿入」→「標準モジュール」とクリックします。

表示されたモジュールにコードを記述しましょう。

オリジナル関数は、Public Function [関数名](引数1,引数2,・・・)As データ型
と書き始めます。

最後のデータ型は、この関数の戻り値(答え)のデータ型を指定するものです。

コードの中に 「 関数名 = 値 」を書くことによって、関数の答えとなります。

以下のように書いてみましょう。


Public Function DateDiffSpecial(ByVal startDay As Date, _
ByVal endDay As Date) As Integer
' 2つの日付の差を取得する。ただし、1か月を30日として計算

  If startDay > endDay Then
    '引数設定ミスは、0を返す
    DateDiffSpecial = 0
    Exit Function
  End If

  '終了日が末日かどうかをフラグに代入
  Dim IsMatsujitsu As Boolean
  If Day(endDay) = Day(DateSerial(Year(endDay), Month(endDay) + 1, 1) - 1) Then
    IsMatsujitsu = True
  Else
    IsMatsujitsu = False
  End If

  Dim Ans As Integer
  Ans = 0
  Dim a As Integer
  '開始日と終了日の月数の差を取得
  a = DateDiff("M", startDay, endDay)
  Select Case a
    Case 0
      If IsMatsujitsu Then
        Ans = 30 - Day(startDay) + 1
      Else
        Ans = Day(endDay) - Day(startDay) + 1
      End If
    Case 1
      Ans = 30 - Day(startDay) + 1
      If IsMatsujitsu Then
        Ans = Ans + 30
    Else
        Ans = Ans + Day(endDay)
      End If
    Case Is >= 2
      Ans = 30 - Day(startDay) + 1
      Ans = Ans + (a - 1) * 30
      If IsMatsujitsu Then
        Ans = Ans + 30
      Else
        Ans = Ans + Day(endDay)
      End If
  End Select

  DateDiffSpecial = Ans
End Function


画像も載せておきます。




条件分岐の方法として Select Case 構文と使う方法と、IF構文を使う方法がありますが、
今回は、その両方を使っています。

つまり、Select Case 構文で、大きく3つの条件分岐を設定し、
その中で、さらに30日になるようにIF構文で条件分岐をしています。

ゆっくりと読んでいくと、ロジックを理解できるでしょう。

なお、If IsMatsujitsu Then というのは、
If IsMatsujitsu = True Then
と同様の意味となります。= True は、省略可能なのです。

また、DateDiff関数は、エクセルのワークシート関数ではなく、VBAが持っている関数です。
引数の順番が異なりますので注意が必要です。

もうひとつ、末日の日を抜き出したい場合は、
Day関数の引数に、翌月1日-1 という値を指定すればいいのです。
翌月1日の前日は、その月の末日になるからです。



この関数を用いるには、答えを出したいセルに「=DateDiffSpecial(B3,C3)」と入力するだけです。




10月30日と11月1日の2日間ということで、答えは2となります。


セルの値を下のように変更してみます。




9月30日と10月1日の2日間ということで、やはり、答えは2となりますね。




えっ?なぜこんなややこしいことをしているのかって?
確かに無意味に見えるかもしれませんが、実は、あるソフトを制作するためにどうしても必要な機能なのです。

次回は、その一部をご紹介できるかもしれません。


それでは、また。


だい
コメント (2)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

VBAで英数字を漢数字に変換する方法(Excel2002以降)

2011-08-18 09:01:06 | ExcelVBA
暑い日が続いています。みなさんお元気ですか。

今日は、ユーザーが入力した任意の数字を漢数字に変換するプログラムを一緒に作りましょう。




ユーザーは、セルB4に好きな数字を入力します。
例として、「1234567」と入力します。






右にあるボタンをクリックすると、セルC4に漢数字に変換されて出力されます。
「一二三四五六七」と出力されました。

このボタンには、マクロが登録されています。
今日は、このマクロ(プロシージャ)をつくります。








それでは、エクセルを起動してください。
次に、Altキーを押しながら、F11キーを押してください。Visual Basic Editor が起動します。
「挿入」→「標準モジュール」とクリックしてください。
これで、コードウィンドウが表示され、コーディングの準備が整いました。

以下のように書いてください。


Sub ConvertChineseNumber()

  Dim i As Integer
  Dim c As Integer
  Dim s As String
  Dim Ans As String


  Ans = ""
  's には、ユーザーの入力した数字を代入
  s = Range("B4").Value

  'Len関数は、引数の文字数を取得できる
  c = Len(s)

  For i = 1 To c
    '変数sに格納されている数字を左から1文字ずつ
    '抜き出して、漢数字に変換。
    Select Case Mid(s, i, 1)
      Case 1
        Ans = Ans & "一"
      Case 2
        Ans = Ans & "二"
      Case 3
        Ans = Ans & "三"
      Case 4
        Ans = Ans & "四"
      Case 5
        Ans = Ans & "五"
      Case 6
        Ans = Ans & "六"
      Case 7
        Ans = Ans & "七"
      Case 8
        Ans = Ans & "八"
      Case 9
        Ans = Ans & "九"
      Case 0
        Ans = Ans & "〇"
      Case Else
        Ans = Ans & Mid(s, i, 1)
    End Select
  Next
  '変数Ansには、返還された漢数字が入っている
  Range("C4").Value = Ans

End Sub

参考までに、画像も載せておきます。





ユーザーが入力する数字は、何桁あるか分からないので、
Len関数を用いて、文字数(=桁数)を取得します。

あとは、その数字の左から1つずつ数字を抜き出して、漢数字に置き換えていきます。
数字は、10こ(0~9)あるので、条件分岐は10必要になりますが、
さらに、英数字以外が入力された時を考慮して、最後に Case Else という条件分岐を追加してあります。
この場合は、抜き出された文字をそのまま出力するコードが書かれています。
ですから、ユーザーが「123a45」と入力すると「一二三a四五」と出力されます。

もし、この部分をコメントアウト(行頭にシングルコートをつけて、プログラムの実行対象から外すこと)すると
「123a45」は、「一二三四五」と出力されます。つまり、数字以外は出力されません。




さて、今回のプログラミングもまた、条件分岐と繰り返し処理が使われていますね。
この2つは、プログラミングのキモです。使いこなしたいですね。



ところで、実は、ここまで引っ張っておいていまさら何ですが、エクセルには、こんな関数があるのです。

NUMBERSTRING関数といいます。
残念ながら、関数一覧には出てきませんので、関数名を手入力してください。
引数は、2つあります。
1つ目は、変換したい数値のあるセル番地、または値です。
2つ目は、変換方法です。1、2、3のどれかを指定します。それぞれの違いは、実際に試してみてください。
なかなかすごい関数です。






以上、プログラムと関数の勉強でした。



だい
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

VBAでカレンダーを作成しよう(Excel2002以降)

2011-07-21 09:01:06 | ExcelVBA
毎日暑い日が続いていますね。体調を崩さないようにご注意ください。

さて、今日はカレンダーを作成します。
方法はたくさんあるでしょうが、今回は、VBAを使って作ってみましょう。
せっかくですから、年と月を自由に指定できるようにしますよ。

下の図が、今回のカレンダーです。
年と月を指定し、作成ボタンを押すと、カレンダーが自動的に作成されます。

あらかじめ、1行目の曜日の見出しと枠線は、作りこんでおいてください。





それでは、VisualBasicEditorを起動します。
Altキーを押しながらF11キーを押すと起動します。

挿入メニューから「標準モジュール」をクリックします。
これでコードを書く準備が整いました。

べたなプロシージャ名ですが、「カレンダー作成」とし、コードを記述してください。

Sub カレンダー作成()
  Range("A2:G7").Value = ""
  MakeCalendar
End Sub



画像も載せておきます。




処理内容としては、日付をクリアして、MakeCalendarというプロシージャを呼び出すだけです。
つまり、カレンダー作成のメインプログラムは、MakeCalendar なのです。


それでは、その MakeCalendar のコードを書きましょう。


Sub MakeCalendar()
  '条件分岐を使ったプロシージャ

  Dim nen As Integer, tsuki As Integer
  nen = Range("J1").Value
  tsuki = Range("L1").Value

  Dim FirstDay As Date
  'ユーザーが指定した年月の1日目を日付として生成
  FirstDay = DateSerial(nen, tsuki, 1)
  Dim lastDay As Integer
  lastDay = Day(DateSerial(nen, tsuki + 1, 1) - 1)

  Dim RowNo As Integer
  Dim ColumnNo As Integer

  RowNo = 2
  ColumnNo = Weekday(FirstDay, vbSunday)

  Dim i As Integer
  For i = 1 To lastDay
    Cells(RowNo, ColumnNo).Value = i
    If ColumnNo = 7 Then
      ColumnNo = 1
      RowNo = RowNo + 1
    Else
      ColumnNo = ColumnNo + 1
    End If
  Next

End Sub





繰り返し処理と条件分岐を駆使します。
列番号が7になると、次の行の1列目に移動する点がポイントです。





これでめでたしめでたし、といきたいところですが、これでは、短すぎて、ケンさんに怒られてしまうので、
もう少し、お付き合い下さい。

カレンダーのように、一定の周期で繰り返されるデータに関しては、工夫すると条件分岐を使わないで済む場合があります。
少しばかり、頭を使いますが、これもパズルのようで楽しいもんです。

周期のある場合、よく使うのが割り算です!
それも、余り(剰余)が大活躍します。
今回も、基本的には、7で割った余りをうまく使います。これが列を特定するのに役立ちます。
行は、割り算の商を活用します。

それでは、MakeCalendar1 という名前でプロシージャを書いてみましょう。

Sub MakeCalendar1()
  '条件分岐を使用しないでカレンダーを作成

  Dim nen As Integer, tsuki As Integer
  nen = Range("J1").Value
  tsuki = Range("L1").Value

  Dim FirstDay As Date
  'ユーザーが指定した年月の1日目を日付として生成
  FirstDay = DateSerial(nen, tsuki, 1)

  Dim k As Integer
  'ユーザーが指定した年月の1日目の曜日を取得
  '日曜:1 月曜:2 火曜:3 ・・・
  k = Weekday(FirstDay, vbSunday)

  Dim lastDay As Integer
  'ユーザーが指定した年月の末日を取得
  '翌月1日の前日が、当月の末日
  lastDay = Day(DateSerial(nen, tsuki + 1, 1) - 1)

  Dim i As Integer
  Dim r As Integer, c As Integer
  For i = k To k + lastDay - 1
    '行番号を算出
    '7で割った商に補正係数の2を加算
    r = Int((i - 1) / 7) + 2
    '列番号を算出
    '7で割った余りに1を加算
    c = (i - 1) Mod 7 + 1
    '上記の行列番号の番地のセルに数字の1から順番に代入
    Cells(r, c).Value = i - k + 1
  Next

End Sub




解説は、コードに書いておきました。

行も列も、商や剰余を使って、どうやったらカレンダーができるか、考えてみると面白いですよ。

ループのカウンター変数iの設定を
For i= 1 to 31
にして、
Cells(r, c).Value = i
にしてから実行すると、仕組みが分かりやすいでしょう。



なお、このMakeCalendar1 を使ってカレンダーを作成するには、ボタンにこのプロシージャを登録してください。


ちなみに、今日から50年後の2061年7月のカレンダーを作成してみました。
なんと!今年と同じ曜日でした!!





だい
コメント (2)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

あれ!?ウィンドウがない!ExcelVBA編

2011-07-07 09:01:20 | ExcelVBA
エクセルを起動して、あるファイルを開いたら、あれれ?シートが1枚も表示されない?
なんて、経験はありませんか?

ないほうがいいですよね。驚いてしまいます。





確かにファイルを開いているのに、そのファイルが表示されない場合は、
ウィンドウの非表示という機能が働いているのです。


さて、この機能をExcelVBAで実現する方法を取り上げます。

エクセルを起動して、任意のファイルを開きます。(新規ファイルでもかまいません)
Altキーを押しながら、F11キーを押すと、VisualBasicEditorが起動します。

「挿入」→「標準モジュール」とクリックします。

次のようにコードを記述してください。



2つのプロシージャを書きました。
ウィンドウを非表示にするプロシージャと、再表示するプロシージャです。

非表示のコードはシンプルですね。
再表示する際は、ブック名を指定する必要があります。

それでは、エクセルに切り替えて、マクロを実行します。




実行すると、確かにウィンドウが非表示になります。





このままでは、事件なので、再表示しましょう。再表示のプロシージャを実行してください。





はい、ちゃんとウィンドウが表示されました。





ちなみに、手作業で行うには、以下のようにします。え?この方が楽じゃん?
そんなこと言わないで~





だい
コメント (2)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

ExcelVBAで電卓を作ろう-その3 「コードを書こう」

2011-06-09 09:01:10 | ExcelVBA
今日は、「ExcelVBAで電卓を作ろう」の3回目です。

バックナンバーは、以下の通りです。

第1回「複数のコントロールのイベントを一つのプロシージャにまとめる(ExcelVBA)
第2回「ExcelVBAで電卓を作ろう-その2「アルゴリズムを考える」

さて、前回のアルゴリズムを踏まえて、今回は、実際にコードを書いてみましょう。

まず、電卓の確認です。



問題をシンプルにするために、0~9の数字と、加減乗除のボタン、=ボタン、それにAC(オールクリア)ボタンのみの
構成にします。


それでは、コーディングしましょう。

第1回の際に、数字のボタンを押すと、数字が表示されるコードを書きましたね。

そうです。Classモジュールに記述しましたね。まず、これを少し、修正しましょう。

実は、このままでは、常に1桁の数字しか表示できないのです。

2ケタ以上表示できるように、以下の様に修正します。


Option Explicit

'イベントを持つコマンドボタン型の変数を宣言
Private WithEvents Btn As MSForms.CommandButton
'ボタンの数字を格納する変数を宣言
Private Index As Integer

Public Sub NewClass(ByVal c As MSForms.CommandButton, _
          ByVal i As Integer)
  'いわゆるコンストラクタ処理

  '引数のコマンドボタンを変数に格納
  Set Btn = c
  'コマンドボタンの数字を変数に格納
  Index = i
End Sub

Private Sub Btn_Click()
  '数字のボタン(0~9)を押した時の処理

  'frmCalcフォームのTextBox1に、
  '変数Indexの中身を表示する

  If IsNew Then
    '数字の新規入力時
    frmCalc.TextBox1.Text = Index
  Else
    '数字の入力途中
    frmCalc.TextBox1.Text = _
        CLng(frmCalc.TextBox1.Text & Index)
  End If

  '数字の入力途中にする
  IsNew = False
End Sub


画像も載せておきます。




変更箇所は、Private Sub Btn_Click() のコードだけです。

IsNew という変数が登場しました。
この変数は、True と False の2種類の値をとることができるブーリアン(Boolean)型の変数です。
この変数にTrueが格納されている場合は、新規入力とします。
つまり、今までの数字は、無視して、最初に入力される数字ということです。
加減乗除のボタンと、=ボタン、ACボタンが押された直後に、Trueが格納されます。

数字の入力直後で、IsNew に Falseを格納します。
これで、2桁以上の数字の表示が可能となります。


なお、このIsNew という変数は、ユーザーフォームからもこのClassモジュールからも使用します。
従って、どのモジュールからも使用できるように、標準モジュールに宣言を記述します。

「挿入」→「標準モジュール」とクリックします。

以下のように記述します。


Option Explicit

Public IsNew As Boolean

Public Sub ShowCalc()
  frmCalc.Show
End Sub

画像はこちら。




変数の宣言の他に、フォームを起動するプロシージャ「ShowCalc」も書いておきました。



それでは、いよいよ、フォームにコードを書いていきます。

ユーザーフォームのコードウィンドウを表示します。

冒頭に変数の宣言と列挙型の宣言、そして、フォームの初期化イベントのコードを書きます。


Option Explicit

Private NumBtn(0 To 9) As New Class1
Private stack(0 To 1) As Currency
Private Action As Integer

Private Enum Act
  Equal
  Plus
  Minus
  Multi
  Devi
End Enum

Private Sub UserForm_Initialize()

  'インスタンスの生成
  Dim i As Integer
  For i = 0 To 9
    NumBtn(i).NewClass Controls("b" & i), i
  Next

  '表示設定
  TextBox1.Text = 0

  '初期化処理
  InitCalc

End Sub



UserForm_Initialize プロシージャの中の InitCalc は、サブプロシージャです。

別途、以下の様に書いておきます。


Private Sub InitCalc()
  '初期化処理

  'スタックと記号の初期化
  stack(0) = 0
  stack(1) = 0
  Action = Act.Plus

  '表示クリアフラグの初期化
  IsNew = True

End Sub

つまり、計算用の配列の値を0にして、記号を格納するAction変数にプラスを意味する数字を代入します。
(ここで、単なる数字の代わりに列挙型を使用しています)

さらに、IsNew 変数にTrueを代入して、新規入力を促しています。


以上、参考までに画像です。





さて、それでは、ここで、記号ボタンを押したときの処理を書いてみましょう。

この処理は、加減乗除の4つのボタンと、=ボタンを押したときに、いつでも呼び出されるプロシージャとして記述します。
何度も同じコードを書く必要がなくなりますね。

以下のように書きます。

Private Sub Calc(ByVal CurrentAction As Integer)
  '計算処理(記号ボタンが押されると呼び出される)

  '電卓窓の数字を変数に格納
  Dim n As Long
  n = CLng(TextBox1.Text)
  stack(1) = n

  '計算結果を格納する変数
  Dim Ans As Double

  Select Case Action
    Case Act.Equal
      '=
      Action = Act.Equal
    Case Act.Plus
      '+
      Ans = stack(0) + stack(1)
      stack(0) = Ans
      stack(1) = 0
      TextBox1.Text = Ans
    Case Act.Minus
      '-
      Ans = stack(0) - stack(1)
      stack(0) = Ans
      stack(1) = 0
      TextBox1.Text = Ans
    Case Act.Multi
      '*
      Ans = stack(0) * stack(1)
      stack(0) = Ans
      stack(1) = 0
      TextBox1.Text = Ans
    Case Act.Devi
      '/
      If stack(1) = 0 Then
        Ans = 0
      Else
        Ans = stack(0) / stack(1)
      End If
      stack(0) = Ans
      stack(1) = 0
      TextBox1.Text = Ans
  End Select

  '引数で受け取った記号を格納
  Action = CurrentAction
  '新規入力にする
  IsNew = True

End Sub

画像はこちら。





前回の記事をご覧いただければ、今回のコードの意味もお分かりいただけるでしょう。
このプロシージャは、引数を1つ持っています。
どの記号が押されたのかを引数に指定するのです。
この記号を、Action変数に格納するためです。



さあ、あとは、記号のボタンのコードだけです。

記号のボタンのイベントプロシージャを以下のように記述してみましょう。



Private Sub Plus_Click()
  '足し算

  'サブプロシージャの呼び出し
  Calc Act.Plus

End Sub


Private Sub Minus_Click()
  '引き算

  'サブプロシージャの呼び出し
  Calc Act.Minus

End Sub


Private Sub Multi_Click()
  '掛け算

  'サブプロシージャの呼び出し
  Calc Act.Multi

End Sub

Private Sub Dev_Click()
  '割り算

  'サブプロシージャの呼び出し
  Calc Act.Devi

End Sub

Private Sub btnEnter_Click()
  '=の処理

  'サブプロシージャの呼び出し
  Calc Act.Equal

End Sub



画像も載せておきましょう。






いずれも、サブプロシージャを呼んでいるだけです。
その際、引数にその記号を指定していることに注意してください。



最後に、ACボタンのコードを書いておきましょう。


Private Sub btnAC_Click()
  'ACボタンの処理

  TextBox1.Text = 0

  '初期化処理
  InitCalc

End Sub


まさに、オールクリアですね。



それでは、実行してみてください。
いかがですか? 実際の電卓と同様の動作をするでしょう。

色々と試してみてください。
なかには、不思議な処理をする時があるかもしれません。
その理由を考えてみてください。
修正してみるのも勉強になります。


エクセルのバージョンは、2002(XP)以上でお願いします。


だい
コメント (2)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

【おすすめ】

パソコン買ったらまず入れる10のアプリ