2017-05-11 23 views
0

Pythonから来て、Excel VBAではeval()などの関数が存在しないため、最終目標を達成する方法を見つけられません。ユーザー入力に基づいて変数を評価する

以下

は私が拡張できることを、簡単な例を用いて実現しようとしているものです:

Dim userinput as String 
userinput = inputbox("A=John, B=Kate, C=Tim", "Enter a letter that corresponds with your name: ") 
Dim A as String 
Dim B as String 
Dim C as String 

A = John 
B = Kate 
C = Tim 

Dim Phrase as Variant 
phrase = msgbox("Hello, my name is " & userinput) 

Result: 
User enters a C 
msg box pops up as "Hello, my name is Tim" 

かかわらず、私がやろうものの、私は、ユーザ入力を持つことができませんその後、解釈される変数に対応ストリングの中で。私のマクロは、ユーザーの入力が、ユーザーが自分で入力するのが難しいはるかに長くて複雑なフレーズを参照することなく無用になります。

答えて

4

あなたは有限の、事前決定を提示していますユーザーにオプションのセットを提供します。

しかし、あなたは全く文字通り何かを入力させ、それとロールしてもらうようにします。

A、ユーザの入力はオプションの有限、所定のセットにを制約されているように、はるかに良い選択肢は、InputBoxアプローチを捨て実UserFormをユーザに提示するだろう - ComboBox制御が頭に浮かぶ:ユーザーフォームのコードビハインド

some UserForm with instructions, ok, cancel buttons and a combobox control

は非常に簡単です - ボタンがクリックされたときにフォームを隠す、キャンセルと「X-アウトを」治療、ユーザーのSelectionを公開し、フォームをProperty Get経由でキャンセルされたかどうかメンバー選択することが可能な値とドロップダウンを移入:

Option Explicit 
Private isCancelled As Boolean 

Public Property Get Cancelled() As Boolean 
    Cancelled = isCancelled 
End Property 

Public Property Get Selection() As String 
    Selection = ComboBox1.Value 
End Property 

Private Sub CancelButton_Click() 
    isCancelled = True 
    Hide 
End Sub 

Private Sub OkButton_Click() 
    Hide 
End Sub 

Private Sub UserForm_Activate() 
    With ComboBox1 
     .Clear 
     .AddItem "Lorem" 
     .AddItem "Ipsum" 
     '... 
    End With 
End Sub 

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) 
    If CloseMode = vbFormControlMenu Then 
     Cancel = True 
     isCancelled = True 
     Hide 
    End If 
End Sub 

そして今、あなたはこれを行うことができます:あなたのComboBoxコントロールのStyleプロパティがある場合

Public Sub Test() 
    With New UserForm1 
     .Show 
     If Not .Cancelled Then 
      MsgBox .Selection 
     End If 
    End With 
End Sub 

これは、プロンプトの相殺ユーザーを処理し、 fmStyleDropDownListに設定すると、ユーザーが期待していない価値を提供する方法はまったくありません。また、Property Getとのメンバーを提供して、必要に応じてTitleInstructionsのラベルを設定するか、ComboBoxを取り込むための有効な値のリストを提供するコードを呼び出してください。

これはです。の部分です。次の部分は、入力を別の文字列値で「マッピング」します。このための最良のデータ構造はDictionaryですが、キーCollectionは、同じようにうまく機能することができます両方のコンボボックスの値のために、あなたがここに必要なデータを移入する多くの方法がある。もちろん、

Dim values As Collection 
Set values = New Collection 
values.Add "string 1", "Lorem" 
values.Add "string 2", "Ipsum" 
'... 

With New UserForm1 
    .Show 
    If Not .Cancelled Then 
     MsgBox values(.Selection) 
    End If 
End With 

をし、コレクション内のマップされた文字列。このようにハードコードしたり、ワークシート上のRangeから取得したり、ボートを揺るがすものであればデータベースから取得することができます。

+0

フレームのキャプションに誤字が入ります。しかたがない。 –

+0

フォームにはどのような言語がありますか?間違いなく正しいアプローチbtw。 –

+1

@ASH [* Lorem Ipsum *は、紀元前45年に書かれたCiceroによる "De Finibus Bonorum et Malorum"(善と悪の極端な)のセクション1.10.32と1.10.33から来ます。 lipsum.com/);-) –

2

ユーザーが手紙を入力しています。より明示的に名前に変換するコードが必要です。多くの方法があります。長いリストやユーザーが入力したリストがある場合、よりダイナミックなソリューションが必要な場合があります。ただし、コードの修正は次のとおりです。

Dim userinput as String 
userinput = inputbox("A=John, B=Kate, C=Tim", "Enter a letter that corresponds with your name: ") 
Dim A as String 
Dim B as String 
Dim C as String 
Dim nameOut as String 

select case userinput 
    case "A" 
     nameOut = "John" 
    case "B" 
     nameOut = "Kate" 
    case "C" 
     nameOut = "Tim" 
end select 

Dim Phrase as Variant 
phrase = MsgBox("Hello, my name is " & nameOut) 

注:文字列を二重引用符で囲むことを忘れないでください。

+0

これは素晴らしい解決策です。私のコードが絶対的な検証を必要としないなら、私は絶対に念頭に置いておきます! –

1

投稿されたのは別のアプローチだからです。入力された文字の位置を3つすべての配列で検索し、名前の配列内の対応する項目を検索します。

Sub x() 

Dim userinput As String 
Dim Phrase As String 
Dim v 

userinput = InputBox("A=John, B=Kate, C=Tim", "Enter a letter that corresponds with your name: ") 
v = Array("John", "Kate", "Tim") 

With Application 
    If IsNumeric(.Match(userinput, Array("A", "B", "C"), 0)) Then 
     Phrase = .Index(v, .Match(userinput, Array("A", "B", "C"), 0)) 
     MsgBox "Hello, my name is " & Phrase 
    Else 
     MsgBox "Wrong letter" 
    End If 
End With 

End Sub 
+0

このアプローチは、Excelの範囲から動的リストを取得する方が簡単に適応でき、そのルートに移動する場合は強く考慮する必要があります。 – Scott

1

スコットの答えから奪うことなく、潜在的に、より動的なアプローチのためにclass modulescallbynameが答えてい思えるまでもありません:

クラスモジュール - class1に

Private pa As String 
Public Property Get a() As String 
a = pa 
End Property 
Public Property Let a(value As String) 
pa = value 
End Property 

テストサブ

Sub testing() 
Dim cls1 As Class1 
    Set cls1 = New Class1 

cls1.a = "tim" 

userinput = "a" 

Debug.Print CallByName(cls1, userinput, VbGet) 

End Sub 
関連する問題