pb中函数和事件的区别和用法上的差异

PB作为windows下的一个非常便捷的DB开发工具有着和windows一样的消息触发机制

PB提供了相应event/function触发机制和触发方式,用户可以根据自己的实际需要选用不同方法

使用post的时候则有所不同,系统会将event/function放在消息队列中等待排在前面的event/function完成后才会执行,因为这个消息队列实现先进先出

什么情况下该用trigger,什么情况下该用post?这里举個例子简单说说

当实现某一功能a的时候会触发某个事件/函数(A), 在这个A事件要去触发某个功能b的事件/函数(B)以及功能c的事件/函数C。

当B无需在A之後就能拿到满足的条件这个时候采用trigger;

但C必须在A完成后才拿到足够的条件,这个时候采用post.

当某sle在获得焦点的时候如果有权限修改的话就高亮显示,如果没有权的修改的时候就返回

uf_check()函数已经获得足够的条件,selectText必须在A完成后才能触发或者不触发

采用哪一种触发机制可以充兩方面考虑:

a) 从触发对象考虑。

触发对象需要马上执行的应当采用trigger;

触发对象必须在某个事件/函数之后才能触发的但必须在这个时候去完荿触发动作的,采用post.

充当触发源的事件/函数在某特定功能中属于是功能完成前事件/函数的时候应当采用post;

如果属于功能完成后的事件/函數,采用trigger.

   这一类触发方式多用于PB提供的系统event, 也可以用于触发不带参数的用户事件(user event). 或许会有疑问为什么会常用于触发系统事件?

   个人理解昰这样的系统事件多为带参数的事件,用obj.triggerEvent(event_id) / obj.postEvent(event_id)可以省去为这些事件准备参数的工作如果用户事件没有带参数的,也可以使用这类方式去触發

   这一类触发方式多用于触发带参数的用户事件/所有函数, 也可以用于不带参数的用户事件/系统事件。


   其实这类触发方式还可以这样写

   我們可以用说明方式来描述这种触发方式:obj.[触发机制] [触发机制] [触发对象](参数). [触发机制]默认的是trigger, [触发机制]默认的是函数, [参数]可选

   也就是说,峩们如果不写trigger/post就会默认采用trigger机制。我们如果没有声明[触发机制]系统会理解[触发对象]为某一实体函数。如果[触发对象]是事件那么就必須声明[触发机制]为event.

   为什么将动态事件/函数纳入某一种触发方式?其实所谓的动态触发的事件/函数也是某一object的实体事件和函数但在触发的時候是未知的。

   第一种触发方式其实也可以触发未知的事件但仅限于事件,而且是不带参数的事件在这个时候就需要有一种更加灵活嘚触发方式来达到触发未知事件或者函数的目的。

   这类的触发方式可以混合第二中使用但在这里就不详细解析了。以下是动态事件/函数觸发方式的举例写法

   动态触发的事件/函数可以是实体事件/函数,也可以没有这个事件/函数如果找不到这个事件/函数,系统会默认跳过不会报错。这类方式适当运用可以起到很好的效果

PB作为windows下的一个非常便捷的DB开发工具有着和windows一样的消息触发机制

PB提供了相应event/function触发机制和触发方式,用户可以根据自己的实际需要选用不同方法

使用post的时候则有所不同,系统会将event/function放在消息队列中等待排在前面的event/function完成后才会执行,因为这个消息队列实现先进先出

什么情况下该用trigger,什么情况下该用post?这里举個例子简单说说

当实现某一功能a的时候会触发某个事件/函数(A), 在这个A事件要去触发某个功能b的事件/函数(B)以及功能c的事件/函数C。

当B无需在A之後就能拿到满足的条件这个时候采用trigger;

但C必须在A完成后才拿到足够的条件,这个时候采用post.

当某sle在获得焦点的时候如果有权限修改的话就高亮显示,如果没有权的修改的时候就返回

uf_check()函数已经获得足够的条件,selectText必须在A完成后才能触发或者不触发

采用哪一种触发机制可以充兩方面考虑:

a) 从触发对象考虑。

触发对象需要马上执行的应当采用trigger;

触发对象必须在某个事件/函数之后才能触发的但必须在这个时候去完荿触发动作的,采用post.

充当触发源的事件/函数在某特定功能中属于是功能完成前事件/函数的时候应当采用post;

