VB hidden button on form - vb.net

I am using VB to search some data from a text file and then populate in excel. It's working. The problem is xl.visible=true makes the excel sheet to be visible at once & then the values keep on populating. I want to hide the excel till data population is complete. then make a button appear on the form which when clicked, will display the excel file.
Please help. Here is the code I'm using:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
' create an excel instance
Dim xl = Microsoft.VisualBasic.CreateObject("Excel.Application")
xl.Visible = False
Dim wb = xl.Workbooks.Add()
Dim sheet = wb.ActiveSheet
' find lines starting with any whitepace followed by MTV or MTB and capture
' the text after =
Dim pattern = "(?<=\s*(MTV).*=).*"
Dim i = 1
Dim arg = {Microsoft.VisualBasic.ControlChars.CrLf, Microsoft.VisualBasic.ControlChars.Lf}
If RichTextBox3.Text = "" Then
MsgBox("No input. What will I process??")
Else
Timer1.Start()
For Each line In File.ReadLines(RichTextBox3.Text)
Dim match = Regex.Match(line, pattern)
' check each line and fill sheet
If match.Success Then
sheet.Cells(i, 1).Value = match.Value
i += 1
End If
Next
End If
xl.Visible = True
End Sub

Use Button2 to do the Excel work but remove the line: xl.Visible = True
Put a button on your form called Button3 (or named whatever); set Button3 property Visible = False. Then at the bottom of Button2 click event put Button3.Visible = True
After your Button2 gets clicked you'll have Button3 visible. In Button3 click event put xl.Visible = True
To make this work, you'll need to declare "xl" as a module or class variable. Just put Dim xl as object above your sub and remove the Dim inside your sub; that will do it.

Simple type button1.Hide() when you click on the button or something else it will then hide the button. Hope this helps you out.
Remember, button1.Hide() refers to the first button - if it is the 2nd button it would be button2.hide(), etc.

Related

How to paste clipboard value into a specific ComboBox on a UserForm?

I copy a name in the first column of the active row on a spreadsheet to the clipboard.
I launch a UserForm by the name CommandsUserForm.
The UserForm is overlaid with multiple pages or tabs, so it defaults to the first tab (this is desired).
On this tab, there is a ComboBox by the name DPComboBox.
I want to paste the value in the clipboard into the ComboBox after the userform is launched.
Userform with the ComboBox highlighted.
Sub Show_Quick_Commands()
DPName = ThisWorkbook.ActiveSheet.Cells(ActiveCell.Row, 1).Value
Set DPNameforQ = New DataObject
DPNameforQ.SetText DPName
DPNameforQ.PutInClipboard
CommandsUserForm.Show vbModeless
End Sub
I tried DPComboBox.PasteSpecial Transpose:=True, but that breaks the code and requests a debug.
For example:
Sub Show_Quick_Commands()
Dim frm As CommandsUserForm
Set frm = New CommandsUserForm
frm.DPName = ActiveCell.EntireRow.Cells(1).Value 'set before showing the form
frm.Show vbModeless
End Sub
Userform:
Option Explicit
Private m_DPName As String
Private Sub UserForm_Activate()
Dim i As Long, v
'put some dummy data in the combobox
For i = 1 To 10
Me.DPComboBox.AddItem "ClientPartner_" & Format(i, "000")
Next i
Me.DPComboBox.Text = m_DPName 'set the value
End Sub
'call this before showing the form
Property Let DPName(nm As String)
m_DPName = nm
End Property

When I double click on a cell to open a form, a checkbox on the form behind my cursor is checked/unchecked. How can I prevent this from happening?

I have a form that appears on a double click event of a specific cell.
The form contains a list box with a bunch of checkboxes in it and in my _Activate() sub, the checkboxes are set to true or false based on values on the active sheet.
The trouble is that when the form opens up behind the cursor, the second click of the double click that opens the form is also checking/unchecking a checkbox in the form.
I've tried sticking "DoEvents" in the activate sub before the code sets the checkbox values but it hasn't made a difference - The checkbox behind my cursor where the form opens will be checked/unchecked.
I don't expect that the code will help much but it is essentially as below:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
If Target = Range("aParticularRangeName") Then
frmSelectStuff.Show
End If
End Sub
Public Sub UserForm_Activate()
Dim iRegions As Integer
Dim sRecheck As Variant
Dim sRecheckList() As String
sRecheckList = Split(ActiveCell.Value, "; ")
For Each sRecheck In sRecheckList
For iRegions = 0 To lbRegionsTemp.ListCount - 1
If sRecheck = lbRegionsTemp.List(iRegions) Then lbRegionsTemp.Selected(iRegions) = True
Next
Next
End Sub
What about using Cancel = True?
If Target = Range("aParticularRangeName") Then
Cancel = True
frmSelectStuff.Show
End If

