这是一个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