Why does Excel vba copy to clipboard inconsistently? - vba

I have an excel macro that does two very simple things:
It displays the current date and time in a little window.
It copies the display as a text string for pasting into other apps as needed.
The cell that is displayed has the following formula in it:
=TEXT(NOW(),"yyyy.MM.dd hh:mm:ss")
Every 5 seconds, the macro refreshes the time and the clock ticks.
My problem is that when I copy the time from the cell, I don't consistently get the contents pasted to the clipboard. Sometimes the cell contents are posted to the clipboard. I can't figure out why it works sometimes and not others as there isn't a lot going on. It should just always work.
I know the data aren't on the clipboard because I can try pasting the clipboard into different programs like notepad and other text apps and nothing happens.
The entire code is in a single module.
Dim stopSwitch As Integer
Dim NextTick
Sub myupdate()
If ActiveCell.Address = "$B$1" Then
growWindow ' resize window beyond just clock display
stopTime '
Exit Sub ' stop updating
End If
Range("a1").Select
Calculate
DoEvents
If ActiveWorkbook.Name = "calendar clock.xlsb" Then shrinkWindow
NextTick = Now + TimeValue("00:00:05") ' give me 5 seconds to copy/paste
Application.OnTime NextTick, "myupdate"
ThisWorkbook.Save ' futile attempt to prevent save dialog
End Sub
Sub auto_open()
' to stop clock, tap right arrow to select cell b1 when workbook is active
Range("a1").Select
myupdate
End Sub
Sub growWindow()
Application.Width = 768
Application.Height = 621.75
ThisWorkbook.Save
End Sub
Sub shrinkWindow()
' strip decorations so window is as small as possible
Application.DisplayFormulaBar = False
ActiveWindow.DisplayGridlines = False
ActiveWindow.DisplayHeadings = False
' move window to second monitor and size to single cell display
Application.WindowState = xlNormal
Application.Top = 0
Application.Left = -720
Application.Width = 174
Application.Height = 127
ActiveWindow.WindowState = xlMaximized
End Sub
Sub stopTime() ' called when workbook is closed
On Error Resume Next
Application.OnTime NextTick, "myupdate", schedule:=False
Range("b1").Select
End Sub
Sub copyTime()
Range("a1").Copy ' copy time
Range("f5").PasteSpecial xlPasteValues ' strip formatting
Range("f5").Copy ' copy time as text
DoEvents ' hack to attempt to make copy work consistently
End Sub
The above code sizes the window and updates the clock every 5 seconds.
To copy the clock as text to the clipboard, I have the following code in the workbook
Private Sub Workbook_Activate()
Application.OnKey "^c", "module1.copyTime"
End Sub
Private Sub Workbook_Deactivate()
Application.OnKey "^c"
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
' turn off auto update
Module1.stopTime
' resize window so if I open another spreadsheet, it's a reasonable size
Application.WindowState = xlNormal
Application.Width = 768
Application.Height = 621.75
Application.OnKey "^c"
ThisWorkbook.Save ' try to prevent save dialog at close
End Sub
I modified the copyTime function to verify the ^C is seen by selecting the unformatted cell and I can see that the data consistently go to the cell so I know my problem isn't with the Range("a1").copy step in copytime or the pastespecial to cell f5.
That leaves the range("a5").copy command as the bad actor when the copy fails which is weird. It's as if copy works as long as the data are kept inside the spreadsheet but fails to update the external clipboard consistently.
That observation led me to try setting application.cutcopymode to xlcopy, true and false to see if that helped. The only effect I saw from trying all the settings is whether I saw f5 get highlighted with a marquee or not - none of the setting forced a copy to the external clipboard.
I tried waiting for a clock tick before copying to see if something was clearing the clipboard following the copy if it was time to update the clock. That appeared to help somewhat but, again not consistently.
So why does the copy fail to always update the clipboard? And why does it not work when it doesn't and does when it does? Even better, how can I modify this code so it always exports to the external clipboard?

Try using this method, it's always reliable for me
Dim TimeInClip As MSForms.DataObject
Set TimeInClip = New MSForms.DataObject
TimeInClip.SetText Range("A1").Value
TimeInClip.PutInClipboard

Try
Sub copyTime()
Range("a1").Copy ' copy time
Range("f5").PasteSpecial xlPasteValues ' strip formatting
Application.CutCopyMode = False ' Clear Excel clipboard
Range("f5").Copy ' copy time as text
DoEvents ' hack to attempt to make copy work consistently
End Sub
You said that you tried Application.CutCopyMode, but have you tried it that way?
It only forces the application to clear the clipboard before copying something else, which should then copy properly on the fresh clipboard.

Related

