How to change a cell value periodically in libreoffice calc? - macros

The title says it all...
For example, if I want to have a cell which displays the current time and auto updates minute by minute (well, I think we call that a clock), how do I do it?
Is there a simple function implemented already or should I create a macro and assign it to a specific event?
EDIT: Following the provided answer by #Jim K, I want to be more clear about what I want. The "clock" example above was here to make it simple to understand, but what I really want is in the title: a cell value which changes periodically, be it a string, a number, a date...

First enter =NOW() in a cell, and format the number by going to Format -> Cells.
Next, this Basic macro (from here) recalculates every minute. Go to Tools -> Customize and assign it to the Open Document event.
Sub RecalculatePeriodically
Const secs = 60
On Error Goto ErrorHandler
Do While True
Wait(1000 * secs)
ThisComponent.calculateAll()
Loop
ErrorHandler:
'Document was probably closed
End Sub
However, this crashes when exiting LibreOffice. So instead, use the following threaded Python macro (like here). Assign keep_recalculating_thread to the Open Document event.
import time
from threading import Thread
import uno
def keep_recalculating_thread(action_event=None):
t = Thread(target = keep_recalculating)
t.start()
def keep_recalculating():
oDoc = XSCRIPTCONTEXT.getDocument()
while hasattr(oDoc, 'calculateAll'):
oDoc.calculateAll()
time.sleep(60)
g_exportedScripts = keep_recalculating_thread,
Another idea is at https://ask.libreoffice.org/en/question/5327/how-can-i-run-a-macro-at-regular-time-interval/, although it requires linking to another file which seems cumbersome.
EDIT:
Maybe you are looking for something like this? Test it by starting with a blank spreadsheet and entering 1 in cell A1.
def keep_changing_cell(action_event=None):
t = Thread(target = keep_changing_thread)
t.start()
def keep_changing_thread():
oDoc = XSCRIPTCONTEXT.getDocument()
oSheet = oDoc.CurrentController.ActiveSheet
COLUMN_A = 0
FIRST_ROW = 0
oCell = oSheet.getCellByPosition(COLUMN_A, FIRST_ROW)
while hasattr(oDoc, 'calculateAll'):
oCell.setValue(oCell.getValue() + 1)
time.sleep(2)

