All credit to go to Metalink...
Doc ID:
Note:117494.1
Subject: How to Implement Iconic Buttons Having Different Images in a Multirecord-Block ?
Type: FAQ
Status: PUBLISHED
Content Type: TEXT/PLAIN
Creation Date: 15-AUG-2000
Last Revision Date: 29-OCT-2002
ORACLE DEVELOPER - FORMS
------------------------
This article describes a way to work around the limitation that it is not
possible to change the icon shown on an iconic button in a multi-record-block.
SET_ITEM_PROPERTY changes the label of the button in all the records of the
block, whereas the ICON_NAME is not one of the properties which can be set
using SET_ITEM_INSTANCE_PROPERTY.
The method described in this article consists of a set of buttons, placed in a
separate-block. For each record in the multi-record-block there is one button
in the separate block. In the when-new-record-instance-trigger the icons shown
on the buttons are synchronized with the record the buttons are placed by.
To make it all work create the buttons with names 'PB_x' with x=record-number.
Suppose you have an EMP-block with 5 records shown, you have to create a control
block with buttons PB_1, PB_2, PB_3, PB_4 and PB_5.
All the triggers needed in the application invoke a procedure from a package
which can also be found in this article.
___________________________________________________________________________
FORM-LEVEL-TRIGGERS
___________________________________________________________________________
There are one or two triggers to be defined at form-level, depending on the
display of a scrollbar for the multi-record-block.
When there is no scrollbar use:
WHEN-NEW-FORM-INSTANCE-trigger:
mr_buttons.when_new_form_instance (start_timer => FALSE);
When there is a scrollbar use:
WHEN-NEW-FORM-INSTANCE-trigger:
mr_buttons.when_new_form_instance (start_timer => TRUE);
WHEN-TIMER-EXPIRED-trigger:
mr_buttons.when_timer_expired;
(When the user drags a scrollbar no trigger fires; to synchronize the images
on the buttons in this situation a timer is used which checks every x seconds
whether the top-record displayed in the multi-record-block is still the same).
___________________________________________________________________________
BLOCK-LEVEL-TRIGGERS
___________________________________________________________________________
In the control-block containing the buttons the next trigger must be defined:
WHEN-BUTTON-PRESSED-trigger:
mr_buttons.when_button_pressed;
In the multi-record-block the following triggers must be defined:
WHEN-NEW-RECORD-INSTANCE-trigger:
mr_buttons.when_new_record_instance;
PRE-QUERY-trigger:
mr_buttons.pre_query;
KEY-ENTQRY-trigger:
mr_buttons.key_entqry;
KEY-CREREC-trigger:
mr_buttons.key_crerec;
KEY-DELREC-trigger:
mr_buttons.key_delrec;
KEY-DOWN-trigger:
mr_buttons.key_down;
___________________________________________________________________________
ITEM-LEVEL-TRIGGERS
___________________________________________________________________________
There is only one item-level-trigger in this situation on the item determining
the image to be displayed on the button:
WHEN-VALIDATE-ITEM-trigger:
mr_buttons.when_validate_item;
___________________________________________________________________________
MR_BUTTONS-package
___________________________________________________________________________
This package contains all the necessary routines; the routines to be localized
can be found by searching on --####### NEEDS TO BE LOCALIZED !!!
The localizations contain eg. the name of the multirecord-block, the delay when
using timers, the names of the icons as well as the whole algorithm determining
which icons are to be shown, and the when-button-pressed-trigger on the button-
block.
PACKAGE MR_BUTTONS IS
-- form-level procedures
PROCEDURE WHEN_NEW_FORM_INSTANCE (start_timer in boolean);
PROCEDURE WHEN_TIMER_EXPIRED;
-- block-level procedures for multi-record-block
PROCEDURE WHEN_NEW_RECORD_INSTANCE;
PROCEDURE PRE_QUERY;
PROCEDURE KEY_ENTQRY;
PROCEDURE KEY_CREREC;
PROCEDURE KEY_DELREC;
PROCEDURE KEY_DOWN;
-- item-level procedure for multi-record-item
PROCEDURE WHEN_VALIDATE_ITEM;
-- block-level procedures for control-block
PROCEDURE WHEN_BUTTON_PRESSED;
END;
PACKAGE BODY MR_BUTTONS IS
MR_BLOCK_NAME VARCHAR2(50) := 'EMP'; --####### NEEDS TO BE LOCALIZED !!!
NR_OF_RECORDS NUMBER := GET_BLOCK_PROPERTY (MR_BLOCK_NAME, RECORDS_DISPLAYED);
PROCEDURE EMPTY_BUTTONS IS
BEGIN
FOR i IN 1..nr_of_records LOOP -- nr of records in block
SET_ITEM_PROPERTY('CONTROL.PB_'||TO_CHAR(i), ICON_NAME, ' ');
END LOOP;
END;
PROCEDURE RESYNC_BUTTON (recno in number) IS
BEGIN
--####### NEEDS TO BE LOCALIZED !!!
if :emp.sal is null THEN
set_item_property('control.PB_'||to_char(recno), icon_name, ' ');
elsif :emp.sal <= 2000 then
set_item_property('control.PB_'||to_char(recno), icon_name, 'afldown');
else
set_item_property('control.PB_'||to_char(recno), icon_name, 'aflup');
end if;
END;
PROCEDURE RESYNC IS
v varchar2(30);
topnr number;
curr number;
BEGIN
if :SYSTEM.MODE != 'ENTER-QUERY' then
v := get_block_property(mr_block_name, current_record);
curr := to_number(v);
v := get_block_property(mr_block_name, top_record);
topnr := to_number(v);
for i in 1 .. nr_of_records loop -- nr of records in block
set_item_property('control.PB_'||to_char(I), icon_name, ' ');
go_record(topnr+(i-1));
resync_button (i);
end loop;
go_record(curr); -- go back to the original record
:GLOBAL.TOPRECORD := V;
end if;
END;
PROCEDURE WHEN_NEW_FORM_INSTANCE (start_timer in boolean) IS
timerid timer;
BEGIN
:GLOBAL.TopRecord := 'wnfi'; -- to force resynchronisation
GO_BLOCK (MR_BLOCK_NAME);
EXECUTE_QUERY;
if start_timer then -- this will cause heavy load when running on the web !!
--####### timervalue NEEDS TO BE LOCALIZED !!!
timerid := create_timer ('RESYNC', 2000, repeat);
end if;
END;
PROCEDURE WHEN_TIMER_EXPIRED IS
v varchar2(20);
BEGIN
v := get_block_property (mr_block_name, TOP_RECORD);
if v is not null and v <> :GLOBAL.TOPRECORD then
-- resync when user has apparently dragged the scrollbar
resync;
end if;
END;
PROCEDURE WHEN_NEW_RECORD_INSTANCE IS
v VARCHAR2(2000);
BEGIN
v := GET_BLOCK_PROPERTY(MR_BLOCK_NAME, TOP_RECORD);
IF v IS NOT NULL AND V <> :GLOBAL.TopRecord THEN
resync; -- call program unit to show values
END IF;
END;
PROCEDURE KEY_CREREC IS
v VARCHAR2(2000);
topnr number;
curr number;
new_icon varchar2(200);
BEGIN
create_record;
v := :system.cursor_record;
-- temporarily set the recordstatus so that navigation out of
-- the new record is allowed; thus all scrolling forms has
-- performed to show the new record can be resync-ed to the buttons
set_record_property (v, MR_BLOCK_NAME, STATUS, QUERY_STATUS);
resync;
go_record (v);
-- and of course reset the status to its original
set_record_property (v, MR_BLOCK_NAME, STATUS, NEW_STATUS);
END;
PROCEDURE KEY_DELREC IS
BEGIN
delete_record;
resync;
END;
PROCEDURE PRE_QUERY IS
BEGIN
:GLOBAL.TopRecord := 'pq'; -- change the top record to force image-change
empty_buttons;
END;
PROCEDURE KEY_ENTQRY IS
BEGIN
:GLOBAL.TopRecord := 'ke'; -- change the top record to force image-change
empty_buttons;
ENTER_QUERY;
END;
PROCEDURE KEY_DOWN IS
BEGIN
-- when tabbing through records, create a new record after the last one
if :SYSTEM.LAST_RECORD = 'TRUE' then
do_key ('create_record');
else
next_record;
end if;
END;
PROCEDURE WHEN_VALIDATE_ITEM IS
v varchar2(30);
topnr number;
curr number;
BEGIN
v := :system.cursor_record;
curr := to_number(v);
v := get_block_property(mr_block_name, top_record);
topnr := to_number(v);
resync_button (curr+1-topnr);
END;
PROCEDURE WHEN_BUTTON_PRESSED IS
BEGIN
--####### NEEDS TO BE LOCALIZED !!!
Message('Button : '||:SYSTEM.TRIGGER_ITEM||' is pressed');
-- This will contain nr as well ....
END;
END;
References
----------
Note:42018.1 CREATING DYNAMICALLY POSITIONED LIST ITEMS IN FORMS
Describes a similar trick to position an item dynamically.