How make VBA run on clicking any checkbox in a userform?

I have a userform with a multiple frames, all filled with multiple checkboxes. I've named the checkboxes to their corresponding Excel cells. Now I want to make VBA run on clicking any of these checkboxes on run time. I know I can do this by creating a click-sub for every individual checkbox, but there must be a cleaner way to do this.
So far I've tried to put this code in the userform_Click and userform_Mousedown events, but they don't run when I click the checkboxes. Does anyone have an idea how to do this?
Dim iControl As Control
For Each iControl In Me.Controls
If TypeName(iControl) = "CheckBox" Then
If iControl.Value = True And Range(iControl.Name).Value = "" Then
Range(iControl.Name).Value = Format(Now, "dd.mm.yyyy")
ElseIf iControl.Value = True And Range(iControl.Name).Font.Color = vbWhite Then
Range(iControl.Name).Font.Color = vbBlack
ElseIf iControl.Value = False And Range(iControl.Name).Value <> "" Then
Range(iControl.Name).Font.Color = vbWhite
End If
End If
Next
As SilentRevolution said - you need an event to fire when you click the button. You're just after a single procedure to fire all check box click events.
So:
Create a class module called cls_ChkBox.
In the class module you'll add the Click event code:
Option Explicit
Private WithEvents chkBox As MSForms.CheckBox
Public Sub AssignClicks(ctrl As Control)
Set chkBox = ctrl
End Sub
Private Sub chkBox_Click()
ThisWorkbook.Worksheets("Sheet1").Range(chkBox.Name).Value = Format(Now, "dd.mm.yyyy")
End Sub
Now you just need to attach the chkBox_Click event to each check box on your form. In your user form add this code:
Option Explicit
Private colTickBoxes As Collection
Private Sub UserForm_Initialize()
Dim ChkBoxes As cls_ChkBox
Dim ctrl As Control
Set colTickBoxes = New Collection
For Each ctrl In Me.Controls
If TypeName(ctrl) = "CheckBox" Then
Set ChkBoxes = New cls_ChkBox
ChkBoxes.AssignClicks ctrl
colTickBoxes.Add ChkBoxes
End If
Next ctrl
End Sub
Each check box is given its own instance of the class, which is stored in the colTickBoxes collection.
Open the form and the cell in Sheet1 will update to show the date depending on the name of the check box.
You need an event to run code, if there is no event, the macro cannot start. I don't know if there is a single event that triggers for any button or checkbox that is clicked.
If the code you want to execute is the same every time except the control, you could write a private sub in the userform module which is called for each event, the private sub can take an input between the () for example.
Private Sub CheckBox1_Click()
Call ExecuteCode(Me.CheckBox1)
End Sub
Private Sub CheckBox2_Click()
Call ExecuteCode(Me.CheckBox2)
End Sub
Private Sub CheckBox3_Click()
Call ExecuteCode(Me.CheckBox2)
End Sub
Private Sub ExecuteCode(IControl As Control)
If TypeName(IControl) = "CheckBox" Then
If IControl.Value = True And Range(IControl.Name).Value = "" Then
Range(IControl.Name).Value = Format(Now, "dd.mm.yyyy")
ElseIf IControl.Value = True And Range(IControl.Name).Font.Color = vbWhite Then
Range(IControl.Name).Font.Color = vbBlack
ElseIf IControl.Value = False And Range(IControl.Name).Value <> "" Then
Range(IControl.Name).Font.Color = vbWhite
End If
End If
End Sub
I just learned this today and thought it might help? Most of the questions, and responses for that matter, to questions regarding checkboxes, listboxes, etc. seem to not distinguish between those forms are inserted directly on the worksheet or are imbedded in a UserForm.
This may work for a checkbox - it works for a ListBox on a UserForm. If you want code to run after a selection, the code you must write has to be in module of the UserForm. I had no clue how to access. Once you have inserted a UserForm in your VBE, add the ListBoxes or whatever to the UserForm. Right click on the UserForm in the upper left project window and select "view code." Here is where you'll place the code, in my case a "change event" such that after a selection is made from the ListBox, other code is automatically run. Her for example:
Sub lstBoxDates_Change()
Dim inputString1 As String
inputString1 = Format(UserForm1.lstBoxDates.Value, "mm-dd-yyyy")
Call EnterDates(inputString1)
Unload Me
End Sub
To explain: Again this code is in the UserForm Module. I named my ListBox,
lstBoxDates. In my main code that I call - EnterDates, I use the variable name = inputString1. The value or date that I have selected from the ListBox is captured from the UserForm1 by UserForm1.lstBoxDates.Value - and I format that to a date, otherwise you see just a number. This is for only one selection.
Because I Dim here, no need to Dim in your main code. The sub for the main code
needs to accept the variable you are passing to it:
Sub EnterDates(inputString1)
This is very generalized but maybe something will click so you can get what you are after. I hope so, for I've worked on this a full two days!!