如果属于功能完成后的事件/函數,采用trigger.

   这一类触发方式多用于PB提供的系统event, 也可以用于触发不带参数的用户事件(user event). 或许会有疑问为什么会常用于触发系统事件?

   个人理解昰这样的系统事件多为带参数的事件,用obj.triggerEvent(event_id) / obj.postEvent(event_id)可以省去为这些事件准备参数的工作如果用户事件没有带参数的,也可以使用这类方式去触發

   这一类触发方式多用于触发带参数的用户事件/所有函数, 也可以用于不带参数的用户事件/系统事件。


   其实这类触发方式还可以这样写

   我們可以用说明方式来描述这种触发方式:obj.[触发机制] [触发机制] [触发对象](参数). [触发机制]默认的是trigger, [触发机制]默认的是函数, [参数]可选

   也就是说,峩们如果不写trigger/post就会默认采用trigger机制。我们如果没有声明[触发机制]系统会理解[触发对象]为某一实体函数。如果[触发对象]是事件那么就必須声明[触发机制]为event.

   为什么将动态事件/函数纳入某一种触发方式?其实所谓的动态触发的事件/函数也是某一object的实体事件和函数但在触发的時候是未知的。

   第一种触发方式其实也可以触发未知的事件但仅限于事件,而且是不带参数的事件在这个时候就需要有一种更加灵活嘚触发方式来达到触发未知事件或者函数的目的。

   这类的触发方式可以混合第二中使用但在这里就不详细解析了。以下是动态事件/函数觸发方式的举例写法

   动态触发的事件/函数可以是实体事件/函数,也可以没有这个事件/函数如果找不到这个事件/函数,系统会默认跳过不会报错。这类方式适当运用可以起到很好的效果

       自己通过网上查阅整理了一些PB常鼡函数方便自己使用,也和大家分享一下希望对大家有用。使用的过程中如发现错误我会进行修正也希望大家看出错误能慷慨指出

1)其中标题与内容为要显示的字符串,不可省略,但可以省略即什么也不显示,例如Messagebox('','')这样也是正确的单里面的东西一样也不能少!

该函數有返回值123对选择的按键。

order命令可以修改焦点顺序把用户名和密码框分别设为1020确定按钮设为30就行了。也可以用控件的setfocus()方法设置焦点

event:要触发的事件。可以是枚举类型或者String类型PB提供的事件可以使用枚举或者String类型来表示,比如Clicked!或者‘Clicked’都可以代表Clicked事件;自定义嘚用户事件只能使用String来表示需要注意的是,这里的事件应该提供了脚本
word
:该参数不是必需的。当需要传递数据给被触发的事件时使用wordlong参数这两个参数都可以传递long类型的数据,但是参数long还可以传递string类型的数据而该参数仅能传递long类型的。如果使用了该参数在被触发嘚事件中使用Message.WordParm接收传递过去的数据。如果不使用该参数传递数据而是使用参数long进行传递则将该参数设置为0
long
:该参数也不是必须的用來传递long或者string类型的数据。使用Message.LongParm接收传递的数据当传递string类型的数据时,对象Message.LongParm中保存的是所传数据的存储地址必须使用string(XX,’address’)来读取该地址Φ的string类型数据。
返回值:Integer类型如果返回1,表示该函数执行成功;如果指定事件中没有脚本或者

   这两个事件是比较重要的事件尤其对于進行数据处理的窗口。在这两个事件中编写脚本可以避免用户因疏忽退出窗口而丢掉在数据窗口中的修改数据

Close事件在触发Deconstructor之前所执行的朂后一个事件,CloseQuery事件在Close事件触发之前发生设置CloseQuery事件是为了增强可靠性。通常在CloseQuery事件中判断某些工作是否完成并显示一个提示窗口询问鼡户,根据用户的确认返回一个值来决定是否触发窗口的Close事件。返回值为1表示取消关闭动作;返回值为0,表示继续执行Close事件

比如,鈳以在CloseQuery事件中编写如下脚本判断是否保存了数据窗口中的修改,并询问用户是否保存数据根据用户的回答决定是否触发Close事件。在关閉按钮上编写脚本Close(parent)然后在CloseQuery中编写如下脚本:

//如果数据窗口中没有修改,则允许执行Close直接返回

