ActiveX Textbox flickers white whenever changing position - excel

I have an ActiveX Textbox on an Excel worksheet. I need to move this textbox around and change its visibility using VBA frequently as you interact with the program. The issue is whenever I change the textbox visibility or position, it briefly flashes white before reacting to the code. Here is a video of what I'm talking about. In this video, the code is designed to move the textbox (which has a grey background), to position itself directly over the active cell whenever the selection changes. You can see when it moves over a cell with a yellow background. Then when I change the selection to leave the yellow cell, you can see the textbox flicker white before moving to the new location and becoming grey again.
https://vimeo.com/709930517
Also heres a screenshot of the instant I click another cell after the textbox was placed over the yellow cell.
Before this image, the single textbox on the Worksheet was grey and placed over the yellow cell. You can see in the image after clicking above the yellow cell, the textbox has flickered white over the yellow cell. This is the white flicker. Also in this image, the textbox appears it has already moved to the new location (where I clicked), but its still visible in the old location as well! There's only 1 textbox on the worksheet!
This is super annoying because I have a lot of background colors and when the textbox flickers white it looks horrible.
This is my code:
WORKSHEET CODE
Private Sub RulesTextbox_KeyDown(ByVal keyCode As MSForms.ReturnInteger, ByVal shift As Integer)
Call MODTextbox_KeyDown(keyCode, shift, TextboxSheets.rules)
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Call MODWorksheet_SelectionChange(Target)
End Sub
MODULE CODE
Option Base 0
Option Explicit
Global activeCell As Range
Public Sub MODTextbox_KeyDown(ByVal keyCode As MSForms.ReturnInteger, ByVal shift As Integer)
End Sub
Public Sub MODWorksheet_SelectionChange(ByVal Target As Range)
Application.ScreenUpdating = False
Set activeCell = Target
Dim textbox As OLEObject
Set textbox = Worksheets(1).OLEObjects("MyTextbox")
Call MODResizeTextboxToMatchRange(textbox, Target)
With textbox
.Visible = False
.Visible = True
.Object.BackColor = RGB(220, 220, 220) 'light grey
End With
textbox.Object.Value = activeCell.Value2
textbox.Activate
Application.ScreenUpdating = True
End Sub
Public Sub MODResizeTextboxToMatchRange(ByRef textbox As OLEObject, ByRef selectedRange As Range)
If selectedRange Is Nothing Then
Exit Sub
End If
Dim totalWidth As Double
Dim totalHeight As Double
Dim top As Double: top = selectedRange.top
Dim left As Double: left = selectedRange.left
If selectedRange.MergeCells And selectedRange.Cells.Count = 1 Then
totalWidth = selectedRange.MergeArea.Width
totalHeight = selectedRange.MergeArea.Height
Else
totalWidth = selectedRange.Width
totalHeight = selectedRange.Height
End If
With textbox
.top = top + 1
.left = left + 1
.Width = totalWidth - 2
.Height = totalHeight - 2
End With
End Sub
I've tried various work-arounds to try and get this to work:
It doesnt matter if you reposition the textbox or make it invisible, it always fickers white first.
Application.ScreenUpdating = False has no effect. Neither does calling DoEvents immediately after changing the position.
Changing the transparency of the textbox to try and make it dissappear doesnt help either, you get the same white flicker
It's like causing any change to the control makes it flicker. I would love some kind of ScreenUpdating = False equivalent so I could just hide the textbox and set back to true when its repositioned. I don't know much about the internal workings of ActiveX. Is it an issue with my computer and not Excel?
Also using a regular form input will not work, I need ActiveX to be able to style the textbox, particularly increasing the font size for users.
Any help is appreciated thanks

Well I figured it out. I need to set the textbox to .Visible = False BEFORE it get's moved, then make it visible after the move.
And you also need to set the backstyle of the textbox to transparent, in the VBA properties before you run the program. When the program is running and the textbox is focused it WONT be transparent, but as soon as it loses focuses it becomes transparent which will eliminate the flicker.
And finally, the TEXT of the textbox may still flicker even if the background doesnt. You can overcome this by setting the font size to 0 before you change the position, then when the textbox arrives at the new location set the font size back to 12 via VBA. You will still see a very tiny version of the text in the flicker, so to take it a step further in addition to setting the font size to 0 you can change the color of the font in the textbox via VBA to match the background color of the cell behind it, again switching back to regular font color once the textbox has been moved.
Wow I had no idea it was so simple!

Related

Excel Shape position disturbed by Windows Display Zoom settings

