Changing the colour of tabs of Multipage in VBA - excel

I'm using the Forms in VBA and I was wondering if it is possible to make the tabs in my Multipages change colour when active, so that there is a better contrast with the other tabs. Here is a screenshot
Is there a way to contrast the active tab from the inactive tabs so that the user can know which tab he is using?
Or do you have any idea so that the active tab can appear better against the inactive tabs?

Approach by marking page captions by a checkmark
"Or do you have any idea so that the active tab can appear better against the inactive tabs?" -
A possible & helpful approach would be to
mark each clicked page caption by a checkmark (e.g. ChrW(&H2611)) and to
automatically de-mark a prior page caption: the code "remembers" the current/old page index via the multipage's .Tag property set at any multipage ..._Change() event (.Tag gets initialized via UserForm_Initialize() firstly).
As Captions may include normal blanks, I chose to add a protected blank (ChrW(&HA0)) to the checkmark character to allow a simple Replace() maintaining the blanks in the original page caption.
Example code in Userform
Private Sub MultiPage1_Change()
'Purpose: mark current page caption by a checkmark
With Me.MultiPage1
Dim pg As MSForms.Page
'a) de-mark old caption
Set pg = oldPage(Me.MultiPage1)
pg.Caption = Replace(pg.Caption, ChkMark, vbNullString)
'b) mark new caption & remember latest multipage value
Set pg = .Pages(.Value)
pg.Caption = ChkMark & pg.Caption
.Tag = .Value ' << remember latest page index
End With
End Sub
Help functions & UserForm_Initialize() routine
Function oldPage(mp As MSForms.MultiPage) As MSForms.Page
'Purpose: return currently marked page in given multipage
With mp
Set oldPage = .Pages(Val(.Tag))
End With
End Function
Function ChkMark() As String
'Purpose: return ballot box with check + blank space
ChkMark = ChrW(&H2611) & ChrW(&HA0) ' ballot box with check + blank
End Function
Private Sub UserForm_Initialize()
'Purpose: mark start page & remember page index
Const startIndx As Long = 0
With Me.MultiPage1
.Pages(startIndx).Caption = ChkMark & .Pages(startIndx).Caption
.Tag = startIndx
End With
End Sub

One method I've used is to rename the tab when activated, and include more space before and after the page name, so that the tab widens when selected for visibility, or surround with <> etc. chars: <<< TAB_NAME >>>.
But lately I've considered using separate buttons to activate a page, and change the color. This saves some screenspace as the multipage itself is shorter, buttons can still look like multipage buttons being on the top left of the multipage, but then all the space to the right is free for other controls.
Actually I use labels setup as command buttonds, generally smaller/less tall.

Related

Show textbox scrolled to the top without highlighted text on UserForm.Show

I know how to show a textbox scrolled to the top on a UserForm.Show event, however that involves the method SetFocus and if I set the focus, it automatically highlights the text which I do not want. I'm using a userform to show a message because my messages are too long for a MsgBox. Is there a way to prevent it from auto-selecting the text while still having the box scrolled to the top upon .Show? This scrolls to the top but still selects the text despite 0 values:
Messages.MessageBox.SetFocus
Messages.MessageBox.SelStart = 0
Messages.MessageBox.SelLength = 0
Messages.MessageBox.TabStop = False is so close to working, but the fact that you can scroll isn't obvious (scroll bars only appear when you click in the textbox) and when you click in the textbox it auto scrolls to the bottom again.
If there is no way around this, is there a better solution that a UserForm for what I am trying to do (show long messages)? I cannot use a label instead of a textbox either, the messages exceed the character limit for the .Caption property.
I fixed it but I'm not going to accept this as the true correct answer because I don't think it would solve everyone's problem. I needed to allow my users to still edit the spreadsheet while the userform was open, so when I set Messages.Show vbModeless it fixed everything. None of the text was selected, the scroll bars were visible, and it was scrolled to the top. I have a feeling it's because the focus technically isn't specifically on the userform anymore, so it didn't highlight the text. If you need to make sure nobody messes with the spreadsheet while the userform is open though, this will not solve the problem for you.
Full code for example:
Sub ValidateData()
'Do all your stuff
Call Messages_Initialize(msgDict)
Messages.Show vbModeless
End Sub
Sub Messages_Initialize(msgs As Dictionary)
Dim msgString As String
If Not msgs.Exists("success") Then
msgString = "The cells highlighted in red contain invalid values. Please fix before attempting to validate them again."
msgItems = msgs.Items
For i = 0 To msgs.Count - 1
msgString = msgString + vbNewLine + vbNewLine + msgItems(i)
Next i
Else
msgString = msgs("success")
End If
Messages.MessageBox.Text = msgString
Messages.MessageBox.MultiLine = True
Messages.MessageBox.Locked = True
Messages.MessageBox.WordWrap = True
Messages.MessageBox.SetFocus
Messages.MessageBox.CurLine = 0
End Sub

