OpenOffice.org Forum at OOoForum.orgThe OpenOffice.org Forum
 
 [Home]   [FAQ]   [Search]   [Memberlist]   [Usergroups]   [Register
 [Profile]   [Log in to check your private messages]   [Log in

cell object from string "sheet.cell" reference
Goto page 1, 2  Next
 
Post new topic   Reply to topic    OOoForum.org Forum Index -> OpenOffice.org Macros and API
View previous topic :: View next topic  
Author Message
LethalCorpse
General User
General User


Joined: 16 Jun 2006
Posts: 9

PostPosted: Fri Jun 16, 2006 4:51 am    Post subject: cell object from string "sheet.cell" reference Reply with quote

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
View user's profile Send private message
pitonyak
Administrator
Administrator


Joined: 09 Mar 2004
Posts: 3152
Location: Columbus, Ohio, USA

PostPosted: Fri Jun 16, 2006 11:15 am    Post subject: Reply with quote

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
View user's profile Send private message Send e-mail Visit poster's website AIM Address
Villeroy
Super User
Super User


Joined: 04 Oct 2004
Posts: 7649
Location: Germany

PostPosted: Fri Jun 16, 2006 11:38 am    Post subject: Reply with quote

@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
View user's profile Send private message
LethalCorpse
General User
General User


Joined: 16 Jun 2006
Posts: 9

PostPosted: Fri Jun 16, 2006 8:49 pm    Post subject: Reply with quote

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
View user's profile Send private message
pitonyak
Administrator
Administrator


Joined: 09 Mar 2004
Posts: 3152
Location: Columbus, Ohio, USA

PostPosted: Fri Jun 16, 2006 9:26 pm    Post subject: Reply with quote

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
View user's profile Send private message Send e-mail Visit poster's website AIM Address
Villeroy
Super User
Super User


Joined: 04 Oct 2004
Posts: 7649
Location: Germany

PostPosted: Sat Jun 17, 2006 7:18 am    Post subject: Reply with quote

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
View user's profile Send private message
LethalCorpse
General User
General User


Joined: 16 Jun 2006
Posts: 9

PostPosted: Tue Jun 20, 2006 7:26 am    Post subject: Reply with quote

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
View user's profile Send private message
Villeroy
Super User
Super User


Joined: 04 Oct 2004
Posts: 7649
Location: Germany

PostPosted: Tue Jun 20, 2006 10:36 am    Post subject: Reply with quote

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
View user's profile Send private message
LethalCorpse
General User
General User


Joined: 16 Jun 2006
Posts: 9

PostPosted: Wed Jun 21, 2006 12:07 am    Post subject: Reply with quote

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
View user's profile Send private message
LethalCorpse
General User
General User


Joined: 16 Jun 2006
Posts: 9

PostPosted: Fri Jun 23, 2006 4:54 am    Post subject: Reply with quote

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
View user's profile Send private message
pitonyak
Administrator
Administrator


Joined: 09 Mar 2004
Posts: 3152
Location: Columbus, Ohio, USA

PostPosted: Fri Jun 23, 2006 5:01 am    Post subject: Reply with quote

What happens if you set a style to the cell for the formatting?
_________________
--
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
View user's profile Send private message Send e-mail Visit poster's website AIM Address
LethalCorpse
General User
General User


Joined: 16 Jun 2006
Posts: 9

PostPosted: Fri Jun 23, 2006 5:09 am    Post subject: Reply with quote

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
View user's profile Send private message
LethalCorpse
General User
General User


Joined: 16 Jun 2006
Posts: 9

PostPosted: Fri Jun 30, 2006 12:31 am    Post subject: Reply with quote

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
View user's profile Send private message
pitonyak
Administrator
Administrator


Joined: 09 Mar 2004
Posts: 3152
Location: Columbus, Ohio, USA

PostPosted: Fri Jun 30, 2006 5:27 am    Post subject: Reply with quote

Can you

1. post the spreadsheet
2. Privide simple instructions on what to do that indicate what happens and what you wanted to happen.

For example:

Place the cursor in sheet1 cell B2
Enter the value 8.5 and press enter

The following happens:

But I wanted the following to happen:
_________________
--
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
View user's profile Send private message Send e-mail Visit poster's website AIM Address
LethalCorpse
General User
General User


Joined: 16 Jun 2006
Posts: 9

PostPosted: Fri Jun 30, 2006 6:18 am    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    OOoForum.org Forum Index -> OpenOffice.org Macros and API All times are GMT - 8 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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