Application.ScreenUpdate and Shapes - excel

I have a sheet that I have a bunch of shapes (rectangle = button) that have marcos assigned to. I am using the shapes as a userform. There is one button that toggles between forms (essentially hiding all the visible shapes then showing all the shapes for another setup). The issue that I am having is that during the switch over to the other setup the shapes from the first setup still appear throughout the transition even though I am using:
Application.ScreenUpdate=False
I am trying to have a clean transition / clean switch over. Any thoughts? If my question is not clear, please let me know.
Sample Code
Sub Toggle_Form
Application.ScreenUpdating = False
Call Form1_ShowHide(False)
Call Form2_ShowHide(True)
Application.ScreenUpdating = True
Sub Form1_ShowHide(VisibleState as boolean)
For CoUnTer = 1 To 10
WS.Shapes("Shape1_" & CoUnTer).Visible = VisibleState
Next CoUnTer
End Sub
Sub Form2_ShowHide(VisibleState as boolean)
For CoUnTer = 1 To 20
WS.Shapes("Shape2_" & CoUnTer).Visible = VisibleState
Next CoUnTer
End Sub
I am using Excel 2016. Do not think it is a computer processing issue (got a pretty good laptop).

Related

Drawing shapes to screen falling behind other code

I am trying to create a small tutorial for one of my Excel Applications and I am running into the issue where I'm trying to draw a text shape to the screen to give advice on what to enter into an InputBox but the InputBox gets displayed before the text shape, however, when running in debug mode and stepping through the code it all works fine.
There is one userform ufNext which only contains one button, ufNext. The click event code for this button contains a Select Case clause to determine what to do each time it is clicked. The value the clause is checking is a Public variable, tutSectionsRun
Option Explicit
Private Sub btnNext_Click()
Select Case tutSectionsRun
Case 1
Call Section2
Case 2
Call Section3
Call MPFilterString
' Case N
' ...
End Select
End Sub
The code starts in Section1 which just sets the position of ufNext and shows the form then sets the global variable tutSectionsRun to 1.
The user clicks the "Next" button on the ufNext form and it calls Section2 which re-positions the form (there would normally be other code in these "Section" procedures), and sets the global variable to 2.
Again, the user clicks the "Next" button but this time there is the issue where before the shapes are drawn to the screen, I get the InputBox popping up first and only after it closes the text shape tutText is drawn to the screen.
Option Explicit
Public tutSectionsRun As Long
Sub Section1()
ufNext.Left = 550
ufNext.Top = 450
ufNext.Show
tutSectionsRun = 1
End Sub
Sub Section2()
ufNext.Left = 910
ufNext.Top = 350
tutSectionsRun = 2
End Sub
Sub Section3()
Dim tutText As Shape
Set tutText = ActiveSheet.Shapes.AddLabel(msoTextOrientationHorizontal, 600, 300, 200, 100)
tutText.TextFrame2.TextRange.Text = "Enter the string ""gr"" into the input box."
tutText.Locked = False
ufNext.Hide
tutSectionsRun = 3
End Sub
Sub MPFilterString()
Dim s As Variant
Application.ScreenUpdating = False
s = Application.InputBox("Enter string to filter out.", "Filter String.")
If s = False Then Exit Sub
End Sub
**Edit : I forgot to mention that the userform is non-modal. Otherwise execution would pause on the call to ufNext.Show and clicking next would call the event handler before the tutSectionsRun variable had been set to 1
Thanks to #BrakNicku who confirmed my suspicions in the comments, saying that the InputBox was preventing the screen from being refreshed for the text shape from ActiveSheet.Shapes.AddLabel to be displayed.
Their link to this answer offered some suggestions.
What I found was that adding either of these before the InputBox was called would force the screen to refresh but only if Application.ScreenUpdating = False was removed, or at least just moved further down in the code.
- ActiveSheet.Calculate
- ActiveWindow.SmallScroll
- Application.WindowState = Application.WindowState
I always like to call Application.ScreenUpdating = False at the top of my procedures, so I went with a different approach, thinking that the problem was that the time to refresh the screen with shapes drawn was longer than the time between the instruction to do so and the instruction to draw the InputBox to screen. So, I thought a slight delay before calling the InputBox might be a better choice for me, probably not for everyone but I felt better about doing it this way. (Application.ScreenUpdating = False is a good friend of mine and I didn't want to see her go, or even be relocated) So I just made a small wait procedure.
Sub Wait(secs As Single)
Dim finishTime As Single
finishTime = Timer + secs
Do While Timer < finishTime
DoEvents
Loop
End Sub
And called it at the top of the MPFilterString procedure. It only takes about 50ms for the shapes to show on screen but I give it 100ms to be safe.
Sub MPFilterString()
Dim s As Variant
WaitFor (0.1)
Application.ScreenUpdating = False
s = Application.InputBox("Enter string to filter out.", "Filter String.")
If s = False Then Exit Sub
' more code ...
End Sub

Changing Userform Label derived from one worksheet when inputting on a different worksheet

I have a worksheet that runs a weightlifting meet. Last year I had created a tab that would give information on the current lifter and on who was lifting next.
left side - Display, right side - input tab
When I input an "x" in columns R, S, T, or W on the data tab, it changes the information in the BenchGenerator tab, like so:
Updated Display tab
What I want to do is make a userform display to run on a different screen so people can see this information. I had accomplished this last year by widening excel and using two view windows - display on the second screen and running the meet on the computer. It was ok but very clunky looking. With a floating userform tab, it would look fantastic. I am new to this, but got the form floating:
Private Sub Worksheet_Change(ByVal Target As Range)
UserForm1.Show (vbModeless)
End Sub
And got the labels to initially populate:
Userform Display
Using this code:
Private Sub UserForm_Activate()
UserForm1.Label1.Caption = Sheets("BenchGenerator").Range("c4").Value
UserForm1.Label2.Caption = Sheets("BenchGenerator").Range("c5").Value
UserForm1.Label3.Caption = Sheets("BenchGenerator").Range("c6").Value
UserForm1.Label4.Caption = Sheets("BenchGenerator").Range("d3").Value
UserForm1.Label5.Caption = Sheets("BenchGenerator").Range("d4").Value
UserForm1.Label6.Caption = Sheets("BenchGenerator").Range("d5").Value
UserForm1.Label7.Caption = Sheets("BenchGenerator").Range("d6").Value
End Sub
What it doesn't currently do is update the captions when I input the "x" in the data tab.
As I mentioned, this is my first foray into userforms and looking through mountains of code trying to figure this out, it will not be my last as there is lots to accomplish with them.
Thanks in advance for any help!
You're pretty close to getting this to work. The problem is that your calling a new form every time a change occurs.
Declare your form as an object outside of the Sub that creates (Show) it.
You can then access it to update labels from another Sub that has the same scope.
Create an UpdateForm sub for example and call it from your Worksheet_Change event.
Try this, place the following code in a new Module:
Dim myForm As Object
Sub launchForm()
Set myForm = UserForm1
myForm.Show (vbModeless)
End Sub
Sub updateForm()
Dim wks As Worksheet
Set wks = Sheets("BenchGenerator")
'Update label values here
myForm.Label1.Caption = wks.Range("C4").Value
myForm.Label2.Caption = wks.Range("C5").Value
myForm.Label3.Caption = wks.Range("C6").Value
myForm.Label4.Caption = wks.Range("D3").Value
myForm.Label5.Caption = wks.Range("D4").Value
myForm.Label6.Caption = wks.Range("D5").Value
myForm.Label7.Caption = wks.Range("D6").Value
End Sub
If you use Worksheet_Change to update the form you'll want to verify the form exist or just skip any errors in the event if it doesn't.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
updateForm
End Sub
Not sure if there is an easier way to do it, but I made a concatenation routine to batch out my label setup and updates to quickly create/copy/paste all the code.
Just in case anyone didn't know how to do this

Launch a different sheet by Spin button

want to use a Spin button (ActiveX Control) to show a previous or next sheet. When the button is clicked the event is successfully triggered and the desired sheet is activated but it holds some elements (commands, graphs, etc.,) from the original sheet and shows these as an appending picture.
Sample code for Down button event :
Private Sub SpinButton_JumpToWeek_SpinDown()
Dim sh_num As String
Dim tmp_num As Integer
Application.ScreenUpdating = False
Application.EnableEvents = False
SpinButton_JumpToWeek.Value = Range("B27").Value - 1
tmp_num = SpinButton_JumpToWeek.Value
' Activate desired KTx sheet
sh_num = "KT" & tmp_num
Range("F27").Value = "" 'reset to blank
Sheets(sh_num).Activate
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
To override this effect I have to manually select (activate) another sheet and then again select the desired sheet. I tried also to automatize this workaround with a macro, but unfortunately it does not work.
It is interesting that this problem do not occur if I execute code in Debug mode (using breakpoint and the stepping line by line).
Surprisingly, I do not have such problem if I try to show the previous/next sheet by writing a value (sheet name index) into a defined cell (i.e. using the Worksheet_Change event). The desired page is correctly shown. See photos.
Sample code for this evententer image description here:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim sh_num As String
Application.ScreenUpdating = False
Application.EnableEvents = False
If Range("F27").Value > 0 Then
' Activate desired KTx sheet
sh_num = "KT" & Range("F27").Value
Range("F27").Value = "" 'reset to blank
Sheets(sh_num).Activate
End If
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
I need to use the Spin button because it is faster and allow me to skip some sheets (for example if these do not have data).
The problem occurs in both 32 and 64-bit Excel.
Do somebody an idea why this problem is occurring and a workaround? Do I have to change some settings or system properties in Excel? Any help would be highly appreciated.
#mehow
I append my commenst here due to large number of words.
I followed your suggestion and tried the example of a UserForm with inserted active control “Microsoft Office Spreadsheet”. I found out that this would not be a good solution for my case, because the response of such sheet is relatively slow (even on a fast PC like mine) when user inserts values into cells. Furthermore, this would greatly complicate my fairly simple *.xlsm workbook, which has more than 50 sheets (1 sheet for each week, the contents of these sheets are then linked to a main sheet), and completely meets my basic necessities (with the exception of this spin button of course).
In my opinion there is probably necessary to manipulate some kind of system property (like for e.g. Application.ScreenUpdating trick), but I do not have enough VBA knowledge to find it.
To clearly explain my question I would need to share my sample workbook, but I do not know how to upload it to this forum. Unfortunately, I am not able upload/show images successfully on this forum (due to my low rating), which would also help a lot.
BTW, I cannot see images on other questions of this forum, too. . Could this problem occur due to missing plugins in a web browser?
You can use a simple trick... before the "Application.screenupdating = true" you can insert the two lines:
ActiveWindow.SmallScroll Down:=-100
ActiveWindow.SmallScroll Up:=100

Excel - Screen flicker on screen update

I've got yet another question from the long serries of 'Stop excel screen from flickering', but I think this one is a bit more tricky.
I've got a client who requires a 'progress' bar on his spreadsheet during macro execution.
What I've done, is I've a pie chart linked to 2 cells which I adjust based on the progress. For performance, I've disabled events, ScreenUpdating and changed calculation to manual.
Then, once in a while I quickly toggle ScreenUpdating on and off to actually update the progress chart. This works like a charm every time I use it (more than 30 projects now).
Recently, the client came back to me with a 'big' problem. Whenever I do the quick toggle to refresh the progress chart, the entire excel screen (including all the items on it)flickers, which drives the guy crazy.
Has anyone got any idea on what could be done with this to keep the chart updating while keeping the front page constantly displayed (the macro jumps between pages) without screen flickering? Something like double buffering or so...
SOLUTION
Believe it or not, but I just found a solution. This was so so so easy. In VBA, it's possible to refresh just a specific object, while the remaining screen remains 'locked'. For example:
ThisWorkbook.Worksheets("Welcome").ChartObjects(1).Chart.Refresh
Thank you everyone for your input.
You may be able to rewrite the macro so that it doesn't "jump between pages" (since it's usually not necessary to activate worksheets in order to manipulate their data. Otherwise, either a user form or the application's StatusBar could be used to display a progress bar:
Sub StatusBar()
Dim pct As Double
Dim msg as String
Application.ScreenUpdating = False
For i = 10000 To 1 Step -1
pct = (10000 - i) / 10000
msg = Format(pct, "0.0%") & " complete"
Application.StatusBar = msg
Next
Application.StatusBar = False
Application.ScreenUpdating = True
End Sub
Here is a revised example with UserForm. Note that you will need to add the UserForm module, and at least one Label to it in order to present the information:
Sub StatusBar()
Dim pct As Variant
DoEvents
UserForm1.Show vbModeless
Application.ScreenUpdating = False
For i = 10000 To 1 Step -1
pct = (10000 - i) / 10000
If Int((i / 10000) * 100) = (i / 10000) * 100 Then
msg = Format(pct, "0%")
UserForm1.Label1 = msg & " complete"
End If
Next
UserForm1.Label1 = "Finished!"
Application.ScreenUpdating = True
End Sub
Problem might be that, depending on how quickly your macro(s) execute, the progress indicator may appear to jump from 0 to 100%. You can do graphical progress bars, too, but the basic idea behind it would be the same, just instead of updating a label value, you'd be changing the size of a textbox with a differing background color, etc.
Revised per OP comments
This is how you can "copy" a range from one sheet to another sheet without "copy/paste":
Set rng1 = Sheets(1).Rows(12)
Set rng2 = Sheets(2).Rows(1)
rng2.Value = rng1.Value
So, you can just define your ranges, and assign the second range to = the first range.

Bugs in Excel's ActiveX combo boxes?

I have noticed that I get all sorts of annoying errors when:
I have ActiveX comboboxes on a worksheet (not an excel form)
The comboboxes have event code linked to them (eg, onchange events)
I use their listfillrange or linkedcell properties (clearing these properties seems to alleviate a lot of problems)
(Not sure if this is connected) but there is data validation on the targeted linkedcell.
I program a fairly complex excel application that does a ton of event handling and uses a lot of controls. Over the months, I have been trying to deal with a variety of bugs dealing with those combo boxes. I can't recall all the details of each instance now, but these bugs tend to involve pointing the listfillrange and linkedcell properties at named ranges, and often have to do with the combo box events triggering at inappropriate times (such as when application.enableevents = false). These problems seemed to grow bigger in Excel 2007, so that I had to give up on these combo boxes entirely (I now use combo boxes contained in user forms, rather than directly on the sheets).
Has anyone else seen similar problems? If so, was there a graceful solution? I have looked around with Google and so far haven't spotted anyone with similar issues.
Some of the symptoms I end up seeing are:
Excel crashing when I start up (involves combobox_onchange, listfillrange->named range on another different sheet, and workbook_open interactions). (note, I also had some data validation on the the linked cells in case a user edited them directly.)
Excel rendering bugs (usually when the combo box changes, some cells from another sheet get randomly drawn over the top of the current sheet) Sometimes it involves the screen flashing entirely to another sheet for a moment.
Excel losing its mind (or rather, the call stack) (related to the first bullet point). Sometimes when a function modifies a property of the comboboxes, the combobox onchange event fires, but it never returns control to the function that caused the change in the first place. The combobox_onchange events are triggered even when application.enableevents = false.
Events firing when they shouldn't (I posted another question on stack overflow related to this).
At this point, I am fairly convinced that ActiveX comboboxes are evil incarnate and not worth the trouble. I have switched to including these comboboxes inside a userform module instead. I would rather inconvenience users with popup forms than random visual artifacts and crashing (with data loss).
I don't have a definitive answer for you, but I can tell you that I stopped using ListFillRange and LinkedCell for ActiveX controls about 10 years ago. I don't recall what particular problems I encountered. I just remember coming to the conclusion that whatever little time they saved me isn't worth the brain ache of trying to track down the bugs. So now I populate the controls through code and deal with output in the events.
My active-x combo box works fine when my Dell is docked but resizes to a larger font each time it is clicked when the Dell is undocked - very strange. I added resizing code which works when undocked, but both .height and .scaleheight fail when docked and when triggered programmatically (even stranger).
Sheet2.Shapes("cb_SelectSKU").Select
Selection.ShapeRange.Height = 40
Selection.ShapeRange.ScaleHeight 0.8, msoFalse, msoScaleFromTopLeft
I then added my own enableevents-like switch so that the resizing only occurs when a user selects a combobox value, not when anything is affected while a macro is running.
Select Case strHoldEvents
Case Is = "N" 'Combobox resizing fails with error when triggered programatically (from SaveData)
Call ShowLoadShts
Sheet2.Shapes("cb_SelectSKU").Select
Selection.ShapeRange.Height = 40
Selection.ShapeRange.ScaleHeight 0.8, msoFalse, msoScaleFromTopLeft
Case Else
End Select
Finally that seems to work, whether docked or undocked, whether triggered by the user or during a procedure. We'll see if it holds...
I have a partial reply for the Dell users, and for your formatting problem
The formatting and display problem is another known-but-undocumented issue in Excel.
Many flat-panel monitors (including laptop displays) are unable to render fonts correctly in textbox controls on an Excel spreadsheet: you've got a mild version of this problem.
Our company has recently upgraded to new (and much larger!) monitors, and I can at last use textboxes, labels and combo boxes in worksheets. Our old Samsung screens displayed text controls correctly, but any manual or VBA-driven updates resulted in an illegible jumble of overlapping characters.
Listboxes don't have the problem: it's the 'textbox' part of your combo box that has the issue. Try manipulating a listbox in VBA event procedures: it's a kludge but it works.
In-Cell dropdowns from Data Validation lists don't have the problem. If you set up a validation list for a cell, then set the data validation error messages to empty strings, you can enter free-form text in the cell; the drop-down list is advisory, not a mandatory limit-to-list.
The problem is sometimes ameliorated (but never completely fixed) by using the Terminal or System fonts in your Active-X control.
The problem is sometimes ameliorated (but never completely fixed) by using a VBA event to nudge or resize your Active-X control by 0.75 mm.
Check if your laptop manufacturer has released an upgrade to the display drivers.
...And that's everything I know about the font rendering problem. If Mike (with his Dell laptop) is reading this: Good luck with those workarounds - to the best of my knowledge, there's no real 'fix'.
The stability problem was a major headache for me until Excel 2003 came out: using any Active-X control in the sheet was a source of instability. The Jury's still out on Listbox controls embedded in a sheet, even in Excel 2003: I still avoid using them.
So I was facing the same issues. I had a file with drop down lists on which I had superimposed the combobox to fight the issue of illegibility when zooming out too much. This was what my code looked like INITIALLY:
'=========================================
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim str As String
Dim cboTemp As OLEObject
Dim ws As Worksheet
Set ws = ActiveSheet
On Error GoTo errHandler
If Target.Count > 1 Then GoTo exitHandler
Set cboTemp = ws.OLEObjects("ComboBox1")
On Error Resume Next
If cboTemp.Visible = True Then
With cboTemp
.Top = 10
.Left = 10
.ListFillRange = "Treatment"
.LinkedCell = Target.Address
.Visible = False
.Value = ""
End With
End If
On Error GoTo errHandler
If Target.Validation.Type = 3 Then
'if the cell contains a data validation list
Application.EnableEvents = False
'get the data validation formula
str = Target.Validation.Formula1
str = Right(str, Len(str) - 1)
With cboTemp
'show the combobox with the list
.Visible = True
.Left = Target.Left
.Top = Target.Top
.Width = Target.Width + 15
.Height = Target.Height + 5
.ListFillRange = ws.Range(str).Address
.LinkedCell = Target.Address
End With
cboTemp.Activate
'open the drop down list automatically
Me.ComboBox1.DropDown
End If
exitHandler:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
errHandler:
Resume exitHandler
End Sub
'====================================
'Optional code to move to next cell if Tab or Enter are pressed
'from code by Ted Lanham
'***NOTE: if KeyDown causes problems, change to KeyUp
'Table with numbers for other keys such as Right Arrow (39)
'https://msdn.microsoft.com/en-us/library/aa243025%28v=vs.60%29.aspx
Private Sub ComboBox1_KeyDown(ByVal _
KeyCode As MSForms.ReturnInteger, _
ByVal Shift As Integer)
Select Case KeyCode
Case 9 'Tab
ActiveCell.Offset(0, 1).Activate
Case 13 'Enter
ActiveCell.Offset(1, 0).Activate
Case Else
'do nothing
End Select
End Sub
'====================================
I was facing all sorts of issues but as primarily mentioned on this thread, the LinkedCell issue was the biggest. My selection from the drop down menu would go wherever on the sheet I had clicked last, instead of the cell I had chosen the drop down box from, and in process, also disturbing the code of wherever the selection would go. I used a simple ONE LINE code to make sure my program in ActiveX runs only when its a drop down menu. I used this before the LinkedCell command ran:
If Target.Validation.Type = 3 Then
'... all the normal code here...
End If
So my code now looks like this:
'... Code as before
If Target.Validation.Type = 3 Then
' NEW CODE LINE ABOVE
If Target.Count > 1 Then GoTo exitHandler
Set cboTemp = ws.OLEObjects("ComboBox1")
On Error Resume Next
If cboTemp.Visible = True Then
With cboTemp
.Top = 10
.Left = 10
.ListFillRange = "Treatment"
.LinkedCell = Target.Address
.Visible = False
.Value = ""
End With
End If
End If
' End of the new If
Unbelievably, this worked. And now my excel sheet isn't misbehaving anymore. Hope this helps.
For this reason, I use cells with data validation lists when putting combo boxes on a spreadsheet.

Resources