Get two VBA textboxes to scroll together

I have a macro that produces two multi-line TextBoxes of related data (sometimes hundreds of rows long). The boxes always have the same number of lines of text in them, with each line corresponding to the adjacent line in the other TextBox. I looked into using a two-column ListBox, but decided to use TextBoxes so that the data can be copied out/highlighted/selected as desired by the user.
I want to make it so that if a user scrolls down, both TextBoxes scroll together (i.e., the lines stay synced up).
After much digging and experimenting, I figured it out! By adding a ScrollBar, I was able to use the ScrollBar_Change() event to adjust the text boxes. On my form, I now have two TextBoxes and a ScrollBar object. Then I have a few necessary subs in my Userform code:
'This constant affects whether the ScrollBar appears or _
not, as well as some of the movement graphics of the _
ScrollBar.
'This MUST be reset if the TextBoxes are resized
'I made it a UserForm-level Const because I use it _
elsewhere, but it could also live in SetUpScrollBar
Private Const TEXTBOX_MAX_LINES_IN_VIEW as Long = 21
Private Sub SetUpScrollBar()
'I call this whenever I show my Userform (happens after a _
separate macro determines what to put in the TextBoxes). _
It determines whether the ScrollBar should be shown, and _
if so, sets the .Max property so it scrolls in accordance _
to the number of lines in the TextBoxes.
Dim linesInTextBox as Long
With Me.TextBox1
.SetFocus
linesInTextBox = .LineCount - 1
'Need to subtract 1 or you'll get an error _
when dragging the scroll bar all the way down.
End With
'If there are fewer lines than the max viewing area, hide the scroll bar.
Select Case linesInTextBox > TEXTBOX_MAX_LINES_IN_VIEW
Case is = True
ShowScrollBar True
With Me.ScrollBox
.Min = 0 'I believe this is the default, but I set it just in case
.Max = maxLinesInTextBox
.Value = 0
End With
Case is = False
ShowScrollBar False
End Select
End Sub
Private Sub ShowScrollBar(show As Boolean)
'A simple way of showing or hiding the scrollbar
With Me.ScrollBar1
.Enabled = show
.Visible = show
End With
End Sub
Private Sub ScrollBar1_Change()
'When the scrollbar position changes (either by dragging _
the slider or by clicking it), set the CurLine property _
of each TextBox to the current ScrollBar value.
With Me.TextBox1
'Need to set focus to the box to get or adjust the CurLine property
.SetFocus
.CurLine = Me.ScrollBar1.value
End With
With Me.TextBox2
'Need to set focus to the box to get or adjust the CurLine property
.SetFocus
.CurLine = Me.ScrollBar1.value
End With
End Sub
This seems to work quite well for my purposes. It allows me to keep the text-selecting/copying benefits of using TextBoxes while keeping my data synced together.
Some issues I've yet to solve:
Scrolling works fine, but if you try to click the arrows (particularly to go in the opposite direction that you just scrolled), you have to click until your cursor gets to the top of the TextBoxes. For me, this is 21 clicks. A bit annoying, but I'm sure there's a workaround.
Scrolling is not live like with a normal scrollbar. This means you can drag the scrollbar, but it won't update the TextBoxes until you let go.
If a user clicks into a TextBox and starts to navigate with their arrow keys, the two boxes will become out of sync. They'll resync the next time the user clicks the ScrollBar. This is very problematic if the user tries to select more lines than are visible in the window: one TextBox will scroll as they drag their selection but the other TextBox stays in place