VB.net/Excel- "Backwards" tab index For Each iteration with textboxes

I have a form with 3 textboxes and 1 button.
textbox1 has tab index 0, and it's text = 1
textbox2 has tab index 1, and it's text = 2
textbox3 has tab index 2, and it's text = 3
I want to iterate thru the textboxes and place their values into cells so that...
range("A1").value = txtbox1.text (ie: A1 = "1")
range("A2").value = txtbox2.text (ie: A2 = "2")
range("A3").value = txtbox3.text (ie: A3 = "3")
but what I am getting is...
range("A1").value = txtbox1.text (ie: A1 = "3")
range("A2").value = txtbox2.text (ie: A2 = "2")
range("A3").value = txtbox3.text (ie: A3 = "1")
I have tried reversing the tab index for the text boxes, but it doesn't change the "backwards iteration".
Is there something I can do to change this so that the loop runs from lowest tab index to highest?
Thanks!
Public Class Form1
Private Sub Button1_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim objExcel As New Microsoft.Office.Interop.Excel.Application 'Declaring the object.
objExcel.Visible = True 'Setting Excel to visible.
Dim cntrl As Control
With objExcel
.Workbooks.Add() 'Adding a workbook.
.Range("A1").Select() 'Selecting cell A1.
End With
'Form contains 3 text boxes, with one number in each (1,2,3), and one button to fire the code in this sub.
For Each cntrl In Me.Controls 'For every control on the form...
If TypeOf (cntrl) Is TextBox Then 'If the control is a textbox, then...
With objExcel
.ActiveCell.Value = cntrl.Text 'place the control's text in the active cell and...
.ActiveCell.Offset(1, 0).Activate() 'offset down one row.
End With
End If 'If the control is not a textbox (if it's the button), do nothing.
Next 'Go to the next control.
objExcel = Nothing 'Release the object.
GC.Collect() 'Clean up.
End Sub
End Class
Sounds like it may be the way Excel is iterating over the controls. Have you tried this to see what the output is?
Dim objExcel As New Microsoft.Office.Interop.Excel.Application 'Declaring the object.
objExcel.Visible = True 'Setting Excel to visible.
Dim cntrl As Control
With objExcel
.Workbooks.Add() 'Adding a workbook.
.Range("A3").Select() 'Selecting cell A3.
End With
'Form contains 3 text boxes, with one number in each (1,2,3), and one button to fire the code in this sub.
For Each cntrl In Me.Controls 'For every control on the form...
If TypeOf (cntrl) Is TextBox Then 'If the control is a textbox, then...
With objExcel
.ActiveCell.Value = cntrl.Text 'place the control's text in the active cell and...
.ActiveCell.Offset(-1, 0).Activate() 'offset up one row.
End With
End If 'If the control is not a textbox (if it's the button), do nothing.
Next 'Go to the next control.
objExcel = Nothing 'Release the object.
GC.Collect() 'Clean up.
Using a For Each loop implies that you don't care what order you are doing them in.
What I would do is use the "tag" property of the control to hold the row number you'd like the answer in:
For Each cntrl In Me.Controls
If TypeOf (cntrl) Is TextBox Then
objExcel.ActiveSheet.Cells(cntrl.Tag, 1).Value = cntrl.Text
End If
Next
You could also add a hidden panel on the form that contains only your key textboxes, then use a traditional FOR loop instead of a 'For Each':
Dim i as integer
Dim myBox as textBox
For i = 1 to 3
set myBox = Me.Panel1.Controls(i)
objExcel.ActiveSheet.Cells(myBox.Tag, 1).Value = myBox.Text
Next i
It should go through in Tab order. You can even skip the typecheck, because you already know what it is.

