| View previous topic :: View next topic |
| Author |
Message |
LethalCorpse General User

Joined: 16 Jun 2006 Posts: 9
|
Posted: Fri Jun 16, 2006 4:51 am Post subject: cell object from string "sheet.cell" reference |
|
|
I do feel fairly helpless posting a question like this, because I'm a programmer and it irks me when I don't automatically know how to use a new language. But I've searched google and this forum and a number of other places and can't seem to find any references to what I'm hoping to achieve - I suspect because I can't come up with the right search terms, not because the information isn't out there. Ordinarily I'd learn how to write macros from top to bottom, but I've been given two days to write this spreadsheet and can't afford to take that time. So I'll just go ahead and post the question and hope I don't get flamed too badly.
I've got a spreadsheet which takes time values in 24hr format as data entry. At present it stops on data validity if anything other than a 24 hour time is entered. I need to allow the users to enter time as floats, eg 8.5 instead of contorting their fingers to find the colon and write 8:30. Seems like a small difference, but when you've got a few thousand timeslots to enter...
Anyway, what I want it to do is execute a macro on a validity error which checks that the user has entered a float between 0 and 24 and converts it to a time format, eg 8.5 -->8:30, and then dumps that back into the cell which had the validity error. I've managed to make it call a macro using the | Code: | | Function ExampleValidity(CellValue as String, TableCell as String) | example given in the help file. So, now I'm in a macro with the two variables I need - the value entered and the cell location. Ripper! I think I can probably handle converting the string value to a float, checking that it's valid (and notifying if not) then converting that to a time. What I can't manage is converting the cell location string into a cell object.
When data validity calls a macro it passes in the cell value and cell reference, including the sheet name, as strings. GetCellByName() requires that you already have the sheet object, and that your cell string only contains a cell reference (not sheet.cell). Do I need to manipulate that string to separate the sheet name and cell location into two separate strings, then getSheetByName() and getCellByName(), or is there an easier way?
Once I've got the cell object, do I use | Code: | | oCell.setValue(fTime) | or will this kill the formatting? For example, my code will modify an entry of "8" for 8 am to "0.333333333" which is the decimal representation of 8am. Do I need to fiddle this back into a time string, or will the fact that it's already formatted as HH:MM cover me here?
Any help you guys could give me, even pointing me at the right openoffice basic reference, would be greatly appreciated.
Cheers,
-Iain |
|
| Back to top |
|
 |
pitonyak Administrator


Joined: 09 Mar 2004 Posts: 3152 Location: Columbus, Ohio, USA
|
Posted: Fri Jun 16, 2006 11:15 am Post subject: |
|
|
What have you managed to accomplish so far? My understanding of your problem is that you want to have the following:
User chooses a cell, any cell.
User enters anything into the cell.
The macro is called auto-magically.
The macro inspects the value and then decides to either ignore the value or change it to a time.
If the macro is called auto-magically, then you must use an event listener. have you figured out how to do that yet?
Also, realize that a time value IS stored as a numerical value already, so you might need to use "trickery" to figure out what was actually entered. _________________ --
Andrew Pitonyak
My Document: http://www.pitonyak.org/AndrewMacro.odt
Free Info: http://www.pitonyak.org/oo.php
Most hated bug: http://www.openoffice.org/issues/show_bug.cgi?id=84159 |
|
| Back to top |
|
 |
Villeroy Super User


Joined: 04 Oct 2004 Posts: 7649 Location: Germany
|
Posted: Fri Jun 16, 2006 11:38 am Post subject: |
|
|
@Andrew
You don't have to use listeners, when you specify a script event in the validation dialog.
@Lain
I would not write a macro for this task.
Set the validity of the unprotected input-cells to number between 0 and 24.
Then add a column for display of the converted time values.
=Input/24
Format as time.
When I need to write a time-constant into a cell, I use:
dtValue = cDate( dblValue )
oTargetCell.FormulaLocal = cStr(dtValue)
Setting string-property FormulaLocal is like typing the string into the formula bar. This works language independant, BUT the spreadsheet's null-date must be 1899-12-30 which is the default (see Tools>Options>Calc>Calculation>NullDate). StarBasic always uses 1899-12-30 as null-date when you convert a number to date. _________________ XUbuntu 9.04, OOo 3.1.1(Sun), Sun Java 1.5.0_06 |
|
| Back to top |
|
 |
LethalCorpse General User

Joined: 16 Jun 2006 Posts: 9
|
Posted: Fri Jun 16, 2006 8:49 pm Post subject: |
|
|
| thanks villeroy, that's very helpful - gets through all the formatting probs. Now all i need to know is how to convert a string "sheet1.a1" reference into a cell object that i can manipulate |
|
| Back to top |
|
 |
pitonyak Administrator


