在libreoffice calc中,如何通过libreoffice Basic更改单元格在不崩溃的情况下设置为event侦听器的值?

发布于 2025-01-25 06:11:07 字数 2795 浏览 2 评论 0 原文

我正在尝试创建两个桌子,这些表会自动地互相反映它们的任何一个。

为此,我添加了当用户编辑这些表的单元格时触发的事件侦听器。

不幸的是,编辑其中一张表会导致Libreoffice崩溃,即使更改确实正确地反映了,如重新打开文件时所见。
我认为崩溃可能是由于无休止的循环引用,但是在将其制成非圆形后仍然崩溃(通过评论代码的相关部分,以便更改仅反映了一种方式而不是两种方式) 。
我注意到该代码在写入没有事件侦听器设置的单元格时工作正常。

我如何将一个设置在他们的事件侦听器崩溃的情况下写给其中一个单元格?

您可能需要下载以下文件。请运行MAIN,然后尝试编辑计划表的单元格C3。任意字符串“ C”应写入服务表的单元格C4。

这是代码的简化版本:

REM  *****  BASIC  *****

const SERVICESSHEET_NUMBER = 2
const SERVICESSHEET_SERVICES_COLUMN = 2

Type cellStruct
    columnNumber As Integer
    rowNumber As Integer
End Type



Sub UpdateServicesSheet(editedCell As cellStruct, newValue As String)
    
    Dim oSheets
    Dim servicesSheet
        
    oSheets = ThisComponent.getSheets()
    servicesSheet = oSheets.getByIndex(SERVICESSHEET_NUMBER)

    servicesSheet.getCellByPosition(SERVICESSHEET_SERVICES_COLUMN, 3).setString(newValue)
    
End Sub


Private oListener, cellRange as Object

Sub AddListener
    Dim sheet, cell as Object

    sheet = ThisComponent.Sheets.getByIndex(0)  'get leftmost sheet
    servicesSheet = ThisComponent.Sheets.getByIndex(2)

    cellRange = sheet.getCellrangeByName("C3")
    oListener = createUnoListener("Modify_","com.sun.star.util.XModifyListener")  'create a listener
    cellRange.addModifyListener(oListener)  'register the listener


    cellRange = servicesSheet.getCellrangeByName("C4")
    oListener = createUnoListener("Modify_","com.sun.star.util.XModifyListener")  'create a listener
    cellRange.addModifyListener(oListener)  'register the listener
End Sub

global CircularReferenceAllowed As boolean

Sub Modify_modified(oEv)

    Dim editedCell As cellStruct
    Dim newValue As String
    
    editedCell.columnNumber = 2
    editedCell.rowNumber = 2
    

    If CircularReferenceAllowed Then
        CircularReferenceAllowed = false
        UpdateServicesSheet(editedCell, "C")
    End If

End Sub

Sub Modify_disposing(oEv)
End Sub

Sub RmvListener
    cellRange.removeModifyListener(oListener)
End Sub


Sub Main

    CircularReferenceAllowed = true
    AddListener

End Sub

crossed to:

I am trying to create two tables which mirror changes made to any of them to one another automatically.

To that end, I added event listeners which are triggered when the cells of these tables are edited by the user.

Unfortunately, editing one of the tables causes LibreOffice to crash, even though the changes are indeed reflected correctly, as seen upon reopening the file.
I thought the crash might be due to a never-ending circular reference, but it still crashes after it has been made non-circular (by commenting out the relevant parts of the code so that changes are reflected only one way rather than both ways).
I noticed the code worked fine when writing to a cell that didn't have an event listener set to it.

How can I write to one of the cells with event listeners set to them without causing LibreOffice to crash?

You may want to download the following file. Please run Main and then try editing the cell C3 of the Planning sheet. The arbitrary string "C" should be written in the cell C4 of the Services sheet.

Here is a simplified version of the code :

REM  *****  BASIC  *****

const SERVICESSHEET_NUMBER = 2
const SERVICESSHEET_SERVICES_COLUMN = 2