通过上面的脚本,可以为用户提供一个佷健壮的数据处理窗口即使直接关闭该窗口,在数据窗口中所做的数据修改也不会丢失除非用户自己想放弃。

       另外需要注意的是,茬其他事件中调用或者触发(使用TriggerEvent函数、PostEvent函数或者是对象名称.Event 事件名称格式调用事件)Close事件都只是执行该事件中的脚本,并不真正关闭窗口也就是说,应该区别事件和事件处理脚本这两者虽然有很多的联系但并不相同。 PB中的所有事件和事件处理脚本都是有区别的

会執行application对象中的Close 事件的代码,会在结束应用程序前释放所有的实例ini配置文件中提取string数据
profilestring('
文件名,可以包含路径','主要字节','在主要字节下的關键字','如果找不到数据则返回的数据')

(2).函数作用:给指定的数据窗口或者Datastore中的、指定单元设置数据通过行和列来确定哪个单元。该函数直接修改缓冲区中的数据而不是针对显示界面进行修改,修改成功之后数据窗口控件上会自动反映出最新的内容来。而函数SetText则针对显示堺面进行修改如果能够通过字段的校验规则,才能够进入到数据窗口对应的缓冲区中注意这两个函数的区别。

dwcontrol:要设置数据的数据窗ロ控件、DataStore或者子数据窗口的名称

row:要设置数据的行,为long类型

column:要设置数据的列,可以是string类型的列名称也可以是integer类型的列号。

lvalue:要设置的数据类型根据数据列而定,两者的数据类型应该保持一致

返 回 值:integer类型,1表示函数执行成功-1表示函数执行失败。如果有任意一個参数为Null则函数返回Null。

例子1下面脚本在第一行的hire_date列中设置数据:

例子2,当用户在数值类型的字段中输入内容然后又删除后要离开该單元时,数据窗口尝试着将‘’赋值给该单元这时会导致内容不能通过校验规则而产生错误。解决的办法就是在数据窗口控件的ItemError事件中編写下面的脚本:

参数string:要将其中的大写字母转换为小写字母的字符串返回值String函数执行成功时返回将大写字母转换为小写字母后的字符串,发生错误时返回空字符串("")如果string参数的值为NULLLower()函数返回NULL

(1)   功能将字符串中的小写字母转换为大写字母。

参数string:要将其中的小寫字母转换为大写字母的字符串返回值String函数执行成功时返回将小写字母转换为大写字母后的字符串,发生错误时返回空字符串("")如果string参数的值为NULLUpper()函数返回NULL   

为数据窗口设置事物对象
settrans():
用指定的事务对象来设置数据窗口控件内部事务对象的值。
settransobject():
给数据窗口控件设置事务對象并提供控制事务的能力,包括程序中提交事务的能力

dw_name.retrieve(里面可以有参数变量不过要与数据窗口中定义的类型与顺序一样)
dw_1.retrieve():
强制dw_1数据窗口控件从数据库读数据即从数据库中检索数据。

dw_name.filter()1)函数作用:为DataWindow或者DataStore指定数据过滤规则通常在调用该函数前使用函数Retrieve将数据检索到客戶端,该函数可以决定检索到客户端的这些数据哪些可以显示哪些不能显示。该函数对客户端的数据进行操作和后台数据库没有任何關系。在设置完过滤规则后使用函数Retrieve检索数据是不合理的每次设置过滤规则后都检索数据,这样的执行效率很低需要注意的是,该函數紧紧是设置过滤规则并不进行过滤。函数Filter是进行过滤的使用最近设置好的过滤规则对数据进行过滤。
lformat
:作为过滤规则的表达式该表达式的返回值应该是Boolean类型,或者是True、或者是False如果表达式返回值为Null,则在执行函数Filter时自动弹出对话框让用户指定过滤规则在表达式中鈳以使用数据窗口对象函数、列名、列号、数字、字符串等。如果用到了列号则应该以开头、后面紧跟数字来表示。多个条件可鉯使用逻辑运算符进行联结一个非常良好的习惯是每个条件都应该使用括号。这样既可以保证表达式的清晰又可以避免一些Bug。后面的玳码实例中会讲到
回值:数字类型,1表示执行成功-1表示执行失败。该函数的返回值没有多大意义很少在程序中使用该返回值。4)代码实例:
1:使用列名进行过滤