I would like to get accurate Shape position in Excel. I noticed that Shape.Top is being disturbed by Windows Display Zoom settings.
To reproduce the bug, please right click on a sheet name > View code > and paste the VBA code in the sheet VBA editor.
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Cancel = True
On Error Resume Next
ThisWorkbook.ActiveSheet.Shapes("BlueRectangle").Delete
Dim sh As Object
Set sh = ThisWorkbook.ActiveSheet.Shapes.AddShape(msoShapeRectangle, ActiveCell.Left, ActiveCell.Top, ActiveCell.Width, ActiveCell.Height)
sh.Name = "BlueRectangle"
End Sub
This code creates Rectange shape in the double clicked cell. Everything works fine as long as the display zoom of Windows settings is set up to 100%. However when we change display zoom in Windows settings to 125% then the rectangle is created in a slightly different place than the Active cell. There is a difference of 1 row in the location height for every 100 rows of Excel. So, when I click A100 cell then the Rectangle is created in A99 cell.
I would like to correct the location Rectangle creation so that Windows Zoom Display is taken into account.
Here is behavior with 100% Display Zoom:
Here is a buggy behavior I would like to fix which happens with 125% Display Zoom:
Here is the related inconspicuous challenge I threw on SO which might be a milestone in answering this question:
Get Windows display zoom value
I cannot reproduce your issue. I'm working with 150% and positioning is correct in Excel even for the very last cells.
Also there should be nothing need to be corrected.
But there might be some issues with your code:
Avoid ThisWorkbook.ActiveSheet and use Target.Parent this is more reliable.
Also avoid using ActiveCell and use Target because ActiveCell might not have changed to the cell you clicked on yet. Target is the cell you doubleclicked not ActiveCell.
Give the follwing a try. I doupt that the DPI is the issue and I suspect it is a ActiveCell related issue.
Option Explicit
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Cancel = True
On Error Resume Next
Target.Parent.Shapes("BlueRectangle").Delete
On Error GoTo 0 'always re-activate error handling after an expected error
Dim shp As Shape
Set shp = Target.Parent.Shapes.AddShape(msoShapeRectangle, Target.Left, Target.Top, Target.Width, Target.Height)
shp.Name = "BlueRectangle"
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

Disable button using Excel VBA