Type cellStruct
    columnNumber As Integer
    rowNumber As Integer
End Type



Sub UpdateServicesSheet(editedCell As cellStruct, newValue As String)
    
    Dim oSheets
    Dim servicesSheet
        
    oSheets = ThisComponent.getSheets()
    servicesSheet = oSheets.getByIndex(SERVICESSHEET_NUMBER)

    servicesSheet.getCellByPosition(SERVICESSHEET_SERVICES_COLUMN, 3).setString(newValue)
    
End Sub


Private oListener, cellRange as Object

Sub AddListener
    Dim sheet, cell as Object

    sheet = ThisComponent.Sheets.getByIndex(0)  'get leftmost sheet
    servicesSheet = ThisComponent.Sheets.getByIndex(2)

    cellRange = sheet.getCellrangeByName("C3")
    oListener = createUnoListener("Modify_","com.sun.star.util.XModifyListener")  'create a listener
    cellRange.addModifyListener(oListener)  'register the listener


    cellRange = servicesSheet.getCellrangeByName("C4")
    oListener = createUnoListener("Modify_","com.sun.star.util.XModifyListener")  'create a listener
    cellRange.addModifyListener(oListener)  'register the listener
End Sub

global CircularReferenceAllowed As boolean

Sub Modify_modified(oEv)

    Dim editedCell As cellStruct
    Dim newValue As String
    
    editedCell.columnNumber = 2
    editedCell.rowNumber = 2
    

    If CircularReferenceAllowed Then
        CircularReferenceAllowed = false
        UpdateServicesSheet(editedCell, "C")
    End If

End Sub

Sub Modify_disposing(oEv)
End Sub

Sub RmvListener
    cellRange.removeModifyListener(oListener)
End Sub


Sub Main

    CircularReferenceAllowed = true
    AddListener

End Sub

Crossposted to :

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

寂寞笑我太脆弱 2025-02-01 06:11:07

似乎事件触发器在另一个事件的功能中导致崩溃。无论如何,解决方案是删除侦听器,然后在修改另一个单元格之后将其添加回。
您确实需要全球化侦听器和单元对象才能进行此工作。

该代码被简化为在第一张纸上的C3和C15上使用。它还将在C14上输出一些信息,这对于您的目的而言并不是必需的,但是我用它来查看发生了什么。您需要根据需要采用。

global goListener as Object
global goListener2 as Object
global goCellR as Object
global goCellR2 as Object
global goSheet as Object

global giRun as integer
global giUpd as Integer

Sub Modify_modified(oEv)
    Dim sCurStr$
    Dim sNewStr As String
    'xRay oEv
    
    giRun = giRun + 1
    sCurStr = oEv.source.string

    oCell = goSheet.getCellByPosition(2, 14)
    If (oCell.getString() <> sCurStr) Then
        ' only update if it's different.
        giUpd = giUpd + 1
        goCellR2.removeModifyListener(goListener2)
        oCell.setString(sCurStr)
        goCellR2.addModifyListener(goListener2)
    End If
    sNewStr =sCurStr & " M1 Run=" & giRun & " Upd=" & giUpd
    goSheet.getCellByPosition(2, 13).setString(sNewStr)    
End Sub

Sub Modify2_modified(oEv)
    Dim sCurStr$
    Dim sNewStr As String
    Dim oCell as Object
    'xRay oEv
    
    giRun = giRun + 1
    sCurStr = oEv.source.string
    oCell = goSheet.getCellByPosition(2, 2)
    If (oCell.getString() <> sCurStr) Then
        ' only update if it's different.
        giUpd = giUpd + 1
        goCellR.removeModifyListener(goListener)
        oCell.setString(sCurStr)
        goCellR.addModifyListener(goListener)
    End If
    sNewStr =sCurStr & " M2 Run=" & giRun & " Upd=" & giUpd
    goSheet.getCellByPosition(2, 13).setString(sNewStr)
End Sub

Sub Modify_disposing(oEv)
    MsgBox "In Modify_disposing"
End Sub

Sub Modify2_disposing(oEv)
    MsgBox "In Modify2_disposing"
