LibreOffice Calc:逐步浏览给定单元格中限制之间的一系列值
LibreOffice Calc: Stepping through a range of values between limits in given cells
在 LibreOffice Calc 中,我正在计算侵蚀和防洪。我有一组这样的数据:
这是在第 2 个 sheet 中,用于我的数据和最终用户不需要看到的其他“丑陋”的东西。在第一个 sheet 中,我使用 Data->Validity->Cell Range 来显示表面类型列表,以便我们可以选择我们正在使用的表面类型。从那里,我使用 VLOOKUP 选择低系数和高系数以进入下两个单元格。所以我有这个:
我选择了 Gravel,因此它通过从我的 table.
中读取数据,为我提供了可用于系数的高值和低值
接下来,为了简单起见,我想要一个名为“表面系数”的输入字段。我想使用微调器或滑块之类的东西,以便我们可以快速选择该行第 4 列和第 5 列的高值和低值之间的值。例如,此处 slider/scroll/spinner 的下限为 0.5,上限为 0.7。如果可能,它将以 0.01 的间隔递增。如果我将表面类型更改为“砾石”,那么 slider/scroll/spinner/whatever 会在 0.50 的低点和 0.70 的高点之间选择。
我找到了如何将滚动条作为表单控件在展开sheet 和link 单元格的值。我知道我可以为该滚动条指定低值和高值,但只能通过指定实际数字来指定。它不会让我将单元格指定为下限和上限。
我可以使用不同类型的控件。我基本上想要一个控件,让我以我设置的增量在低范围和高范围(在单元格中指定,而不是直接数字)之间步进。
有没有一种方法可以在滚动条或其他控件中指定用于下限和上限的单元格,让我做我想做的事?
让我们根据您对建议的用户界面的描述重新制定任务。
在一个单元格中,您需要输入步长为0.01的数值。此值的最小和最大限制显示在输入单元格右侧的两个单元格(同一行)中。为了便于输入,最好使用合适的控件来通过鼠标选择值。但是,也允许从键盘手动输入值。
首先,没有宏编程就无法解决此任务。
首先,让我们学习如何区分宏应该工作的单元格与 sheet 上的所有其他单元格。
最简单的方法是创建自定义单元格样式并将其应用于 sheet 上所需的单元格。 “单元格”对象有一个 .CellStyle
属性 ,我们可以通过它轻松识别所需的单元格。让我们将样式命名为“setValue”,并在宏的开头输入
的描述
Const STYLENAME_OF_FIELD = "setValue"
现在一个简单的条件
If oCell.CellStyle = STYLENAME_OF_FIELD Then
将阻止执行其他单元格的代码。
好的,现在我们来回答你在题目中提出的主要问题:如何将输入限制为指定的值。由于限制会动态变化,因此不要使用内置的数据有效性标准机制。编写一个看起来像这样的子程序会更容易:
Sub onValueChanged(oEvent As Variant)
Dim nColumn As Long, nRow As Long
Dim minValue As Double, maxValue As Double, newValue As Double
Dim oSheet As Variant
Rem Is this Event frome single cell?
If oEvent.SupportsService("com.sun.star.sheet.SheetCell") Then
Rem Does this cell have our predefined style?
If oEvent.CellStyle = STYLENAME_OF_FIELD Then
Rem To find out the contents of neighboring cells,
Rem you need to understand where this cell is located in our spreadsheet
nRow = oEvent.getCellAddress().Row
nColumn = oEvent.getCellAddress().Column
oSheet = oEvent.getSpreadsheet()
Rem Now you get the limits easily:
minValue = oSheet.getCellByPosition(nColumn+1, nRow).getValue()
maxValue = oSheet.getCellByPosition(nColumn+2, nRow).getValue()
Rem The current value of the cell is not available for any event via .getValue()
newValue = Val(Replace(oEvent.getFormula(),",","."))
Rem If the current value is out of range, return it back
newValue = IIf (newValue > maxValue, maxValue, newValue)
newValue = IIf (newValue < minValue, minValue, newValue)
Rem And write this value back into the cell
If newValue <> oEvent.getValue() Then oEvent.setValue(newValue)
EndIf
EndIf
End Sub
(这会奏效,但我必须警告您 - 这段代码远未完成!事件可以通过更改触发,不是在一个单元格中,而是在整个单元格范围内。甚至几个不同的范围。另外,当前单元格可能会出现在行尾,而它的右边根本就没有单元格,这段代码不处理这些情况)
现在介绍可信任的鼠标输入控件
您可以尝试使用滚动条。这将是输入范围不是很广的整数值的理想选择。但这不太适合您的任务,不适合处理分数值。 (你问滚动条值是如何传递到单元格的。这不是通过事件处理完成的,而是通过链接单元格,在数据选项卡上设置的)
将几个按钮组合成一组可能对您的任务很方便。将每个按钮的Tag属性设置为某个值,然后所有按钮都可以由一个宏控制:
Sub onBtnClick(Optional oEvent As Variant)
Rem Each button in group work with this Sub
Dim oCell As Variant
Dim oModel As Variant
Dim DeltaFromTag As Double
oModel = oEvent.Source.getModel()
DeltaFromTag = Val(oModel.Tag)
oCell = getActiveCell()
oCell.setValue(oCell.getValue() + DeltaFromTag)
onValueChanged(oCell)
End Sub
注意最后一行。使用宏更改单元格值不会引发 Content Changed 事件。因此,我们自己调用需要的代码。
将此子例程分配给每个按钮的事件处理程序 Action Execute
其他几个宏控制一组按钮的显示——代码可见in this file。调用主要的 - onChngSelected() - 分配给 sheet 事件选择已更改。
分配 sheet 事件处理程序很容易:从菜单中选择 Sheet-Sheet 事件,或者只需右键单击 sheet 的选项卡
在 LibreOffice Calc 中,我正在计算侵蚀和防洪。我有一组这样的数据:
这是在第 2 个 sheet 中,用于我的数据和最终用户不需要看到的其他“丑陋”的东西。在第一个 sheet 中,我使用 Data->Validity->Cell Range 来显示表面类型列表,以便我们可以选择我们正在使用的表面类型。从那里,我使用 VLOOKUP 选择低系数和高系数以进入下两个单元格。所以我有这个:
我选择了 Gravel,因此它通过从我的 table.
中读取数据,为我提供了可用于系数的高值和低值接下来,为了简单起见,我想要一个名为“表面系数”的输入字段。我想使用微调器或滑块之类的东西,以便我们可以快速选择该行第 4 列和第 5 列的高值和低值之间的值。例如,此处 slider/scroll/spinner 的下限为 0.5,上限为 0.7。如果可能,它将以 0.01 的间隔递增。如果我将表面类型更改为“砾石”,那么 slider/scroll/spinner/whatever 会在 0.50 的低点和 0.70 的高点之间选择。
我找到了如何将滚动条作为表单控件在展开sheet 和link 单元格的值。我知道我可以为该滚动条指定低值和高值,但只能通过指定实际数字来指定。它不会让我将单元格指定为下限和上限。
我可以使用不同类型的控件。我基本上想要一个控件,让我以我设置的增量在低范围和高范围(在单元格中指定,而不是直接数字)之间步进。
有没有一种方法可以在滚动条或其他控件中指定用于下限和上限的单元格,让我做我想做的事?
让我们根据您对建议的用户界面的描述重新制定任务。
在一个单元格中,您需要输入步长为0.01的数值。此值的最小和最大限制显示在输入单元格右侧的两个单元格(同一行)中。为了便于输入,最好使用合适的控件来通过鼠标选择值。但是,也允许从键盘手动输入值。
首先,没有宏编程就无法解决此任务。
首先,让我们学习如何区分宏应该工作的单元格与 sheet 上的所有其他单元格。
最简单的方法是创建自定义单元格样式并将其应用于 sheet 上所需的单元格。 “单元格”对象有一个 .CellStyle
属性 ,我们可以通过它轻松识别所需的单元格。让我们将样式命名为“setValue”,并在宏的开头输入
Const STYLENAME_OF_FIELD = "setValue"
现在一个简单的条件
If oCell.CellStyle = STYLENAME_OF_FIELD Then
将阻止执行其他单元格的代码。
好的,现在我们来回答你在题目中提出的主要问题:如何将输入限制为指定的值。由于限制会动态变化,因此不要使用内置的数据有效性标准机制。编写一个看起来像这样的子程序会更容易:
Sub onValueChanged(oEvent As Variant)
Dim nColumn As Long, nRow As Long
Dim minValue As Double, maxValue As Double, newValue As Double
Dim oSheet As Variant
Rem Is this Event frome single cell?
If oEvent.SupportsService("com.sun.star.sheet.SheetCell") Then
Rem Does this cell have our predefined style?
If oEvent.CellStyle = STYLENAME_OF_FIELD Then
Rem To find out the contents of neighboring cells,
Rem you need to understand where this cell is located in our spreadsheet
nRow = oEvent.getCellAddress().Row
nColumn = oEvent.getCellAddress().Column
oSheet = oEvent.getSpreadsheet()
Rem Now you get the limits easily:
minValue = oSheet.getCellByPosition(nColumn+1, nRow).getValue()
maxValue = oSheet.getCellByPosition(nColumn+2, nRow).getValue()
Rem The current value of the cell is not available for any event via .getValue()
newValue = Val(Replace(oEvent.getFormula(),",","."))
Rem If the current value is out of range, return it back
newValue = IIf (newValue > maxValue, maxValue, newValue)
newValue = IIf (newValue < minValue, minValue, newValue)
Rem And write this value back into the cell
If newValue <> oEvent.getValue() Then oEvent.setValue(newValue)
EndIf
EndIf
End Sub
(这会奏效,但我必须警告您 - 这段代码远未完成!事件可以通过更改触发,不是在一个单元格中,而是在整个单元格范围内。甚至几个不同的范围。另外,当前单元格可能会出现在行尾,而它的右边根本就没有单元格,这段代码不处理这些情况)
现在介绍可信任的鼠标输入控件
您可以尝试使用滚动条。这将是输入范围不是很广的整数值的理想选择。但这不太适合您的任务,不适合处理分数值。 (你问滚动条值是如何传递到单元格的。这不是通过事件处理完成的,而是通过链接单元格,在数据选项卡上设置的)
将几个按钮组合成一组可能对您的任务很方便。将每个按钮的Tag属性设置为某个值,然后所有按钮都可以由一个宏控制:
Sub onBtnClick(Optional oEvent As Variant)
Rem Each button in group work with this Sub
Dim oCell As Variant
Dim oModel As Variant
Dim DeltaFromTag As Double
oModel = oEvent.Source.getModel()
DeltaFromTag = Val(oModel.Tag)
oCell = getActiveCell()
oCell.setValue(oCell.getValue() + DeltaFromTag)
onValueChanged(oCell)
End Sub
注意最后一行。使用宏更改单元格值不会引发 Content Changed 事件。因此,我们自己调用需要的代码。
将此子例程分配给每个按钮的事件处理程序 Action Execute
其他几个宏控制一组按钮的显示——代码可见in this file。调用主要的 - onChngSelected() - 分配给 sheet 事件选择已更改。
分配 sheet 事件处理程序很容易:从菜单中选择 Sheet-Sheet 事件,或者只需右键单击 sheet 的选项卡