Excel VBA textbox to populate combobox

I'm after some help that has had me stumped for a while. Excuse the long explanation.
I have a combobox that populates from a range when the userform initializes. When I type into the combobox the preemptive text appears as it is supposed to. I then have a Change event for a textbox which populates based on what gets typed into the combobox. That part all works fine (I got that code from another site).
I have two ways to enter the data into the combobox, one is by typing, and the other is when the text in another text box changes, it also populates the combobox. I do this by "combobox1 = textbox1.value". Now here is the part when I am stumped. When using the combobox1 = textbox1 method, it doesn't work properly (or more so, how I want it to work). It enters the text that is contained in textbox1, but it doesn't show the full line of preemptive text like how it does when typing in the combobox, nor does it then populate the textbox that changes when the combobox changes. If I then click in the combo box and hit the space bar the change event fires and the rest of the preemptive text from the range appears. I tried putting a space " " command at the end combobox1 = textbox1 & " " in the hope it would think there is more text to come but that didn't work. Is there any way to get VBA do do this, or am I asking too much of it?
Hopefully this makes sense.
cheers
paul
seems like ComboBox AutoCompletion feature is triggered by UI input only
you can work around it as follows:
Private Sub TextBox1_Change()
Dim iList As Long
With Me.ComboBox1
For iList = 0 To .ListCount - 1
If Left(.List(iList), Len(Me.TextBox1.Value)) = Me.TextBox1.Value Then
.ListIndex = iList ' if any combobox1 value matches textbox1 value then select it
Exit Sub
End If
Next
.ListIndex = -1 ' if no combobox1 value matches textbox1 value then "deselect" combobox1
End With
End Sub

how to add item to a combobox on button click?