End Sub

Sub RmvListener
    MsgBox "In RmvListener"
    goCellR.removeModifyListener(goListener)
    goCellR2.removeModifyListener(goListener2)
End Sub


Sub AddListener

    goSheet = ThisComponent.Sheets.getByIndex(0)  'get leftmost goSheet
    'servicesSheet = ThisComponent.Sheets.getByIndex(2)

    goCellR = goSheet.getCellrangeByName("C3")
    goListener = createUnoListener("Modify_","com.sun.star.util.XModifyListener")  'create a listener
    goCellR.addModifyListener(goListener)  'register the listener

    goCellR2 = goSheet.getCellrangeByName("C15")
    goListener2 = createUnoListener("Modify2_","com.sun.star.util.XModifyListener")  'create a listener
    goCellR2.addModifyListener(goListener2)  'register the listener
End Sub

Sub Main
    giRun = 0
    giUpd = 0
    AddListener

End Sub

It seems like the event trigger is within another event's function is causing the crash. In any case, the solution is to remove the listener, then add it back after modifying the other cell.
You do need to global the Listener and the Cell objects to make this work.

This code is simplified to work on C3 and C15 on the first sheet. It would also output some information on C14, which isn't really necessary for your purpose, but I use it to see what's happening. You need to adopt the according to what you need.

global goListener as Object
global goListener2 as Object
global goCellR as Object
global goCellR2 as Object
global goSheet as Object

global giRun as integer
global giUpd as Integer

Sub Modify_modified(oEv)
    Dim sCurStr$
    Dim sNewStr As String
    'xRay oEv
    
    giRun = giRun + 1
    sCurStr = oEv.source.string

    oCell = goSheet.getCellByPosition(2, 14)
    If (oCell.getString() <> sCurStr) Then
        ' only update if it's different.
        giUpd = giUpd + 1
        goCellR2.removeModifyListener(goListener2)
        oCell.setString(sCurStr)
        goCellR2.addModifyListener(goListener2)
    End If
    sNewStr =sCurStr & " M1 Run=" & giRun & " Upd=" & giUpd
    goSheet.getCellByPosition(2, 13).setString(sNewStr)    
End Sub

Sub Modify2_modified(oEv)
    Dim sCurStr$
    Dim sNewStr As String
    Dim oCell as Object
    'xRay oEv
    
    giRun = giRun + 1
    sCurStr = oEv.source.string
    oCell = goSheet.getCellByPosition(2, 2)
    If (oCell.getString() <> sCurStr) Then
        ' only update if it's different.
        giUpd = giUpd + 1
        goCellR.removeModifyListener(goListener)
        oCell.setString(sCurStr)
        goCellR.addModifyListener(goListener)
    End If
    sNewStr =sCurStr & " M2 Run=" & giRun & " Upd=" & giUpd
    goSheet.getCellByPosition(2, 13).setString(sNewStr)
End Sub

Sub Modify_disposing(oEv)
    MsgBox "In Modify_disposing"
End Sub

Sub Modify2_disposing(oEv)
    MsgBox "In Modify2_disposing"
End Sub

Sub RmvListener
    MsgBox "In RmvListener"
    goCellR.removeModifyListener(goListener)
    goCellR2.removeModifyListener(goListener2)
End Sub


Sub AddListener

    goSheet = ThisComponent.Sheets.getByIndex(0)  'get leftmost goSheet
    'servicesSheet = ThisComponent.Sheets.getByIndex(2)

    goCellR = goSheet.getCellrangeByName("C3")
    goListener = createUnoListener("Modify_","com.sun.star.util.XModifyListener")  'create a listener
    goCellR.addModifyListener(goListener)  'register the listener

    goCellR2 = goSheet.getCellrangeByName("C15")
    goListener2 = createUnoListener("Modify2_","com.sun.star.util.XModifyListener")  'create a listener
    goCellR2.addModifyListener(goListener2)  'register the listener
End Sub

Sub Main
    giRun = 0
    giUpd = 0
    AddListener

End Sub
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文