Determine which button was pressed?

I'm wondering if there's a simple way for a Word macro to determine which button was just pressed? I have a document template with several button which should all fire a macro.
The thing is, I want to create ONE macro which is called in each button. I don't want tons of macros for each button.
Now, this macro, when the button is pressed, it inserts a picture and the size of this picture is selected based on the buttons size. Meaning, this ends up as a picture placeholder. But, I want to write the macro dynamically so that the same code will work on each button without doing more than just calling the macro.
The complete macro is already done, I just need to know this one last thing, if anyone has any info on how to accomplish this? :) Thanx in advance!
UPDATE: This is the code at the moment
Private Sub ImageButton1_Click()
PicturePlaceholder ImageButton1
End Sub
Private Sub ImageButton2_Click()
PicturePlaceholder ImageButton2
End Sub
Public Sub PicturePlaceholder(ByVal oButton As CommandButton)
Dim oShape As Word.Shape
Dim Dlg As Office.FileDialog
Dim strFilePath As String
Dim oDoc As Document
Dim rgePlace As Range
Dim buttonHeight As String
Dim buttonWidth As String
Set Dlg = Application.FileDialog(msoFileDialogFilePicker)
Set oDoc = ActiveDocument
Set rgePlace = Selection.Range.Fields(1) _
.Result.Paragraphs(1).Range
Response = MsgBox("Do you want to delete the button/Picture?", vbYesNoCancel, "Do you want an image here?")
If Response = vbYes Then rgePlace.Fields(1).Delete
If Response = vbCancel Then Exit Sub
If Response = vbNo Then
With Dlg
.AllowMultiSelect = False
If .Show() <> 0 Then
strFilePath = .SelectedItems(1)
End If
End With
If strFilePath = "" Then Exit Sub
Set oShape = oDoc.Shapes.AddPicture(FileName:=strFilePath, _
LinkToFile:=False, SaveWithDocument:=True, _
Anchor:=rgePlace)
With oShape
.Height = oButton.Height
.Width = oButton.Width
End With
rgePlace.Fields(1).Delete
End If
End Sub
OK, so they're CommandButtons in the document.
In that case, there's nothing you can do - you need to have handlers called Button1_Click, Button2_Click, etc. (or whatever the button names are).
However, you can do something like this:
Private Sub Button1_Click(...)
DoStuff Button1
End Sub
Private Sub Button2_Click(...)
DoStuff Button2
End Sub
Private Sub DoStuff(ByVal oButton As CommandButton)
' All your shared code goes here
MsgBox oButton.Caption
End Sub
See also this tech note for how to create your buttons in code.
EDIT: updated to pass CommandButton reference so that the shared function can access the button properties.
EDIT 2: updated to show complete code using InlineShapes. Note that this no longer passes in the Button object, since the width/height of the button can be obtained directly from the field.
Private Sub CommandButton1_Click()
PicturePlaceholder
End Sub
Private Sub CommandButton2_Click()
PicturePlaceholder
End Sub
Public Sub PicturePlaceholder()
' Get the selected field, which must be a button field
Dim oField As Field
Set oField = Selection.Fields(1)
Debug.Assert oField.Type = wdFieldOCX
' Ask the user what he wants to do
Select Case MsgBox("Do you want to delete the button/Picture?", vbYesNoCancel, "Do you want an image here?")
Case vbCancel
Exit Sub
Case vbYes
oField.Delete
Exit Sub
End Select
' Get the filename of the picture to be inserted
Dim strFilePath As String
With Application.FileDialog(msoFileDialogFilePicker)
.AllowMultiSelect = False
If .Show() <> 0 Then
strFilePath = .SelectedItems(1)
End If
End With
If strFilePath = "" Then
Exit Sub
End If
' Figure out where to insert the picture, and what size to make it
Dim oRange As Range
Set oRange = oField.Result
Dim sglWidth As Single
sglWidth = oField.InlineShape.Width ' oButton.Width
Dim sglHeight As Single
sglHeight = oField.InlineShape.Height ' oButton.Height
' Delete the button field
oField.Delete
' Insert and resize the picture
Dim oInlineShape As Word.InlineShape
Set oInlineShape = oRange.InlineShapes.AddPicture(FileName:=strFilePath, LinkToFile:=False, SaveWithDocument:=True, Range:=oRange)
With oInlineShape
.Width = sglWidth
.Height = sglHeight
End With
End Sub
EDIT 3: Updated as requested to use Shapes rather than InlineShapes. (Both the CommandButton and the inserted Picture are now Shapes).
Private Sub CommandButton1_Click()
PicturePlaceholder
End Sub
Private Sub CommandButton2_Click()
PicturePlaceholder
End Sub
Public Sub PicturePlaceholder()
' Get the selected shape, which must be a button shape
Debug.Assert Selection.Type = wdSelectionShape
Dim oButtonShape As Shape
Set oButtonShape = Selection.ShapeRange(1)
' Ask the user what he wants to do
Select Case MsgBox("Do you want to delete the button/Picture?", vbYesNoCancel, "Do you want an image here?")
Case vbCancel
Exit Sub
Case vbYes
oButtonShape.Delete
Exit Sub
End Select
' Get the filename of the picture to be inserted
Dim strFilePath As String
With Application.FileDialog(msoFileDialogFilePicker)
.AllowMultiSelect = False
If .Show() <> 0 Then
strFilePath = .SelectedItems(1)
End If
End With
If strFilePath = "" Then
Exit Sub
End If
' Insert the picture at the same size/position
Dim oPictureShape As Shape
Set oPictureShape = ActiveDocument.Shapes.AddPicture _
( _
FileName:=strFilePath, _
LinkToFile:=False, _
SaveWithDocument:=True, _
Left:=oButtonShape.Left, _
Top:=oButtonShape.Top, _
Width:=oButtonShape.Width, _
Height:=oButtonShape.Height, _
Anchor:=oButtonShape.Anchor _
)
' Copy across the button shape formatting
oButtonShape.PickUp
oPictureShape.Apply
' Copy across other layout details
oPictureShape.LayoutInCell = oButtonShape.LayoutInCell
oPictureShape.LockAnchor = oButtonShape.LockAnchor
oPictureShape.RelativeHorizontalPosition = oButtonShape.RelativeHorizontalPosition
oPictureShape.RelativeVerticalPosition = oButtonShape.RelativeVerticalPosition
oPictureShape.WrapFormat.Type = oButtonShape.WrapFormat.Type
oPictureShape.WrapFormat.Side = oButtonShape.WrapFormat.Side
oPictureShape.WrapFormat.DistanceTop = oButtonShape.WrapFormat.DistanceTop
oPictureShape.WrapFormat.DistanceLeft = oButtonShape.WrapFormat.DistanceLeft
oPictureShape.WrapFormat.DistanceBottom = oButtonShape.WrapFormat.DistanceBottom
oPictureShape.WrapFormat.DistanceRight = oButtonShape.WrapFormat.DistanceRight
oPictureShape.WrapFormat.AllowOverlap = oButtonShape.WrapFormat.AllowOverlap
' Delete the button shape
oButtonShape.Delete
End Sub
I assume you mean that the button is a Command Bar button (aka toolbar button).
If so, you can use Application.CommandBars.ActionControl to get a reference to the button that was clicked. From there you can examine the caption, tag, or whatever.
You could put your base macro into a separate sub and then just call the macro from each button's click event, passing as a parameter the desired size. Then the only code you would have in the buttons is the call to the base sub.
You can have a button in Vba to pass arguments when it calls the macro which takes arguments.
For eg: if you have a function called as function test(x as string)
then the button which calls the macro will have a syntax as onclick("sheetx!test", "whatever"). So that way you can either have a generic macro to be called. Hope this helps you.
Placing the following in the various click/got_focus/change events of ActiveX buttons and textboxes works for me:
MsgBox ThisDocument.ActiveWindow.Selection.Fields.Item(1).OLEFormat.Object.Name