tl;dr
Is there a simple function implemented already
No.
From LibreOffice and fairly recent:
(I don't know a 'clock' property applying to cells.)
There are simple ways to obtain the time, for example given suitable formatting, with date:
=NOW()
or Ctrl+;
Or, for example, without date:
=MOD(NOW(),1)
The first and last will update, but only when the sheet is recalculated.
For a cell that ticks away (eg second by second) I believe you will need a script.

Related

Excel VBA Form - Update Labels based on cell value (Debug)

I have hard times trying to update labels in a VBA form based on Worksheet values in Excel.
The methods I've tried so far:
1st Take:
Sub Update_Label_FirstTime()
Label1.Caption = Sheets(1).Cells(1, 1)
End Sub
'Whenever I call the Macro for a second time It fails and VBA freezes my form
2nd Take
Private Sub UserForm_Activate()
call Update_Label
End Sub
Sub Update_Label()
Label1.Caption = Sheets(1).Cells(1, 1)
Application.OnTime Now() + TimeValue("00:00:01"), "Update_Label"
End Sub
' also tried Controls("Label1").Caption = Sheets(1).Cells(1, 1).Value
These are all stored and ran from within the UserForm code. Both codes work fine on 1st load/call but both break my form whenever I call them a second time.
Each time I call for these updates (after the initial values are loaded) the form freezes and the VBA window in popped-up without any code highlights or error messages.
I have used these methods before and had no such issues.
Any thoughts ?
Try moving Update_Label to a standard module.
You will need to reference the form in the code. You may also want to recalculate before getting the cell value.
Sub Update_Label()
Dim rng As Range
Set rng = Sheets(1).Cells(1, 1)
rng.Calculate
UserForm1.Label1.Caption = rng
Application.OnTime Now() + TimeValue("00:00:01"), "Update_Label"
End Sub

Debugging a for loop in matlab

I've been looking throught the documentation, but can't seem to find the bit I want.
I have a for loop and I would like to be able to view every value in the for loop.
for example here is a part of my code:
for d = 1 : nb
%for loop performs blade by blade averaging and produces a column vector
for cc = navg : length(atbmat);
atb2 = (sum(atbmat((cc-(navg-1):cc),d)))/navg;
atbvec2(:,cc) = atb2;
end
%assigns column vector 'atbvec2' to the correct column of the matrix 'atbmat2'
atbmat2(d,1:length(atbvec2)) = atbvec2;
end
I would like to view every value of atb2. I'm a python user(new to MATLAB) and would normally use a simple print statement to find this.
I'm sure there is a way to do it, but I can't quite find how.
Thankyou in advance.
you can use disp in Matlab to print to the screen but you might want to use sprintf first to format it nicely. However for debugging you're better off using a break point and then inspect the variable in the workspace browser graphically. To me, this is one of Matlab's best features.
Have a look at the "Examine Values" section of this article
The simplest way to view it everywhere is to change this line:
atb2 = (sum(atbmat((cc-(navg-1):cc),d)))/navg;
Into this, without semicolon:
atb2 = (sum(atbmat((cc-(navg-1):cc),d)))/navg
That being said, given the nature of your calculation, you could get the information you need as well by simply storing every value of abt2 and observing them afterwards. This may be done in atbmat2 already?
If you want to look at each value at the time it happens, consider setting a breakpoint or conditional breakpoint after the line where abt2 is assigned.

Frame only displaying last record in table

Hopefully this will be my last question for a while. I know there isn't much to be said about Progress's UI capability, but I'm having what seems to be a really strange problem with displaying in a frame.
Here is some pseudo code to help you understand the problem:
DEF TEMP-TABLE tMainTable.
DEF TEMP-TABLE tPage LIKE tMainTable.
DEF VAR iCursor AS INT.
/* SOME INPUT DETECTION */
/* Moving the cursor */
FIND FIRST tMainTable WHERE tMainTable.UniqueId EQ iCursor.
DO i = 1 TO iMaxPageSize:
CREATE tPage.
BUFFER-COPY tMainTable TO tPage.
END.
/* DISPLAY */
FOR EACH tPage:
DISPLAY tPage.iNumber tPage.Name.
END.
These are the basics of the program. Now the desired output, would have the FRAME displaying these to end right under the last entry. Currently, using the default FRAME, it scales to the bottom of the terminal screen.
Though, when I instantiate a FRAME and interchange all of the logical available options, I can get it to size to where I want it, but can't get it to display the entries in seperate lines. What it looks like it's doing instead, is displaying each entry on the same line, overwriting the last one, as it always shows the last record in the TEMP-TABLE.
I tried instantiating the FRAME "WITH iMaxPageSize DOWN", with no effect. After reading a little deeper on this particular option, it looks like it's only available for displaying multiple fields in a table, and not certain fields of multiple tables.
Hope this made sense, I really need help with this.
Figured it out, took me a cumulative of 8 hours of reading, and trial-and-error coding.
FOR EACH tPage WITH 6 DOWN:
Was all I needed.
It still bugs me that when I instantiated a FRAME, I could only ever get it to display one record despite using it in a FOR EACH.
you need to do something like this - the FIND / DO combination isn't doing what you think it is.
DEF TEMP-TABLE tMainTable.
DEF TEMP-TABLE tPage LIKE tMainTable.
DEF VAR iCursor AS INT.
DEF VAR i AS INT.
i = 0.
FOR EACH tMainTable
WHERE tMainTable.UniqueId EQ iCursor
NO-LOCK:
i = i + 1.
IF i > maxpagesize THEN
LEAVE.
CREATE tPage.
BUFFER-COPY tMainTable TO tPage.
END.
/* DISPLAY */
FOR EACH tPage:
DISPLAY tPage.iNumber tPage.Name
WITH DOWN.
END.

Is there a way to get the original value of a cell in onEdit()?

I'd like to know if there's a way to get the original value of the cell from within the onEdit() event.
For example:
Cell A1's current value is "hello"
I edit A1 it by changing it to "world"
Right now, when I try to get the value from the active range, I'd get "world"
But I would also like to have the possibility to get the original value, i.e. "hello". Is that currently possible?
You can use onEdit(e) and e.oldValue if you're dealing with a single cell. The example below adds the original value to A1 when any cell is edited. 'undefined' if the cell was blank.
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = sheet.getActiveCell();
var origValue = e.oldValue
sheet.getRange('A1').setValue(origValue);
}
The only code that would come close to this is to use an onOpen exit to save
the initial value. The initial value could be saved in several ways. There
are "user properties". I don't know how they work, yet. I am new to this.
You could also use a "hidden" sheet to save the value, in the "onOpen" exit.
There may be other ways, that I don't know about.
The problem becomes more difficult with an increasing number of cells for which
you want to save the original value.
By-the-way, you should understand that the "onOpen" routine fires at the time
the spreadsheet is opened. It so happens, that the end-user also has access and
can change cell values before the onOpen handler finishes its execution. You may
not capture all of your initial values.
One final thing you should know. The onEdit trigger is NOT fired when an UNDO or REDO
event occurs. The cell's contents could change and you will not know it.
I don't know how a validation routine works. If the routine rejects a value, will
the spreadsheet restore the original value? If it does, then this might get around
the onOpen problem. If it only tells the user the value is invalid, it will not be
of much help.
A really round about way that may work, but is very complicated is to save the image
before the spreadsheet closes. You post all the "after" images to a second spreadsheet.
Then in your onEdit handler you look at the corresponding cell in the other spreadsheet.
You then decide to restore the previous image or allow the new image to proceed.
Lastly a wild idea of using a data table in place of the second spreadsheet.
I am just learning about all of these concepts, so don't ask me how to implement them.
I just understand that they MIGHT be possible. For coding and support purposes they
may not be the best options. But since the current script service does not provide
before image access, it is about the best I could do. You have to understand that this
google interface is a client-server application. Your scripts run on the server. The data changes occur in the "clients" (end-users) browser.
One final note: the onEdit trigger does not fire for an UNDO or REDO change to a cell.
So the cell could change and your script is not aware of it.
I don't think that's possible.
I imagine you could get that functionality by having a exact copy of your sheet on a second sheet that updates automatically when your 'onEdit' functions ends.
Until that update, data on the second sheet will have the former value.
A bit tricky but why not ?-)
EDIT : seems to be the 'question of the day', see this post and Henrique Abreu's pertinent comment.
When you change the value of a cell diagrammatically, you can use the setComment method to store the original value as a comment in that cell.
What you basically need to do is to create a shadow sheet (which you can protect and hide or even have it in a totally separate spreadsheet) and use the IMPORTRANGE function to get the values of the original sheet into the shadow sheet (This gives enough delay time to get the old value that was in the cell before it got edited).
=IMPORTRANGE("enter your original sheet's ID","enter the range you wish to get from the sheet")
Please note that using this code, when editing multiple cells at the same time, the function will only work on the first cell.
function onEdit(){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var originalSheet = sheet.getSheetByName('Original');
var shadowSheet = sheet.getSheetByName('Shadow');
var editedCell = originalSheet.getActiveCell();
var cellColumn = editedCell.getColumn();
var cellRow = editedCell.getRow();
var oldValue = shadowSheet.getRange(cellRow, cellColumn).getValue();
var cellValue = editedCell.getValue();
var editorMail = Session.getActiveUser().getEmail(); \\getting the editor email
if ("The condition you want to meet for the onEdit function to activate"){
editedCell.setNote(editorMail + "\n" + new Date + "\n" + oldValue + " -> " + cellValue);
}
}

