这是一个PB9写的数据窗口单击标题自动排序/拖动行可以改变行顺序的标准datawindow对象。
自动排序:
拖动行改变行顺序:
代码:
建立一个新的Standard Visual的datawindow对象,命名为uo_datawindow并保存,然后Edit Source,将代码替换为以下内容,再保存即可。
forward global type uo_datawindow from datawindow end type end forward global type uo_datawindow from datawindow integer width = 686 integer height = 400 string dragicon = "Query5!" string title = "none" boolean hscrollbar = true boolean vscrollbar = true boolean livescroll = true borderstyle borderstyle = stylelowered! event key pbm_dwnkey event lbuttondown pbm_lbuttondown event mouseup pbm_dwnlbuttonup event lbuttonup pbm_lbuttonup event ue_win_mousemove pbm_mousemove end type global uo_datawindow uo_datawindow type variables Protected: boolean 行指示 = true boolean ib_first_row_countmove = false //第一行不可以移动,可扩展为指定行不可移动 string is_drag_col = 'xh' //单击后可以移动行的列(不同的dataobject对应的列不同,这里需要自己修改) private: long il_drag_down, il_last_dragmove //被拖动的行、当前拖动移到的行 boolean ib_draging = false //是否正处于拖动状态下 boolean ib_draging_other = false //是否正在从其他数据窗口托数据行到这里 long il_drag_down_other //其他数据窗口中被拖动的行 boolean ib_created = false long il_line_color = -1 long il_text_color = 0 string is_ordercol, is_sorttype = 'A', is_lbuttondown_obj boolean ib_clicked_header constant string ASC_SIGN = ' △' //升序标示▲ constant string DESC_SIGN = ' ▽' //降序标示▼ end variables forward prototypes public subroutine of_sort () public subroutine of_clear_sort_sign () public function integer of_add_sort_sign_noredraw (string as_sort) public function integer of_add_sort_sign (string as_sort) public subroutine uf_create_drag_object () public function string of_describe (string as_describe, long row) public function long of_get_dw_right_column (ref string as_col) public subroutine uf_drag_end () public subroutine uf_drag_move_row () public function long of_get_row_bottom (long row) end prototypes event key;//key end event event lbuttondown;if left(getbandatpointer(),6) = 'header' then ib_clicked_header = true is_lbuttondown_obj = lower(trim(left(getobjectatpointer(),pos(getobjectatpointer(),"~t") - 1))) end if //==================================================================== //按下鼠标左键:如果数据窗口非只读(单据处于可编辑状态),且行数大于1, // 同时,存在is_drag_col列,并且鼠标单击的列是is_drag_col列,则可以 // 进入拖动模式 //说明:ib_first_row_countmove 表示第一行不可以被移动,其他行也不可以 // 移动到第一行 //==================================================================== if rowcount() > 0 then if of_Describe(is_drag_col + ".x", 1) <> '!' then //控件不存在,才新增 then if trim(left(getobjectatpointer(), pos(getobjectatpointer(), "~t") - 1)) = is_drag_col then il_drag_down = long(trim(mid(getobjectatpointer(), pos(getobjectatpointer(), "~t") + 1))) if il_drag_down > 0 and il_drag_down <= rowcount() then il_last_dragmove = il_drag_down if Object.DataWindow.ReadOnly = "no" then if rowcount() > 1 then if ib_first_row_countmove and il_drag_down = 1 then //第一行不可以移动 uf_drag_end() return end if ib_draging = true il_text_color = 0 end if end if end if end if end if end if end event event mouseup;post of_sort() end event event lbuttonup; //==================================================================== // 弹起鼠标左键:如果当前处于拖动模式,则结束拖动模式 //==================================================================== if ib_draging or ib_draging_other then uf_drag_end() end if end event event ue_win_mousemove;//==================================================================================================== // 按下左键,拖动鼠标,且光标指向的行发生改变时(数据窗口行数需要大于1,且存在is_drag_col列),开始拖动模式 //==================================================================================================== if (ib_draging or ib_draging_other) and keydown(keyleftbutton!) then string ls_col long ll_row, ll_drag_down if ib_draging then ll_drag_down = il_drag_down else ll_drag_down = il_drag_down_other end if ll_row = this.rowcount() if ((ll_row > 1 and ib_draging) or ib_draging_other) and not ib_created then //大于1行才有拖动的意义 //当前鼠标移到被拖动行以外的行时,才开始进入拖动模式 if ll_drag_down > 0 then //and long(trim(mid(getobjectatpointer(), pos(getobjectatpointer(), "~t") + 1))) <> ll_drag_down then this.Drag (begin!) uf_create_drag_object() int li_w li_w = nvll(long(this.describe(is_drag_col + ".width")), 130) if li_w <= 0 then li_w = 130 int li_scw = 0 if this.object.datawindow.firstrowonpage <> '1' or this.object.datawindow.lastrowonpage <> string(rowcount()) then li_scw = 80 modify("t_for_Drag.text = '" + string(ll_drag_down) + "' t_for_Drag.width = '" + string(li_w) + "' rr_for_drag.width = '" + string(min(of_get_dw_right_column( ls_col), width - 35 - li_scw)) + "'") ib_created = true end if else end if end if end event public subroutine of_sort ();if ib_clicked_header then ib_clicked_header = false string ls_curobj ls_curobj = lower(trim(left(getobjectatpointer(),pos(getobjectatpointer(),"~t") - 1))) if ls_curobj = is_lbuttondown_obj and is_lbuttondown_obj <> "" then string ls_curcol if this.describe(ls_curobj + ".text") <> "!" then ls_curcol = left(ls_curobj, len(ls_curobj) - 2) if is_ordercol <> ls_curcol then is_sorttype = 'A' is_ordercol = ls_curcol else if is_sorttype = 'A' then is_sorttype = 'D' ELSE is_sorttype = 'A' end if end if of_add_sort_sign( is_ordercol + " " + is_sorttype) setsort(is_ordercol + " " + is_sorttype) sort() groupcalc() end if end if end if is_lbuttondown_obj = "" end subroutine public subroutine of_clear_sort_sign (); //======================================================================================================================== // 清除数据窗口的排序标示 //======================================================================================================================== string ls_sort, ls_tmp, ls_col, ls_a_d, ls_text ls_sort = trim(this.describe("DataWindow.table.sort")) if ls_sort = "" or ls_sort = "?" or ls_sort = "!" then return if right(ls_sort, 1) <> ',' then ls_sort += "," //"bm_sp a, barcode d, gg a," long i,j i = pos(ls_sort, ',') do while i > 0 ls_tmp = trim(left(ls_sort, i - 1)) j = pos(ls_tmp, ' ') if j > 0 then ls_col = trim(left(ls_tmp, j - 1)) ls_a_d = lower(trim( mid(ls_tmp, j + 1))) if ls_a_d = 'd' or ls_a_d = 'desc' then //降序 ls_a_d = DESC_SIGN else ls_a_d = ASC_SIGN end if if ls_col + ls_a_d <> '' then ls_text = this.describe(ls_col + "_t.text") if right(ls_text, len(ls_a_d)) = ls_a_d then ls_text = left(ls_text, len(ls_text) - len(ls_a_d)) this.modify(ls_col + "_t.text = '" + ls_text + "'") end if end if end if ls_sort = trim(mid(ls_sort, i + 1)) i = pos(ls_sort, ',') loop end subroutine public function integer of_add_sort_sign_noredraw (string as_sort); //======================================================================================================================== // 根据as_sort字符串,设置数据窗口的排序标示 //======================================================================================================================== //排序规则没有发生改变则返回 if lower(as_sort) = lower(this.object.datawindow.table.sort) and this.describe("text_for_sort_only.text") <> '!' then return -1 //设置前先清除旧的排序 of_clear_sort_sign(this) //新的排序规则为空,则不需要进行排序 if as_sort = "" then return -1 end if //设置新的排序 string ls_tmp, ls_col, ls_a_d, ls_text if right(as_sort, 1) <> ',' then as_sort += "," //"bm_sp a, barcode d, gg a," long i,j i = pos(as_sort, ',') //记录排序前的行顺序,以便将来还原用 string ls_sorttext ls_sorttext = this.describe("text_for_sort_only.text") if ls_sorttext = '!' or ls_sorttext = '?' then this.modify('create text(band=background alignment="2" text="未排序" border="0" color="16777215" x="0" y="0" height="0" width="0" html.valueishtml="0" name=text_for_sort_only visible="0" font.face="宋体" font.height="-9" font.weight="400" font.family="2" font.pitch="2" font.charset="0" background.mode="1" background.color="536870912" )') ls_sorttext = '未排序' end if if ls_sorttext = '未排序' and this.rowcount() <= 1000 then //未排序,则记录当前的行id顺序 ls_sorttext = "," for j = 1 to this.rowcount() yield() ls_sorttext += string(this.GetRowIdFromRow(j) ) + ',' next this.modify("text_for_sort_only.text = '" + ls_sorttext + "'") end if do while i > 0 ls_tmp = trim(left(as_sort, i - 1)) j = pos(ls_tmp, ' ') if j > 0 then ls_col = trim(left(ls_tmp, j - 1)) ls_a_d = lower(trim( mid(ls_tmp, j + 1))) if pos(',d,desc,descending,di,ds,', ',' + ls_a_d + ',') > 0 then //降序 ls_a_d = DESC_SIGN else ls_a_d = ASC_SIGN end if if ls_col + ls_a_d <> '' then ls_text = this.describe(ls_col + "_t.text") if right(ls_text, len(ls_a_d)) <> ls_a_d then ls_text = ls_text + ls_a_d this.modify(ls_col + "_t.text = '" + ls_text + "'") end if end if end if as_sort = trim(mid(as_sort, i + 1)) i = pos(as_sort, ',') loop return 1 end function public function integer of_add_sort_sign (string as_sort); //======================================================================================================================== // 根据as_sort字符串,设置数据窗口的排序标示 //======================================================================================================================== //排序规则没有发生改变则返回 this.setredraw(false) int li li = of_add_sort_sign_noredraw(as_sort) this.setredraw(true) return li end function public subroutine uf_create_drag_object (); //==================================================================== // 增加拖动控件t_for_drag //==================================================================== if Describe("t_for_drag.x") = '!' then //控件不存在,才新增 string ls_col if il_line_color = -1 then il_line_color = rgb(128,128,128) modify('create roundrectangle(band=foreground ellipseheight="36" ellipsewidth="41"x="0" y="0" height="12" width="' + string(min(width,of_get_dw_right_column(this, ls_col))) + '" name=rr_for_drag visible="0" brush.hatch="6" brush.color="15793151" pen.style="0" pen.width="6" pen.color="' + string(il_line_color) + '" background.mode="2" background.color="16711935" )') string ls_color ls_color = of_describe(is_drag_col + ".background.color", this.getrow()) if not isnumber(ls_color) then ls_color = "67108864" modify('create text(band=foreground alignment="2" text="100" border="6" color="' + string(il_text_color) + '" x="0" y="0" height="' + this.Describe(is_drag_col + ".Height") + '" width="130" html.valueishtml="0" name=t_for_drag visible="0" font.face="Times New Roman" font.height="-9" font.weight="700" font.family="1" font.pitch="2" font.charset="0" background.mode="2" background.color="' + ls_color + '"') end if end subroutine public function string of_describe (string as_describe, long row);string str_return str_return = this.describe(as_describe) if pos(str_return, "~t") < 1 then return str_return if left(str_return, 1) = '"' or left(str_return, 1) = "'" then str_return = mid(str_return, 2) if right(str_return, 1) = '"' or right(str_return, 1) = "'" then str_return = left(str_return, len(str_return) - 1) str_return = mid(str_return, pos(str_return, "~t") + len("~t")) if row < 1 or row > this.rowcount() then row = this.getrow() if row = 0 then return '' return this.describe("evaluate(~"" + str_return + "~"," + string(row) + ")") end function public function long of_get_dw_right_column (ref string as_col);/*================================================ * 功能:取得数据窗口最右边一对象(可能是column或computer或其他可视化dwobject) * 参数:datawindow as_dw * string as_col * 返回:最右边横坐标 *===============================================*/ long ll_,ll_max=0 string ls_objects,ls_object,ls_ret int li_pos ls_objects = Describe("DataWindow.Objects") + "~t" li_pos =pos(ls_objects,'~t') do while li_pos>0 ls_object = left(ls_objects,li_pos -1) if of_Describe(ls_object+".Visible", 1)='1' and of_describe(ls_object+".Band", 1)='detail' then ll_=integer(of_Describe(ls_object+".x", 1)) +integer(of_Describe(ls_object+".width", 1)) if ll_>ll_max then ll_max=ll_ ls_ret=ls_object end if end if ls_objects = mid(ls_objects,li_pos+1) li_pos =pos(ls_objects,'~t') loop as_col =ls_ret return ll_max end function public subroutine uf_drag_end (); //==================================================================== // 结束拖动,还原 //==================================================================== //弹起鼠标左键 this.Drag (end!) il_drag_down = 0 ib_draging = false ib_draging_other = false ib_created = false modify("t_for_drag.visible = '0' rr_for_drag.visible = '0' ") end subroutine public subroutine uf_drag_move_row (); //==================================================================== // 移动行,将行从row_from 移动 row_to //==================================================================== if lower(Object.DataWindow.ReadOnly) = "yes" then return long row_from, row_to row_from = il_drag_down row_to = il_last_dragmove if row_from = 0 or row_from = row_to then return this.RowsMove(row_from, row_from, primary!, this, row_to + 1, Primary!) if row_from > row_to then setrow(row_to + 1) else setrow(row_to) end if end subroutine public function long of_get_row_bottom (long row); //==================================================================== // 根据行号取得该行的底部相对数据窗口的y值 //==================================================================== //if this.Object.DataWindow.Processing = '0' then return -1 long li_parenty, li_y, li_colheight, li_detailheight, li_coly, li_colheaderheight, li_rowsafterfirst,li_objheight long li_vpos, li_dwy, li_dwborder, li_dwtitlebar, li_dwtitleborder int li_counter string ls_tempheaderheight, ls_colname // Get exact pointers. // li_pointerx = this.PointerX() // li_pointery = this.PointerY() // // // Get the DataWindow X/Y coordinates, Border width, and Title width. // li_dwx = this.X // li_dwy = this.Y // Get the X/Y point of the Left/Upper location for this column. // Get the Height for this column and for the the Detail portion. ls_colname = this.Describe("#1.name") li_coly = Integer(this.Describe( ls_colname + ".Y")) li_colheight = Integer(this.Describe(ls_colname+".Height")) //ls_colname+".Height" li_detailheight = Integer(this.Describe("DataWindow.Detail.Height")) // Get the height of the column header(s). ls_tempheaderheight = this.Describe("DataWindow.Header.Height") DO WHILE Pos(ls_tempheaderheight,"!") = 0 li_colheaderheight += Integer(ls_tempheaderheight) li_counter ++ ls_tempheaderheight = this.Describe("DataWindow.Header"+string(li_counter)+".Height") LOOP // 取得屏幕上显示的第一行数据的行号 li_rowsafterfirst = row - Long(this.Describe("DataWindow.FirstRowOnPage")) //取得垂直滚动条的位置,freefrom 格式的数据窗口,才需要考虑 if integer(this.Describe("DataWindow.Processing")) = 0 then li_vpos = Integer (this.Describe("DataWindow.VerticalScrollPosition")) else li_vpos = 0 end if //li_vposMax = Integer (this.Describe("DataWindow.VerticalScrollMaximum")) // Determine the Height of the column holding the dropdown. li_objheight = li_colheight // Calculate the X and Y Coordinates (check that it does not go past borders). li_y = li_parenty + li_dwy + li_dwborder + li_dwtitleborder + li_dwtitlebar + & li_colheaderheight + (li_detailheight * li_rowsafterfirst ) + & li_detailheight - li_vpos - 3 return li_y end function event clicked;setrow(row) end event event rowfocuschanged;selectrow(0 ,false) selectrow(currentrow ,true) end event on uo_datawindow.create end on on uo_datawindow.destroy end on event constructor;if 行指示 = true then SetRowFocusIndicator(Hand!) end event event dragdrop; //==================================================================== //释放拖动的行,结束拖动 //==================================================================== if ib_draging then //移动行 uf_drag_move_row() //结束拖动模式 uf_drag_end() else //结束拖动模式 uf_drag_end() end if end event event dragleave;if source <> this then il_drag_down_other = 0 uf_drag_end() end if modify("t_for_drag.visible = '0' rr_for_drag.visible = '0' ") end event event dragwithin; //==================================================================== // 拖动过程中,鼠标所指向的行发生改变时 //==================================================================== long ll_row ll_row = row if ib_draging or ib_draging_other then //如果第一行不可移动,则其他行被拖到第一行之前时,不做处理 if ib_first_row_countmove and ll_row = 0 then return //行发生改变时,才进行的操作 //setredraw( false) if il_last_dragmove <> ll_row then //取得当前光标下的数据带 string ls_band ls_band = lower(GetBandAtPointer()) //如果行号为0,且数据带为detail或summary,则表示光标当前在所有行的下面,需要默认为将行拖动到最后 if (left(ls_band, 6) = 'detail' or left(ls_band, 7) = 'summary') and ll_row = 0 then //头部 'detail'header ll_row = rowcount() end if //设置新的行 il_last_dragmove = ll_row //修改行插入位置 modify("rr_for_drag.y = '" + string(of_get_row_bottom( ll_row)) + "' rr_for_drag.visible = '1'") end if //鼠标移动时,就发生的操作 //修改用于指示被拖动行行号的控件的位置 int li_w li_w = nvll(long(this.describe("t_for_drag.width")), 130) modify("t_for_Drag.color = '" + string(il_text_color) + "' t_for_drag.x = '" + string(pointerx() -35 - li_w) + "' t_for_drag.y = '" + string(pointery() + 38) + "' t_for_drag.visible = '1'") //setredraw( true) end if end event event rbuttondown;if ib_draging or ib_draging_other then uf_drag_end() end if Return 1 end event
其中用到的一个全局函数nvll
global type nvll from function_object end type forward prototypes global function any nvll (any ai, any an) end prototypes global function any nvll (any ai, any an);if isnull(ai) then return an return ai end function