Automatically Show ShapeSheet of Current Shape

I do a lot of Visio ShapeSheet editing and it would save me a tremendous amount of time to automatically switch to the current shape's sheet when I select a new shape. Let's assume I only have 1 ShapeSheet open, only select 1 Shape, and have all the windows docked on the Visio app (I don't have RegEdit powers to change this).
So far, I've got the following VBA code in ThisDocument:
Private WithEvents vsoWin as Visio.Window
Private Sub ThisDocument_RunModeEntered(ByRef doc as IVDocument)
'Just assume this is the correct window
Set vsoWin = ActiveWindow
End Sub
Private Sub vsoWin_SelectionChanged(ByRef win as IVWindow)
'If nothing is selected, leave
If vsoWin.Selection.Count < 1 Then Exit Sub
'Look for a ShapeSheet (Window.SubType = 3)
For each oWin in Application.Windows
If oWin.Subtype = 3 Then
Application.ScreenUpdating = False 'Pause screen to prevent jitter
oWin.Close 'Delete old ShapeSheet
vsoWin.Selection(1).OpenSheetWindow 'Make new ShapeSheet
Application.ScreenUpdating = True 'Update visuals
Exit For 'Stop looking for ShapeSheets
End If
Next
Exit Sub
(The above code is written from memory since I don't have access to Visio at the moment. Please forgive any minor errors)
This code works, but I'm hoping for a less jittery result. Application.ScreenUpdating = False doesn't seem to do anything in this case: I still briefly witness the old ShapeSheet closing, the drawing window resizing, then the new ShapeSheet opening. Swapping the order (open new window > close old window) is a little less chaotic, but not great. Using Application.Minimize to hide the swap instead is slightly better on the eyes, but still not a smooth transition.
My question: Is there a smoother way to display the active shape's ShapeSheet?
This code works at my side! I just add variable which related with Visio Application - vsoApp.
Private WithEvents vsoWin As Visio.Window
Private WithEvents vsoApp As Visio.Application
Sub st()
Set vsoWin = ActiveWindow ' initialize Window variable
Set vsoApp = Application ' initialize Application variable
End Sub
Private Sub ThisDocument_RunModeEntered(ByRef doc As IVDocument)
'Just assume this is the correct window
Set vsoWin = ActiveWindow
End Sub
Private Sub vsoApp_SelectionChanged(ByVal Window As IVWindow)
'If nothing is selected, leave
If vsoWin.Selection.Count < 1 Then Exit Sub
'Look for a ShapeSheet (Window.SubType = 3)
For Each oWin In Application.Windows
If oWin.SubType = 3 Then
Application.ScreenUpdating = False 'Pause screen to prevent jitter
oWin.Close 'Delete old ShapeSheet
vsoWin.Selection(1).OpenSheetWindow 'Make new ShapeSheet
Application.ScreenUpdating = True 'Update visuals
Exit For 'Stop looking for ShapeSheets
End If
Next
End Sub
My workaround:
Press Alt+F8 keys and run St sub-routine.
Open ShapeSheet window for selected shape.
Select another shapes and so on...
Update with your code i get error like this.

VBA code conflict

I know, I am asking an unusual question. But, please do help me.
I have a below code on Workbook that will take care of copy/paste data on sheets. It would allow me to paste data into the cells without changing format(past only values).
Basically, the code will use destination formatting. similar to "paste values". It would allow the user to paste data from any other format. So that format is consistent across sheets.
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim vNewValues as Variant
NewValues = Target
Application.EnableEvents = False
Application.Undo
Target = NewValues
Application.EnableEvents = True
End Sub
Along with above code, I also have another code on the sheet that will help me to clear the contents and code is linked to a button. So, when the button is pressed it will clear the contents of the sheet.
Private Sub ResetKey_Click()
If MsgBox("Content of the sheet will be deleted and cannot be restored", vbOKCancel + vbInformation) = vbOK Then
Worksheets("User").Range("E19:I3018").ClearContents
Else
Exit Sub
End If
End Sub
Concern: I see a conflict between these codes. Because, when I click on the button I get the error that will point me to Application.Undo in the first code. I tried debugging the code but I was not able to get both to work. Please Suggest.
This will work:
Private Sub ResetKey_Click()
If MsgBox("Content of the sheet will be deleted and cannot be restored", vbOKCancel + vbInformation) = vbOK Then
Application.EnableEvents = False
Worksheets("User").Range("E19:I3018").ClearContents
Application.EnableEvents = True
Else
Exit Sub
End If
End Sub
That is, you have to suppress the Change event in other macros working on that sheet. Not elegant but doable.
To clarify what the first macro does: it saves the cell's content, undoes a user's paste or input, and then only fills in the value which was pasted, leaving the format intact. The problem with this approach is that the event handler does not return information on the action that triggered it - it could be a paste but clearing cells as well.
You can only use .Undo to undo the last action in the worksheet not to undo vba actions and must be the first line in the macro. As explained in the documentation.Application.Undo. Quote below:
This method undoes only the last action taken by the user before
running the macro, and it must be the first line in the macro. It
cannot be used to undo Visual Basic commands.

Running excel macros only on one sheet

Hi Iam new to writing VBA code and need assistance. My VBA code and Macro works fine as long as I am on the active sheet.
My Problem:
My VBA code and macro, stops running automatically, when i change from the active sheet to another within the same workbook and
My VBA code and macro, stops running automatically, when i open a new excel workbook
Solution required:
Run the VBA code and macro only on desired worksheet and prevent it from running on other worksheets and workbooks.
Background:
I have an excel file, named "Net Weight" with two sheets. sheet 1 is named : "weight", sheet 2: is named "base data".
sheet 1 is used as a user input form.
In sheet 1- cell B1 : user will type in a product code , in cell E1: a look up formula will place the description of the product code using the data from sheet 2
I have setup a VBA code and macro that does the following:
As soon as a user inputs a product code into cell B1, in sheet 1, sheet 1 is saved as PDF file into a predefined folder location data from cell B1 and E1
A macro saves and overwrties the PDF file every 10 seconds.
This process is repeated every time a new product code is entered
There are no buttons on sheet 1, everything is done automatically.
Here is my current code:
Sheet 1: set as Worksheet
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$B$1" Then
Call Macro1
End If
End Sub
Module 1 macro : set as general
Sub Macro1()
Application.DisplayAlerts = False
If ThisWorkbook.Name = "Nett Weight.xlsm" And ActiveSheet.Name = "Weight" Then
Sheets("Weight").ExportAsFixedFormat Type:=xlTypePDF, _
Filename:="C:\Nett weight\" & Range("B1 ").Text & Range(" E1").Text
Application.OnTime Now + TimeValue("00:00:10"), "Macro1"
Else
Exit Sub
End If
End Sub
First, you need to create a public variable to hold your timer, otherwise you'll never be able to cancel it so it will continue trying to fire even when your workbook is closed. You should also create a public variable to store when the timer is running, so you can check before creating a new timer.
At the top of a code module put:
Public nextTime As Date
Then in your Workbook_BeforeClose() event method (within ThisWorkbook), disable the existing timer so it doesn't keep trying to fire after the workbook is closed.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
On Error Resume Next ' Continue with next line of code if we encounter an error
Application.OnTime Earliesttime:=nextTime, Procedure:="Macro1", Schedule:=False
On Error GoTo 0 ' Resume error-trapping
End Sub
In Macro1() you should explicitly and directly reference your workbook components - ThisWorkbook always refers to the workbook the code is running from, so you don't need your If statement. Then you set the nextTime and activate the timer using that variable if it is not already running.
Sub Macro1()
Dim sht As Worksheet ' Creates a variable to hold your Weight worksheet
Set sht = ThisWorkbook.Sheets("Weight") ' Sets the reference
Application.DisplayAlerts = False
sht.ExportAsFixedFormat Type:=xlTypePDF, Filename:="C:\Nett weight\" & sht.Range("B1").Text & sht.Range("E1").Text ' Remember to preceed Range with sht. to explicitly reference the range of your Weight worksheet
On Error Resume Next ' Continue with next line of code if we encounter an error
Application.OnTime Earliesttime:=nextTime, Procedure:="Macro1", Schedule:=False
On Error GoTo 0 ' Resume error-trapping
nextTime = Now + TimeSerial(0, 0, 10) ' Adds 10 seconds to Now
Application.OnTime Earliesttime:=nextTime, Procedure:="Macro1", Schedule:=True
timerIsRunning = True
Application.DisplayAlerts = True ' Remember to enable alerts at the end of code
End Sub
Your Worksheet_Change() event method can stay as is. Now if there is a change in B1 it will call Macro1(). Macro1() will save the Weight worksheet as a PDF regardless of whether the workbook or worksheet is active, and create a new timer to re-run Macro1() every 10 seconds after deactivating an existing timer. When you're finished with the workbook, you close it and the existing timer is also deactivated.
EDIT:
Fortunately (as it fixes a spreadsheet of my own) I have figured out why the solution I originally provided wasn't working. Placing the Public variables under ThisWorkbook meant they no longer held their values after code execution. The remedy was to place them in a module instead. Once that was sorted out, I also realised that when the timer fires to call Macro1() it will throw an error when trying to unschedule the existing timer (as none exists unless Macro1() was called ad hoc by the Worksheet_Change() event).
Long story short: Public variables have been moved to a code module, and the timerIsRunning flag has been removed entirely and errors when attempting to unschedule the timer are simply ignored in the event that no timer exists.

Excel: Recalculating every x seconds

One of my spreadsheets deals with various calculations involving, among other things, the current date and time and it would be nice to have it automatically refresh itself once in a while instead of manually having to either press F9 or altering one of the cells.
Is there some way in Excel to set a spreadsheet to automatically recalculate itself every x seconds?
I haven't been able to find a setting in Excel itself, perhaps indicating that no such feature exists. If not, can this be achieved with VBA? (The latter may or may not sound like a silly question, but I have no prior experience with writing Excel macros and as such have no idea what its capabilities are in terms of manipulating spreadsheets.)
This code will create a clock, updated every 10 seconds.
Note that it only refreshes specific cells, and not the entire workbook - this means that you can leave the calculation options at whatever you are happy with:
Dim SchedRecalc As Date
Sub Recalc()
'Change specific cells
Range("A1").Value = Format(Now, "dd-mmm-yy")
Range("A2").Value = Format(Time, "hh:mm:ss AM/PM")
'or use the following line if you have a cell you wish to update
Range("A3").Calculate
Call StartTime ' need to keep calling the timer, as the ontime only runs once
End Sub
Sub StartTime()
SchedRecalc = Now + TimeValue("00:00:10")
Application.OnTime SchedRecalc, "Recalc"
End Sub
Sub EndTime()
On Error Resume Next
Application.OnTime EarliestTime:=SchedRecalc, _
Procedure:="Recalc", Schedule:=False
End Sub
and, to make sure it stops, in the This Workbook module:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
EndTime
End Sub
Goto Developer Visual basic Editor - Right Click workbook - insert module (make sure you have manual calculation
in the module
Sub run_over
Timetorun = Now + timevalue("00:00:10")
application.ontime timetorun,"Refresh_all"
End Sub
Sub Refresh_all
Activeworkbook.Refreshall
End Sub
Sub auto_close()
Application.OnTime timetorun, Refresh_all, , False
End Sub
Change the timing in "00:00:00" format as required

Excel macro doesn't update correctly

i have created macro for excel but it seems somewhere i have done something wrong,
i want to fetch an image from a URL and then update it up to 1 second (more or less)
Sub GetPicture()
PictureURL = "This is where i put the URLi want"
Set MyPict = ActiveSheet.Pictures.Insert(PictureURL)
Cells(1).Value = Now
nextTime = Now + TimeValue("00:00:01")
End Sub
when i run the macro doesn't do anything,only when i press f5 the it updates as fast as i press f5,also what is the value to update less than 1 second ("00:00:01"),when i try ("00:00:0.5") it comes up with "run time error 13" "type mismatch"
Any help is very much apreciated.
In Excel, you can use VBA to trigger code that updates a Worksheet on specific intervals. The code below shows how you would activate a Timer each time the Worksheet is activated by a user. Whenever the Timer fires (on 1 second intervals here) this code updates Cell A1 in the ActiveSheet with the current Time.
To further customize, you would add code to the OnTimerMacro in order to update a Picture or whatever else you recurring task might be.
(Props to Hartmut Gierke for his post on the topic.)
Option Explicit
Dim Execute_TimerDrivenMacro As Boolean
Sub Start_OnTimerMacro()
Execute_TimerDrivenMacro = True
Application.OnTime Time + TimeValue("00:00:01"), ActiveSheet.Name & ".OnTimerMacro"
End Sub
Sub Stop_OnTimerMacro()
Execute_TimerDrivenMacro = False
End Sub
Public Sub OnTimerMacro()
If Execute_TimerDrivenMacro Then
' Do something e.g. put the actual time into cell A1 of the active sheet
ActiveSheet.Cells(1, 1).Value = Time
' At the end restart timer
Application.OnTime Time + TimeValue("00:00:01"), ActiveSheet.Name & ".OnTimerMacro"
End If
End Sub
Private Sub Worksheet_Activate()
'Start the timer driven method when opening the sheet
Start_OnTimerMacro
End Sub
Private Sub Worksheet_Deactivate()
'Stop the timer driven method when opening the sheet
Stop_OnTimerMacro
End Sub
if you would like the macro to repeat you have to put it in a do...until loop. The only problem, is that you can't really have the macro run all the time. There has to be a way to stop it. The do...until loop will help with this, but you have to come up with a reasonable exit from the loop. Can you give a little more background as to what you ultimately want this to do?
Also it sounds like you want the running of the macro to be triggered by something other than the pressing of F5. Can you explain when you would like to see it start?