How to add operator signs '+,-,/,*,mod' etc to a label for making a calculator?

I have made a calculator for simple operations but I cant figure out how should I add the operator signs next to the numerals that I am entering.
I created 2 functions 1 on the number being entered
-(IBAction)buttonDigitPressed:(id)sender
and another for the operation
-(IBAction)buttonOperationPressed:(id)sender.
calculatorScreen.text = [NSString stringWithFormat:#"%.2f",result];
This is for the result to be shown on the label calculatorScreen.
The result i would like would be something like "1+2*3/4" on the calculatorScreen.
Sorry if I misunderstand your question, but what you want is to display on your calculator app the full equation that you've input thus far (e.g. 63+42-62).
Like any other calculator, you should have 2 label, one for your current input, and one to show all that you've entered.(I'm guessing you need the latter)
With the second label up, you can add in the append function into your digitpressed, enter/= function, operation function. If you want to tweak it such 16+23-32 will show up as
1) 16+23
2) 39-32
3) 39-32=7
then you'll have to add in your own specific code. otherwise the label will input as 16+23-32 = 7
You can just append the character to whatever is already on calculatorScreen. Or you can save the current input in an instance variable and display where appropriate.
This is just a guideline, since I don't know the behavior of your calculator in case of this input: 1 + 2 * 3 (simple calculator will return 9, scientific will return 7).