Joined: 09 Mar 2004 Posts: 3152 Location: Columbus, Ohio, USA
|
Posted: Fri Jun 16, 2006 9:26 pm Post subject: |
|
|
You probably need to
1. parse the sheet name from the cell name.
2. Get the sheet by name.
3. Get the cell from the sheet by name.
Then again, if you do not really need to obtain the cell, you should be able to use the full name directly if it is used in an equation. Without error checking, it will look something like this:
| Code: | Dim s$
Dim nLoc As Integer
Dim oCell
Dim oSheet
s$ = "Sheet1.C2"
nLoc = InStr(s$, ".")
oSheet = ThisComponent.getSheets().getByName(Left(s$, nLoc-1))
oCell = oSheet.getCellRangeByName(Mid(s$, nLoc + 1)) |
_________________ --
Andrew Pitonyak
My Document: http://www.pitonyak.org/AndrewMacro.odt
Free Info: http://www.pitonyak.org/oo.php
Most hated bug: http://www.openoffice.org/issues/show_bug.cgi?id=84159 |
|
| Back to top |
|
 |
Villeroy Super User


Joined: 04 Oct 2004 Posts: 7649 Location: Germany
|
Posted: Sat Jun 17, 2006 7:18 am Post subject: |
|
|
| LethalCorpse wrote: | | thanks villeroy, that's very helpful - gets through all the formatting probs. Now all i need to know is how to convert a string "sheet1.a1" reference into a cell object that i can manipulate |
I tested the validation by macro for the first time and noticed that this is very useful even if you don't actually want to validate the cell.
| Code: |
Function onCellValidation(sVal$,sAdr$)
print sVal,sAdr
onCellValidation = TRUE
End Function
|
This provides a cell-modify listener with information about the calling cell (FormulaLocal to be entered and string-address)
If the function returnes FALSE then the input will be rejected.
That's very interesting.
This is my set of function for getting a range from string-identifiers:
| Code: |
REM---------------------------------other stuff-----------------------------
'this is something like oSpreadSheetDoc.getCellRangeByName($mySheet.$A$1:$C$1000)
'param:=strAddress needs to be an address or a named range, both referring to a range with explicit sheetname
'would be usefull to pass another param oCell as base-ref for relative addresses -- some day
Function getRangeFromString(oDoc,strAddress)
on error goto errHopeless
Dim oSh as Object,oRg
if oDoc.namedRanges.HasByName(strAddress) then
oRg = oDoc.namedRanges.getByName(strAddress).getReferredCells
if (Not isNull(oRg)) then getRangeFromString = oRg
elseif oDoc.DatabaseRanges.HasByName(strAddress) then
getRangeFromString = oDoc.DatabaseRanges.getByName(strAddress).getReferredCells
else
oSh = getSheetFromStringAddress(oDoc,strAddress)
'this will throw error if strAddress like "validSheetName.somethingNotAddressable"
if VarType(oSh) = 9 then getRangeFromString = oSh.getCellRangeByName(strAddress)
Endif
errHopeless:
End Function
Function getSheetFromStringAddress(oDoc,strAddress)
Dim iPoint%,iCrit%,sResult$,oSh
iCrit = 1
if left(strAddress,1)= "$" then iCrit = 2
iPoint = instr(iCrit,strAddress,".")
if iPoint > iCrit then
sResult = mid(strAddress,iCrit,iPoint - iCrit)
if oDoc.Sheets.hasByName(sResult) then oSh = oDoc.Sheets.getByName(sResult)
elseif oDoc.namedRanges.HasByName(strAddress) then
oSh = oDoc.namedRanges.getByName(strAddress).getReferredCells
'referred cells are Null if the name refers to a constant, a formula or to an address without specified absolut $sheet
if not isNull(oSh) then oSh = oSh.getSpreadSheet
elseif oDoc.DatabaseRanges.HasByName(strAddress) then
oSh = oDoc.DatabaseRanges.getByName(strAddress).getReferredCells.getSpreadSheet
End If
getSheetFromStringAddress = oSh
End Function
|
_________________ XUbuntu 9.04, OOo 3.1.1(Sun), Sun Java 1.5.0_06 |
|
| Back to top |
|
 |
LethalCorpse General User