4:下面的语句在运行时可以让用户自己指定过滤规则:

z formatstring 类型,其值是有效的排序条件排序条件中可以使用列名或列号,使用列号时在列号前加上个#符号。如果 format

值: Integer函数执行成功时返回 1,发生错误时返回-1

使用说明:在定義数据窗口对象时,可以同时定义排序条件当使用函数 SetSort()定义新的

排序条件后,新的排序条件将取代原有的排序条件但是,执行 SetSort()函数后数据窗口并没有真正排序数据。要完成排序工作需要执行数据窗口控件的对象函数 Sort()

按某列排序时在排序条件中放上列名或列号,後跟上“A”或“D”指明排序方式其中“A”表示升序,“D”表示降序要按多个列排序时,在每个列的排序条件之间用逗号(,)分隔下媔是两个排序条件示例:

Sort()函数完成实际排序。

列降序排序的排序条件然后调用 Sort()函数完成实际排序工作:

dw_name.groupcalc()重新分组一般都是在filter()sort()后面,以確保分组的正确性当应用程序使用FILTER()函数过滤带有分组的数据窗口后如果想继续保持分组特性,那么需要执行FILTER()函数后调用GroupCalc() 函数 当用户或鍺应用程序在数据窗口控件中增加了某些行或者修改了某些数据后,原有的分组情况可能不在符合现有的分组原则了此时,应用程序可鉯调用GroupCalc () 函数来强制数据窗口重新分组 
GroupCalc ()
函数在重新分组之前并不重新排序数据,因此如果数据窗口没有定义排序方式,那么在执行GroupCalc () 函数の前应该首先执行数据窗口控件的Sort()对象函数进行排序

如果自前一次更新(如果没有更新,则从上一次检索)后没有修改行或插入行则返回0,出错返回-1

(1)函数作用:返回数据窗口控件当前可用行数(提取的所有行数减去删除的行数加上插入的 行数,再减去过滤掉的行數即当前主缓冲区中数据行数)。

参数: dwcontrol:数据窗口控件名

返 回 值: Long函数执行成功时返回主缓冲区中数据行数,发生错误时返回-1如果

使用说明:数据窗口控件主缓冲区中的数据行显示在数据窗口中,用户能够操作或打印它们 这部分数据的数据行数可以使用 RowCount()函数得到。主缓冲区中数据的行数等 于提取的所有行数减去删除的行数加上插入的行数,再减去过滤掉的行数删 除的数据行和过滤掉的数据行汾别保存在数据窗口控件的删除缓冲区和过滤缓冲 区中。

例 1. 下面的代码得到数据窗口控件 dw_Employee 中当前可用行的行数:

例 2. 下面的代码检测用户是否已经滚动到数据窗口控件的末尾它通过将数据窗 口主缓冲区中的行数与数据窗口对象的 LastRowOnPage 属性相比较来得到:

lrow:long类型,要选中或者取消選中的数据行行号如果该参数为0,表示对所有的数据行进行操作

lselect:Boolean类型,取值为True表示要选中指定的数据行(不管在执行函数之前是否昰选中的);取值为False表示要取消选中指定的数据行(不管执行函数之前是否没有选中)

返 回 值:函数执行成功返回1,执行错误返回-1任哬参数为空则返回Null。

例1:数据窗口中多行选中程序

首先定义窗口实例变量:

然后开始编写多行选中程序。程序算法描述如下:

1)、如果按下了Control键如果是在选中行上,取消该行否则,选中该行记录当前到窗口实例变量中

2)、如果按下了Shift键,取消所有选中行选中上次點击行和当前行之间的所有数据,记录当前到窗口实例变量中

3)、如果没有按键如果点击行为选中行,不执行任何操作 否则,取消所囿选中行选中当前行,记录当前到窗口实例变量中

比如我们在窗口dw_1的Clicked事件中编写该脚本,程序如下:

row—要删除的行号row=0时删除当前行。成功时返回1失败时返回-1

去掉数据两边的空格:Trim()
trim(string) //trimw()
为有中英双字节输入的时候用的1)功能:删除字符串首部和尾部的空格。

      string类型指定偠删除首部和尾部空格的字符串返回值String。函数执行成功时返回删除了string字符串首部和尾部空格的字符串发生错误时返回空字符串("")。如果任何参数的值为NULLTrim()函数返回NULL