I want to disable a button with VBA code like this:
ActiveSheet.Shapes("Button 1").ControlFormat.Enabled = False
I tried:
Set b1 = ActiveSheet.Buttons("Button 1")
b1.Enabled = False
And:
Me.Shapes("Button 1").ControlFormat.Enabled = False
My button name is correct, because it doesn't give me an error message, so the code is completely run through.
After this script I can click on that button and the assigned macro runs. Nothing should happen when I click on it.
Disabling a Form button (not talking ActiveX here) does not prevent the assigned macro to run and does not gray out the button. The code below does exactly that based on the version got from Excel. If you did not assign a name to your Form button, you can also use (Buttons(1).
If Excel version = 16 or higher the button is "enabled" by making it black and assigning my macro, else the button is "disabled" by making it gray and assigning no action to it.
Code can e.g. reside in Private Sub Worksheet_Activate() within sheet "Test Sheet"
If Application.Version < 16 Then
Worksheets("Test Sheet").Buttons("button_name").Font.Color = 8421504
Worksheets("Test Sheet").Buttons("button_name").OnAction = ""
Else
Worksheets("Test Sheet").Buttons("button_name").Font.Color = 0
Worksheets("Test Sheet").Buttons("button_name").OnAction = "'Name of the workbook.xlsm'!my_macro_name"
End If
Probably you are using ActiveX Button. Try this:
Sheets("Sheet1").CommandButton1.Enabled = False '--->change sheet name as required
EDIT:
______________________________________________________________________________
For a Form control Button the following line
ActiveSheet.Shapes("Button 1").ControlFormat.Enabled = False
disables the button i.e. click event will no longer work but the appearance of the button does not change which gives an impression that the button is still active. So work around for that is to change the color of the text of the button as follows:
Sub disable_button_2()
Dim myshape As Shape: Set myshape = ThisWorkbook.Worksheets("Sheet1").Shapes("Button 2")
With myshape
.ControlFormat.Enabled = False '---> Disable the button
.TextFrame.Characters.Font.ColorIndex = 15 '---> Grey out button label
End With
End Sub
And to bring back button to its original state write:
Sub activate_button_2()
Dim myshape As Shape: Set myshape = ThisWorkbook.Worksheets("Sheet1").Shapes("Button 2")
With myshape
.ControlFormat.Enabled = True '---> Enable the button
.TextFrame.Characters.Font.ColorIndex = 1 '---> Highlight button label
End With
End Sub
I suggest to create a shadow button/shape with exactly same size/position, but different color (fill and/or text to your liking) and no macro/action attached. Then just change the .visible property of your primary shape. Visible = button is active; not visible button is e.g. grayed out and has no action/is passive.
Only tested on Excel 2016 x86
I continued to receive errors utilizing .ControlFormat. solutions.
After much searching I found another solution that worked great for my needs of disabling Shapes/Buttons.
To mimic the .Enabled property of a uf control, you might toggle the .OnAction property of a shape.
Function ShapeIsEnabled(aShape As Shape) As Boolean
ShapeIsEnabled = (aShape.OnAction <> "")
End Function
Sub EnableShapeMacro(aShape As Shape)
aShape.OnAction = aShape.AlternativeText
End Sub
Sub DisableShapeMacro(aShape As Shape)
aShape.AlternativeText = aShape.OnAction
aShape.OnAction = vbNullString
End Sub
Note the use of the .AlternativeText property to store the macro name.
source: mikerickson
https://www.excelforum.com/excel-programming-vba-macros/1267897-disable-action-of-macro-enabled-shape.html#post5080833

Last item in multiselect listbox only partly visible

I have an excel sheet with multiple listboxes. All of them multi-select. As excel always messes up the dimensions of the listboxes i had a piece of code to repair them when opening the workbook:
Private Sub Workbook_Open()
Dim Ctrl As OLEObject
For Each Ctrl In Sheets("SomeSheet").OLEObjects
If Ctrl.progID = "Forms.ListBox.1" Then
With Ctrl
.Width = 95.4
.Height = 70.2
End With
End If
Next Ctrl
End Sub
However after a while i noticed that the last entry is at best partially visible. A search on the interweb provided me with a solution : link.
Unfortunately that solution does not work for me. I adapted the above code to:
Private Sub Workbook_Open()
Dim Ctrl As OLEObject
Application.ScreenUpdating = False
For Each Ctrl In Sheets("SomeSheet").OLEObjects
If Ctrl.progID = "Forms.ListBox.1" Then
With Ctrl
.Object.IntegralHeight = False
.Width = 95.4
.Height = 70.2
.Object.IntegralHeight = True
.Object.MultiSelect = fmMultiSelectSingle
.Object.MultiSelect = fmMultiSelectExtended
End With
End If
Next Ctrl
End Sub
The result is that the width and height i have set are again screwed up by excel, as soon as the three statements following the .height are executed. With each statement resulting in a further shrinking of the listbox in both dimensions. To make matters worse they also move away from their position.
I'm looking for any clues how to fix this, so to have listboxes of the desired dimension, with all entries visible.
Edit 20140905
As per request a screenshot is added. Even though the scrollbar suggest i can scroll down further, that is not possible. As you can see by the blue color, 'Orange' is there, and is selected, and is in the listbox.
set IntegralHeigth property of ListBox to false.

Clipboard "copy" selection gone when autosizing VBA button?

I´m puzzled that Excel throws away the clipboard "copy" selection for no (obvious) reason when creating an auto-sized button.
Consider this simple selection change handler:
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Excel.Range)
Dim P As Button: Set P = ActiveSheet.Buttons.Add(1, 1, 100, 100)
End Sub
This simple creates a dumb button on the top left corner of the sheet on every cell selection change.
If you press Ctrl-C in any cell (no matter if it´s empty or not), the cell will have this nice border indicating that the selection is what will be pasted if you select paste elsewhere.
That border will remain visible even if you navigate around on the sheet.
Now add one line:
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Excel.Range)
Dim P As Button: Set P = ActiveSheet.Buttons.Add(1, 1, 100, 100)
P.AutoSize = True
End Sub
This makes the button(s) autosize themselves. Works fine. But from know on, every selection change will destroy the clipboard "copy" selection.
Why? Can I prevent this, or work around it?
Reproduced with Excel 10 14.0.7116.5000 32-bit :-O
If you have copied content then you will need to paste it before anything else happens. This is how Excel behaves naturally.
So, in your event, you can Paste the content (to the currently active cell) before Auto-Sizing the button.
Dim P As Button
If Application.CutCopyMode = xlCopy Then
Me.Paste
End If
Set P = ActiveSheet.Buttons.Add(1, 1, 100, 100)
'Application.EnableEvents = False
P.AutoSize = True
'Application.EnableEvents = True
EnableEvents is unnecessary here, but I've included it to indicate how you might prevent an event from triggering a second time. You probably need to work with it at some point.

Resources