I want to add item to a combobox found in excel worksheet from text box which is located in the user form When button is clicked.i see the value added to combobox but it will become empty when I close and reopens the workbook.can any one help me handling this?
Thank u for you're fast response first
thank you both for your feedback and correction.let me make more clear my concern
Create a workbook and save as xlsm.
On the first worksheet define user name as follows:
Name: dn_cmb_items
Range: =""
Using the developer ribbon add an Excel (not ActiveX) combobox onto the Worksheet1 and set its list-by-range to dn_cmb_items
Open VBA editor and add a user form to the workbook, name it as frm_add_cmb_item and set ShowModal to False.
Drop a text box to the form and name it tb_item_text.
Drop a button to the form, name it cmb_add and from its context menu choose View code. This creates the click event handler.
Implement the handler as follows:
Private Sub cmb_add_Click()
Dim v_r As Range, v_n As Name
Set v_n = Names("dn_cmb_items")
If v_n.Value = "=""""" Then
v_n.Value = "=" & Worksheets(1).Name & "!$A$1:$A$1"
v_n.RefersToRange.Value = tb_item_text.Text
Else
Set v_r = v_n.RefersToRange
Set v_r = v_r.Cells(v_r.Rows.Count + 1, 1)
v_r.Value = tb_item_text.Text
v_n.Value = "=" & Worksheets(1).Name & "!$A$1:" & v_r.Address(True, True)
End If
End Sub
Drop onto the workshet a button, then create/set a macros in the workbook. Implement the created macros with the code frm_add_cmb_item.Show.
In the VBA Editor from the Debug menu choose Compile. Then save the VBAProject as well as the workbook. That's all for the coding.
Switch to the worksheet, show the form.
Now when you enter some to the textbox, then click the cmb_add button, a new item will be added to the A column at the end thus changing the value of dn_cmb_items assigned to the combobox on the worksheet.
See the screenshorts attached:
Initial state:
1 added:
2 added:
PS
I have the ready workbook with all the code. Where should I upload it?
Be specific with your question and always post the relevant code, so that it will become easy to solve it for others.
If you want to see the data while executing the userform, just write the required data in userform_activate or Initialize. before executing it will take the values and shows up in the combobox.
the input which you are taking from the worksheet just write those values in another worksheet so that whenever you open the workbook the values will not get erased.

(Excel bug?) Avoid Hyperlink hit-area repeating on all pages of PDF generated with Excel

I discovered something strange in a PDF generated with Excel 2007. I need to create TextBoxes with Hyperlinks on a worksheet, set repeating header rows for printing and then export the worksheet to PDF.
Here's what happens. The first page of the PDF will show the TextBox, and it is clickable as a link, as expected. But strangely, all the following pages will have an area that's also clickable in about the same place the first page has the TextBox, but there's absolutely nothing there - i.e. second page is visibly blank, but there is somewhere on the page a blank clickable area that will open up the link of the TextBox from the first page. Which is not desired.
Here's some code that will prepare the scenario exactly:
' Run this procedure
Public Sub TestRepeatingHyperlinkHitArea()
Call AddDummyContent
Call CreateTextBoxWithHyperlink
ActiveSheet.PageSetup.PrintTitleRows = ActiveSheet.Rows(1).Address
Call ActiveSheet.ExportAsFixedFormat(xlTypePDF, _
"RepeatingHyperlinkHitArea.pdf", OpenAfterPublish:=True)
End Sub
Public Sub AddDummyContent()
' Needed only to create multiple pages
Call ActiveSheet.Cells.Clear
Dim i As Integer
For i = 1 To 300
ActiveSheet.Cells(i, 1).Value = i
Next i
End Sub
Public Sub CreateTextBoxWithHyperlink()
If ActiveSheet.Shapes.Count = 1 Then
Call ActiveSheet.Shapes(1).Delete
End If
Dim TB As Shape
Set TB = ActiveSheet.Shapes.AddTextbox(msoTextOrientationHorizontal, _
100, 100, 150, 50)
TB.TextFrame.Characters.Text = "I'm a textbox with a hyperlink"
Call ActiveSheet.Hyperlinks.Add(TB, "http://www.example.com")
End Sub
Paste this in a blank Workbook and run TestRepeatingHyperlinkHitArea(). It will prepare the ActiveSheet and create a PDF. In the PDF, search with your mouse on the second page and in its first half there will be the hit-area of a link (the same link from page 1), but nothing visible.
Is this avoidable? I really don't want ghost-links on the pages. It only seems to happen when ActiveSheet.PageSetup.PrintTitleRows is set, and only Hyperlinks on the first page are repeated as ghost-links. I'm assuming that the hyperlink hit-areas are somehow rendered on the same layer as the PrintTitleRows. Which is bad, as they get repeated together in the PDF.
Instead of normal TextBoxes, I tried using ActiveX Labels as Hyperlinks, since they don't exhibit this problem (they don't get rendered as Shapes?), but they're a mess to set up as Hyperlink targets in VBA (calling ActiveSheet.Hyperlinks.Add() on an ActiveX Label fails with error, no matter how I try to convert them to Shapes). Still trying though.
Any ideas about creating Hyperlinks in a PDF with repeating header rows are welcome.
EDIT: Dropbox link to generated PDF file: https://www.dropbox.com/s/un1q81vgpvvg6w0/RepeatingHyperlinkHitArea.pdf?dl=0

Resources