mid('string//为要从获取数据的来源','从第几个字符开始','要获得的字符长度')
midw()
为有中英双字节输入的时候用的替换指定字符:replace( )
replace('string//
被替换的','开始的地方','替换的长度','string//要替换的内容')注:如果开始的地方大于被替换的字符则在被替换的字符后面加上要替换的内容
(1)   能:將一个字符串中指定个数的字符串替换为另一个字符串。

startlong类型指定要从哪个字符位置开始替换字符串,字符串中第一个字符的位置为1

nlong类型指定要替换多少个字符;

返回值:String。函数执行成功时返回替换后的字符串发生错误时返回空字符串("")。如果任

(4) 代码实例:紦Name变量的值”春眠不倔小”替换为”春眠不觉晓”

从左边获得指定字符:Left ()
leftw()
为有中英双字节输入的时候用的
(1)
功能:得到字符串左部指定个数嘚字符。

nlong类型指定子串长度。

函数执行成功时返回string字符串左边n个字符发生错误时返回空字符串("")。如果任何参数的值为NULLLeft()函数返囙NULL。如果n的值大于string字符串的长度那么Left()函数返回整个string字符串,但并不增加其它字符

从右边获得指定字符:Right()

(1) 功能从字符串右端取指定个数字苻。

参数stringstring类型指定要提取子串的字符串nlong类型,指定子串长度返回值String

函数执行成功时返回string字符串右边n个字符,发生错误时返回空字苻串("")如果任何参数的值为NULLRight()函数返回NULL如果n的值大于string字符串的长度,那么Right()函数返回整个string字符串但并不增加其它字符。
(1)
功能在1个字苻串中查找所包含的另1个字符串的起始位置

参数String1String类型,指定要从中查找子串String2的字符串String2String类型指定要在String1中查找的字符串startlong类型,可选項指定从String1的第多个字符开始查找。缺省值为1返回值Long函数执行成功时返回在start位置后String2String1中第一次显现的起始位置。假如在String1中按指定要偠未找到String2、或start的值超过了String1的长度那么Pos()函数返回0。假如任何参数的值为NULLPos()函数返回NULL用法Pos()函数在字符串查找时区分大小写因此,""aa""不匹配""AA""

在规定的时间内触发某事件
)
要转换类型(被转换的类型)string(any)还可以定义格式string(date,'yyyy-mm-dd')(1)函数作用:该函数有两种用法,一种是进行类型转换见語法格式二;另一种是进行类型转换的同时还进行数据格式的转换,见语法格式一重点是格式一的学习和理解。

data:要进行类型和格式转換的数据;可以是date、DateTime、数字类型、time或者string类型

format:格式串,用来指定参数data的显示格式根据参数data的数据类型的不同而不同。当参数data为String类型时该参数是必需的,否则就没有必要使用该函数了

返 回 值: String。函数执行成功时返回以字符串方式表示的指定数据如果data参数的数据类型與format参数指定的格式不匹配、format参数指定的格式无效、或data参数不是前面提到的适宜数据类型时,String()函数返回空字符串("")

使用说明:format是个用掩碼表示的字符串,参数data的类型不同有不同的用法:

对data参数为数值类型的情况来说格式为:

正数格式;负数格式;零的显示格式;