Joined: 16 Jun 2006 Posts: 9
|
Posted: Tue Jun 20, 2006 7:26 am Post subject: |
|
|
Okay, I'm almost there guys. Here is my current code:
| Code: |
Function ReplaceHours(sCellValue as String, sTableCell as String)
Dim nLoc As Integer
Dim oCell
Dim oSheet As Object
Dim oDoc As Object
Dim dCellValue as Double
Dim dTimeValue as Double
Dim dtTimeValue as Date
Dim sSheet as String
Dim sCell as String
oDoc = ThisComponent
'nLoc = InStr(sTableCell, ".")
'oSheet = getSheetFromStringAddress(oDoc,sTableCell)
'sSheet = Left(sTableCell, nLoc - 1)
'sCell = Mid(sTableCell, nLoc + 1)
'oSheet = oDoc.Sheets.getByName(sSheet)
'oCell = oSheet.getCellRangeByName(sCell)
oCell = getRangeFromString(oDoc, sTableCell)
dCellValue = val(sCellValue)
if (dCellValue = 0 and not instr(sCellValue, "0")) or dCellValue < 0 or dCellValue >= 24 Then
MsgBox "Error: please enter a time between 0:00 and 23:59"
oCell.formulalocal = ""
goto errexit
end if
dTimeValue = dCellValue/24
dtTimeValue = cDate(dTimeValue)
oCell.formulalocal = dtTimeValue
errexit:
End Function
Function getRangeFromString(oDoc, sTableCell)
on error goto errHopeless
Dim oSh as Object,oRg
if oDoc.namedRanges.HasByName(sTableCell) then
oRg = oDoc.namedRanges.getByName(sTableCell).getReferredCells
if (Not isNull(oRg)) then getRangeFromString = oRg
elseif oDoc.DatabaseRanges.HasByName(sTableCell) then
getRangeFromString = oDoc.DatabaseRanges.getByName(sTableCell).getReferredCells
else
oSh = getSheetFromStringAddress(oDoc,sTableCell)
'this will throw error if strAddress like "validSheetName.somethingNotAddressable"
if VarType(oSh) = 9 then
getRangeFromString = oSh.getCellRangeByName(sTableCell)'.getCellByPosition(0,0)
Endif
Endif
errHopeless:
End Function
Function getSheetFromStringAddress(oDoc,sTableCell)
Dim iPoint%,iCrit%,sResult$,oSh
iCrit = 1
if left(sTableCell,1)= "$" then iCrit = 2
if instr(sTableCell,"'") then icrit = icrit + 1
iPoint = instr(iCrit,sTableCell,".")
if instr(stableCell,"'") then iPoint = ipoint - 1
if iPoint > iCrit then
sResult = mid(sTableCell,iCrit,iPoint - iCrit)
msgbox sresult
if oDoc.Sheets.hasByName(sResult) then oSh = oDoc.Sheets.getByName(sResult)
elseif oDoc.namedRanges.HasByName(sTableCell) then
oSh = oDoc.namedRanges.getByName(sTableCell).getReferredCells
'referred cells are Null if the name refers to a constant, a formula or to an address without specified absolut $sheet
if not isNull(oSh) then oSh = oSh.getSpreadSheet
elseif oDoc.DatabaseRanges.HasByName(sTableCell) then
oSh = oDoc.DatabaseRanges.getByName(sTableCell).getReferredCells.getSpreadSheet
End If
getSheetFromStringAddress = oSh
End Function
|
I've done a lot of fiddling about with this code trying to diagnose the problems with it. As you can see from the commented section, I've tried it with both your suggestions - It turns out they both work fine to obtain the cell reference, but either way I've now got a different problem. After putting in a whole heap of debugging output I now think I've got it pinned down. My first major problem came from the fact that my sheet names had spaces in them, and so the string passed by the validity checker had single quotes around the sheet name. Neither of your code snippets handled this, so I changed my sheet name for much of the debugging, and I've now modified Villeroy's code to handle the presence of single quotes around a sheet name. For a long time I thought it just wasn't getting the cell reference correctly, which is why I was trying both your code snippets with heavy modification. Then I found I was able to display the current contents of the cell in a messagebox (without using the value passed in) so it was obviously getting the cell reference no problem. But every time I pressed enter on the cell, whatever I had just typed stayed there. I tried changing the sCellTable string to some other cell, and it worked fine - modified the data and dumped it in the other cell. What I think it's doing is running the macro before it's left the cell, then once it's finished running my macro it executes the enter/tab key and overwrites whatever my macro has written in with whatever was typed. I need to make it execute that move first, so that nothing occurs after my macro runs. I thought about telling the macro to move the cursor down then up one, then down again afterwards, but this will only work if the user has pressed enter, not tab (or home, or clicked on another cell, or any of the other things they can do to leave a cell). I want the cursor to end up where the user tells it to. Any thoughts? |
|
| Back to top |
|
 |
Villeroy Super User


Joined: 04 Oct 2004 Posts: 7649 Location: Germany
|
Posted: Tue Jun 20, 2006 10:36 am Post subject: |
|
|
Thank you for using and enhancing my code. Sorry, none of my spreadsheets has spaces in names. I avoid it consequently. So I did not think about this possibility. When you call Function ReplaceHours(sCellValue as String, sTableCell as String) from a validation event, your function needs to return true in order to accept sCellValue. For clarity "sCellValue" should be named "sFormulaLocal" because property FormulaLocal will be set if your validation-function returns true.
| Code: |
Function ReplaceHours(sFormulaLocal as String, sTableCell as String) As Boolean
[...your code...]
if (dCellValue = 0 and not instr(sCellValue, "0")) or dCellValue < 0 or dCellValue >= 24 Then
MsgBox "Error: please enter a time between 0:00 and 23:59"
oCell.formulalocal = ""
goto errexit
else
ReplaceHours = true 'added the else-condition
end if
[...your code...]
End Function |
_________________ XUbuntu 9.04, OOo 3.1.1(Sun), Sun Java 1.5.0_06 |
|
| Back to top |
|
 |
LethalCorpse General User

Joined: 16 Jun 2006 Posts: 9
|
Posted: Wed Jun 21, 2006 12:07 am Post subject: |
|
|
Didn't help. I tried putting it in and outside the if structure, but the value in the cell still stayed the same as what I'd typed.
BTW I've noticed your usage of $ and % signs in the variable names. I first thought this was just naming convention, like putitng s at the start, but then I noticed that you've referred to the same variable with and without the $. Is it just type casting (as in a short form of "As String" or "As Integer") or is it similar to pointers in C? |
|
| Back to top |
|
 |
LethalCorpse General User

Joined: 16 Jun 2006 Posts: 9
|
Posted: Fri Jun 23, 2006 4:54 am Post subject: |
|
|
| No further thoughts on this one? I'm almost over the line, just can't make it dump text into the cell without the typed value overriding. Would it help if I publish the spreadsheet, not jsut the code? |
|
| Back to top |
|
 |
pitonyak Administrator


Joined: 09 Mar 2004 Posts: 3152 Location: Columbus, Ohio, USA
|
|
| Back to top |
|
 |
LethalCorpse General User

Joined: 16 Jun 2006 Posts: 9
|
Posted: Fri Jun 23, 2006 5:09 am Post subject: |
|
|
| Doesn't do anything I'm afraid. The formatting is all fine - if a date value is typed into the cell, it's formatted correctly. If I hard code the target cell to any other reference than the one which called the macro, it works fine - will take, say, 21.5 entered in one cell, convert that to 21:30, paste 21:30 into the target cell, and it's formatted correctly. But if the target cell is the one that called the macro, it doesn't work. What it appears to be doing is running the macro before it processes my "return" keystroke, or tab, or clicking somewhere else in the spreadsheet. So, my macro takes the entered value runs, and happily sets the cell contents to the changed value. But then, once the macro returns, OOo executes my return keystroke, setting the cell contents to whatever it was I typed. What I need is some way to either prevent it doing this, or do it before the macro runs |
|
| Back to top |
|
 |
LethalCorpse General User

Joined: 16 Jun 2006 Posts: 9
|
Posted: Fri Jun 30, 2006 12:31 am Post subject: |
|
|
| I've played with various return values (true, false, cellvalue etc) but to no avail. The only other way around it that I can see is to have three hidden cells elsewhere in the spreadsheet into which the replacehours macro places the cell location, adjusted cell contents and a change flag. Then I've got listener listening on all cells, which runs when any cell is selected, by mouse click, tab, enter, whatever. The listener checks if the flag has been set, then copies the adjusted cell contents into the cell location and clears the flag. This allows OOo to finish the replacehours macro, store the originally entered text into the cell and move into the next cell before the listener attempts to change the cell contents. Yes, this is incredibly roundabout, but I can't see any way in which to change the cell contents from the replacehours macro - OOo is always going to store the entered value in the cell after the macro returns. Unless anyone has any other suggestions on how to do this, that's what I'll have to do. |
|
| Back to top |
|
 |
pitonyak Administrator


Joined: 09 Mar 2004 Posts: 3152 Location: Columbus, Ohio, USA
|
|
| Back to top |
|
 |
LethalCorpse General User

Joined: 16 Jun 2006 Posts: 9
|
Posted: Fri Jun 30, 2006 6:18 am Post subject: |
|
|
No worries
Place the cursor in any of the white cells in the range A8:AB24.
Type "8:30", or any other time in 24 hour HH:MM format, and the entry should pass the validity test and be stored in the cell.
Type "8.5" or any other decimal value between 0 and 24. The value will fail the validity test, and the "ReplaceHours" macro will run.
After the macro has run, the value in the cell will be "8.5". I want the value in the cell after the macro has run to be the 24 hour representation of the entered value, ie "8.5" --> "8:30", "13.75" --> "13:45"
Using messagebox output it can be shown that the macro runs successfully, converts the cell location string into a cell object, and saves the adjusted value into the cell. It can also be shown that if you hard code a different cell location into the macro in place of the sTableCell which is passed in (I used sTableCell = "'Week 1'.B9") the macro has no problems converting the entered value into a time and saving it into the cell. It can't, however, save anything into the cell which called the validity macro. |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|