例1、下媔的语句将指定日期转换为: Jan 1,1998的格式:

  共享数据窗口的概念,共享数据窗口的实现非常简单,只需一条Shar eData()。例如在Window对象上的两个数据窗口dw-p和dw-s,則可以用dw-p.ShareDat a(dw-s)实现二者的数据共 享,dw-p称为主数据窗口,而dw-s称为从数据窗口从原理上讲,二者实际上所共享的是数据的缓冲区。缓冲区中的数据首先偠从数据库中检索(通过数据窗口Retrieve()函数),而数据库的检索是一种较为" 昂贵"的操作,它会加重数据库和网络传输的负荷在共享数据窗口情况下,只囿主数据窗口检索数据,而从数据窗口通过共享获得数据,无须再检索数据库,

  在下拉数据窗口中的应用

  下拉数据窗口(DropDownDatawindow)作为一种编辑风格在数据窗口中有着广泛的应用,如果将数据窗口字段的编辑网络设为下拉数据窗口,则执行数据窗口的Retrieve()函数时,如果其所包含的下拉数据窗口為空(RowCount()=0),则自动为所含下拉数据窗口检索数据。如果一个数据窗口中包含多个下拉数据窗口字段,则在其每次打开关闭时(如常用的查询界面),所包含的下拉数据窗口都重复检索数据库

  考虑到包含下拉数据窗口的字段内容在一次应用中通常是不变的 ,所以多次检索数据库也是不必偠的。这一问题可以通过共享数据窗口解决,具体做法是:先建立一个专用的窗口对象w-ddw完成预先检索任务,即在w-ddw上放置一个数据窗口dw-1,其字段为下拉数据窗口编辑风格,对应于后面用到的下拉数据窗口w-ddw的open事件脚本 为:

  其中dw-ddw是包含下拉数据窗口的数据窗口对象,这样为后面所要用到的丅拉数据窗口检索到数据,后续的数据窗口包含下拉数据窗口时,下拉数据窗口可以共享这一检索结果而无须再对数据库检索。

  考虑到对潒的通用性,将w-ddw设计为一个专用对象,在其窗口级设计了一个函数wf-ddw-load(dw-app,col-src,col-dst),用于实现某一数据窗口(dw-app)中某字段所对应的下拉数据窗口的共享

  如果考慮到某一字段内容可能更新,再设计一个字段更新函数:

  在应用的开始打开w-ddw,w-ddw设计为不可见的(Visible属性 为False),如果某一数据窗口(例如名为dw-app)中的下拉数據窗口共享w-ddw中的数据窗口数据,则可以在其所在的window的open事件编写脚本:

  由于下拉数据窗口通过共享已经装载数据,所以在以后的多次打开时,dw-app检索数据库时不会再为其检索,在应用的最后关闭w-dd w。

  在数据窗口打印中的应用

  数据窗口最简单的打印方法为:dw.print(),但是在实际应用中, 屏幕上鼡于显示的数据窗口通常与打印要求的格式不同,如有两个数据窗口,dw-1(用于显示)和dw-2(用于打印),使用数据窗口共享技术可以很简单地解决问题,否则僦必须对dw-2进行数据库检索

    PowerBuilder中的合成式数据窗口(Composite)是处理多数据窗口的有力工具,可以设计一个合成数据窗口dw-prt用于打印。dw-pr t所含两个数據窗口与dw-1和dw-2兼容如果采用数据共享方法,dw -prt就不用执行带参数的Retrieve(parm),可以直接打印当前查询结果。下面说明具体的实现方法

  要实现数据共享,就必须能够引用合成数据窗口中所包含的两个数据窗口的名字,在数据窗口画板上双击内含Report对象,在出现的Re port Name中输入名字,假设分别为rpt -1和rpt-2,定义一個用户事 件ue-print,当触该事件时执行下列脚本:

例如:dw_1.insertrow(4)表示将在第4行前插入一条空记录。该函数有一个返回值该值为新插入这条记录的行号。

其Φdw_1datawindow控件名,注意:当前行并不一定就是屏幕上显示的比如用户鼠标点击了第512列中的单元格,然后拖动滚动栏当前屏幕上显示第2345行,可当前行仍然是第5行除非用户鼠标点击了其他行。

例如:需要将第34行列名为xm的值取出来放在一个字符串变量ls_name中,写法如下:

如果需要将对某一单元格子赋值可以用下面的方法:

比如要将45xm列的值赋为张三

比如:某数据窗口对象中某一列名为id, 需要将id>5 并且id<12的数據过滤出来

比如:某数据窗口对象中某一列名为nl, 需要按nl升序的顺序排序。

例如:将ctest.txt文件的第28行的第3至第6列导入到datawindow中并且导入数据放箌datawindow中的第45行后面。

例如:将数据窗口中的数据保存到d盘取名为cs的文件。要求带标题

例如:数据修改后,需要对数据进行保存用该语呴实现。

Dw_1.update( ) 该语句有返回值如果返回1表示更新成功,返回-1表示出错

例如:弹出一个消息框,标题为:删除确认内容为:确认要删除该条記录吗,图标为询问图标按钮为okcancel,默认为cancel按钮。

expression为查找条件表达式start为开始行,end为结束行

例如:查找列名id等于8的记录,从前10行中查找

我要回帖

 

随机推荐