Showing posts with label Best Practices. Show all posts
Showing posts with label Best Practices. Show all posts

January 31, 2013

Behavior of Tab Canvases

The behavior of tab canvases ist very interesting, when your form gets more and more tabpages. Let's say, you have only three pages in your tab canvas. (Width Style Property = Fixed)

Forms automatically renders all three pages in the same size. That's what we expected.

In the next step we create a fourth tab:

If there is not enough space for all page-labels in the same size, then we see a first kind of resizing. All labels are readable. But the size of some pages is reduced.

If we create more tabpages:
At one point the label-text shrinks and some letters were exchanged by dots.

And in the last stage:

The last type of look and feel is, when we get a horizontal scrollbar. Think on this, when you use many tabpages in your form

Have fun
Gerd

January 17, 2011

Versioning forms and comparing sourcecode

Comparing sourcecodes of different versions of the same FMB is very important while developing an application or during maintenance.

If you want to store all versions of your FMB's, then they are two ways:

Manual versioning

Each version of all files is stored under its name plus the versionnumber. E.g. emp_27.fmb, emp_28.fmb, ... In this case "emp" + "_27" + ".fmb".

Parallel to each version you store the textversion of the FMB, emp_27.txt, emp_28.txt and so on. You get the textversion in forms through Edit-Administration-"Object list report".

For viewing the changes between two versions you can use tools like Beyond Compare, my favorite compare tool.



Using Subversion, Git or another VCS

Using a version control software is the other approach. But here we have the problem, that storing the binary file in tools like Subversion didn't solve our origin problem, finding sourcecode differences between two versions. Storing the textversion of the binary FMB plus the forms FMB is here the best practice for the check-in.

If we now want to see the changes between two version, we can easily use the builtin features of the versioning tool:


just use it
Gerd

May 05, 2010

Migrate your charset to UTF8, annotation to step 3

After migrating to UTF8 you may have problems with your report-server. This is, when your reports cannot be displayed and internally the server throws a "Canceled as server is shutting down"

With UTF8 you need a bigger cache-size in "report server-parameter". Easiest way, when you run into problems, double up the value of the parameter.

Try it
Gerd


Back to part 3 of the article

April 28, 2010

Migrate your charset to UTF8, step 3

Applications without Reports are useless :-)

So we have to change some things in the Reports Environment to enable UTF8 in PDF-Output.

First

you have to edit in your OAS Report-Server the report-config:




Add one "environment id" per section. A section is in this example development, test and production. After that, each section has defined it's own NLS_LANG and report-path.

Second

You can use the new sections through Forms. Before starting the report you add another parameter to the paramlist:

Add_Parameter (V_ParamListe, 'ENVID', TEXT_PARAMETER, 'NLS-PROD');

Now you can control the NLS_LANG of your reportserver.


Third

Last checkpoint for your reports is the correct mapping between your fonts and your TrueType-Fonts (in this case we have a windows-system)

Edit the file "uifont.ali" in the directory \tools\common and add the following lines in the section [ PDF:Subset ]

Arial..Italic.Bold..             = "c:\windows\fonts\arialbi.ttf"
Arial...Bold..                   = "c:\windows\fonts\arialbd.ttf"
Arial..Italic...                 = "c:\windows\fonts\ariali.ttf"
Arial.....                       = "c:\windows\fonts\arial.ttf"

"Courier New"..Italic.Bold..     = "c:\windows\fonts\courbi.ttf"
"Courier New"...Bold..           = "c:\windows\fonts\courbd.ttf"
"Courier New"..Italic...         = "c:\windows\fonts\couri.ttf"
"Courier New"                    = "c:\windows\fonts\cour.ttf"

"Times New Roman"..Italic.Bold.. = "c:\windows\fonts\timesbi.ttf"
"Times New Roman"...Bold..       = "c:\windows\fonts\timesbd.ttf"
"Times New Roman"..Italic...     = "c:\windows\fonts\timesi.ttf"
"Times New Roman"                = "c:\windows\fonts\times.ttf"


In this example windows has its fonts in the directory c:\windows\fonts\

have fun
Gerd

To be continued with Migrate your charset to UTF8, annotation to step 3

Back to part 2 of the article

April 07, 2010

Migrate your charset to UTF8, step 2

Now, after changing the NLS to UTF8 we may have problems with hotkeys.

That's because the nls-change to UTF8 will now use a different resource-file. Instead of fmrweb.res the fmrweb_utf8.res is used. The resource-files are located in the forms-home-directory.

If you have used "term" in your formsweb.cfg - otherparams, then you point hardcoded to a specified file. Here you have to change the value of the parameter or you have to exchange the content of the file.

e.g. changing the value of the parameter:
old: otherParams=term=\fmrweb.res
new: otherParams=term=\fmrweb_utf8.res

After this changes you can use the same hotkeys like before


To be continued with Migrate your charset to UTF8, step 3

Back to part 1 of the article

March 31, 2010

Migrate your charset to UTF8 in 3 steps

What do we have to do in your forms application, when the database in the backend is upgraded from a single-byte charset to a UTF8-charset.

First Step

Make a backup of your forms-sources, your local forms installation and your application server configs.

After that change the NLS_LANG in your registry. You can create a backup of the parameter, through creating a new parameter named "NLS_old" with the value of the old NLS_LANG-value. The new value of NLS_LANG is for example "GERMAN_GERMANY.UTF8". This change is for your local forms builder, when you recompile your forms sources.

Now we can edit our local default.env. If there is a line with the NLS_LANG, then change the value to the UTF8-value (see above) or create a new line with the NLS_LANG. This change is for our local OC4J instance only.

Do the same change on the application server (use the OEM for edits)

These changes were the basic environment-changes we need for UTF8.


To be continued with Migrate your charset to UTF8, step 2

August 31, 2009

Forms Debugger - hidden Feature

The Forms 10g debugger is much better than the Forms 6i debugger. He is completly new written and has the ability to debug remote. So you can look into a running session of an user and search for errors. This is in the new web-environments a powerful method to find problems.

And that's only one aspect of the new debugger.


The debugger works in two different modes: The stop-mode is well-known, because you can use there all functions of the debugger. He is active, while you investigate the code. You can work in this work, through a breakpoint e.g.


The run-mode is the other one. He can be found only, while the form is running in the foreground.


And at that point you can press the break-button, which is one of the most interesting features in the debugger. It creates a breakpoint dynamically in the next line of code, which will be executed.

So, if you press the button, nothing happens. If you then return from the Forms Builder back to the runform, the next event in the form starts the debugging-process. And then the debugger shows you the first line of code in that trigger, which will be executed next. So you don't have to think to much, where to set breakpoints and so on... just use the break-button.

That's my tip of the day
Gerd

June 29, 2009

Disabling a Trigger

If you have a trigger and you want to quickly disable him, then just use the "_"-technique :



In this case we have a Key-Create-Record-Trigger which should be disabled. Rename the "-" to "_" in the name of the trigger and from that point on the trigger is a user-named-trigger, which won't fire through an event.



Important: You can't rename the trigger to "KEY-CREREC2" or something else. The hyphen is in forms reserved for event-triggers.

To activate the trigger rename it back to "-" and that's all.

Have fun
Gerd

February 27, 2009

Filtering data through multiple rows

Lets say we have created a form on the table EMP and want to filter the data, so that only the Employees from Department 20 and 30 are displayed. The best UI for the user is a filter-block, where you see all departments and can mark them.

In this filter we click on the checkboxes for department 20 and 30:



The button Query data (Abfrage starten) starts a query on the emp-block.



What do we need for this technique?

-) A CONTROL-block with an item TI_Filter_String (char, 2000)
-) A checkbox CB_Filter in the DEPT-block (numeric, 0-unchecked, 1-checked)

The button, which starts the query, needs a WHEN-BUTTON-PRESSED:


:Control.TI_Filter_String := ';';
go_block ('DEPT');
first_record;
LOOP
IF :DEPT.CB_Filter = 1 THEN
:Control.TI_Filter_String := :Control.TI_Filter_String || :DEPT.DEPTNO || ';';
END IF;
IF :SYSTEM.LAST_RECORD = 'TRUE' THEN
EXIT;
ELSE
Next_Record;
END IF;
END LOOP;
go_block ('EMP');
execute_query;


The EMP-block needs this default-where:


:Control.TI_Filter_String LIKE '%;' || DEPTNO || ';%'

The trick is, that each deptno from the filter-string can be found using the LIKE %;...;% - technique:



Have fun with this little trick!
Gerd

January 19, 2009

Forms Function Numbers

Editing the fmrweb.res to assign hotkeys to Forms Functions is not that easy. The syntax is described inside the file and there are no problems with the parameters JFN, JMN, URKS and URFD. But what IDs are used for FFN ?


# JFN : JMN : URKS : FFN : URFD (whitespace ignored)
#
# JFN = Java function number
# JMN = Java modifiers number
# URKS = User-readable key sequence (double-quoted)
# FFN = Forms function number
# URFD = User-readable function description (double-quoted)

Here it the complete list:

FFN Description
-----+---------------
1 Next Field
2 Previous Field
3 Clear Field
4 Left Arrow
5 Right Arrow
6 Up Arrow
7 Down Arrow
8 Goto Beginning of Line
9 Goto End of Line
10 Goto Extreme Vertical Up
11 Goto Extreme Vertical Down
12 Scroll Up
13 Scroll Down
14 Scroll Left
15 Scroll Right
16 Delete Character Left
17 Delete Character Right
18 Delete Line
19 Move Cursor Left
20 Move Cursor Right
21 Scroll-Up
22 Invoke Editor for Field
23 Delete Character ??
/ 23 Insert Line ??
24 Search
25 Toggle Insert/Replace Mode
26 Select Item
27 Return
28 Invoke Menu
29 List of Values
30 Help
31 Redraw Screen
32 Exit
35 Show Keys
36 Accept
61 Next Primary Key
62 Clear Record
63 Delete Record
64 Duplicate Record
65 Insert Record
66 Next Set
67 Next Record
68 Previous Record
69 Clear Block
70 Block Menu
71 Next Block
72 Previous Block
73 Duplicate Field
74 Clear Form
75 Enter
76 Enter Query
77 Execute Query
78 Display Error
79 Print
80 Count Query
81 Update Record
82 User Defined Key 0
83 User Defined Key 1
84 User Defined Key 2
85 User Defined Key 3
86 User Defined Key 4
87 User Defined Key 5
88 User Defined Key 6
89 User Defined Key 7
90 User Defined Key 8
91 User Defined Key 9
92 Clear Eol
95 List Tab Pages
11022 Accelerator Key 1
11023 Accelerator Key 2
11024 Accelerator Key 3
11025 Accelerator Key 4
11026 Accelerator Key 5
11027 Accelerator Key 6
11028 Accelerator Key 7
11029 Accelerator Key 8
11030 Accelerator Key 9
11031 Accelerator Key 10


Have fun with the Forms Function Numbers !
I'll check as soon as possible, why the Nr. 23 is duplicated in the notes from Oracle...
Gerd

December 17, 2008

Tab-Canvases and F2

I just found an interesting undocumented feature:


While the cursor is inside a tab-canvas you can press F2


Then you see a little list-item in the upper-right corner of the tab-canvas. There you can move up, down and press Enter or Return.


This starts the WHEN-TAB-PAGE-CHANGED-trigger. Here you can do whatever you want. For example a navigation to a block and starting a query.

Have fun
Gerd

October 15, 2008

Views based on Year, Month and Day

While developing applications I need often list-of-values, which have a result-set of years, months or days.

You can hard-code those selects each time in each form, but much more elegant is to create views, which do the whole work.

Here are 3 views for years, months and days:


CREATE OR REPLACE FORCE VIEW YEARS_V
(YDATE) AS
SELECT add_months (trunc (sysdate, 'YYYY'), 12 * (50 - Level))
FROM Dual
CONNECT BY Level <= 100;

CREATE OR REPLACE FORCE VIEW MONTHS_V
(MDATE) AS
SELECT add_months (trunc (sysdate, 'MM'), 500 - Level)
FROM Dual
CONNECT BY Level <= 1000;

CREATE OR REPLACE FORCE VIEW DAYS_V
(DDATE) AS
SELECT trunc (sysdate) + 15000 - Level
FROM Dual
CONNECT BY Level <= 30000;


Those Views helps us to Select Data for the

- actual year +/- 50 years
- actual month +/- 500 months
- actual day +/- 15000 days

In a Record-Group you can use those views:

LOV of the next 10 years

SELECT YDATE
FROM Years_V
WHERE YDATE BETWEEN trunc (sysdate, 'YYYY')
AND add_months (trunc (sysdate, 'YYYY'), 10*12);


LOV of the last 30 and the next 10 days

SELECT DDATE
FROM Days_V
WHERE DDATE BETWEEN trunc (sysdate-30) AND trunc (sysdate+10);


Try it
Gerd

July 21, 2008

Finding all Items in the layout-editor at once

To find all items, which are displayed in the layout editor at once in the Object Navigator, press Ctrl+A, for select All.



After the Ctrl+A you have all Objects marked in the Tree:



have fun
Gerd

June 26, 2008

Faster compilation in Forms Builder

You can speed up the time for a "Compile All", when you close all nodes in the Object Navigator, so that the form shows only the name of the form. Then you press Ctrl+Shift+K for Compile All.


Compile-Times of a normal pl/sql-library with 70 program units


closed nodes : 2 sec
open nodes : 18 sec

Compile-Times of a big pl/sql-library with 130 program units

closed nodes : 2 sec
open nodes : 34 sec

Compile-Times of a medium form with 14 blocks

closed nodes : 3 sec
open nodes : 12 sec

Compile-Times of a big form with 24 blocks and much sourcecode

closed nodes : 6 sec
open nodes : 37 sec



With this little trick you can compile really fast !
try it
Gerd

June 19, 2008

Compile or Compile All ?

What is the best way to compile a form? Before I answer this question here are some explanations:


Compile Incremental : Ctrl + K
Compile All : Shift + Ctrl + K
Compile Module (Generate): Ctrl + T
Run : Ctrl + R

In the older versions of Forms the Compile Module was known as Generate. I prefer this, because the Ctrl+T generates the FMX.

During my daily work I open forms and maintain them. If I use the Ctrl+T to generate the FMX, then Oracle Forms starts implicitly a Compile Incremental before the Generate.

And that's the problem. In 9 of 10 cases the generated FMX is OK, but sometimes the automatical Compile Incremental didn't work properly. It results in non-reproducable errors at runtime.

My solution for this problem is:

After opening a form I start immediately a Compile All. Each Incremental Compile and each Generate now works without runtime-problems.

Try it
Gerd

June 05, 2008

Forms Shutdown

In the article forms-startup I wrote last year how to hide the browser-window, while starting a forms-application. Another problem is: How can we close the browser-window after exiting the forms-application. Here is my favorite solution:

1) Create a new html-file e.g. close.html in your html-directory. This is the main routine, which closes the browser-window.


< BODY onLoad="window.close();" >

2) Set the formsweb.cfg parameter HTMLbeforeForm in the server-directory. This eliminates the security-question "Do you want to close the browser-window".

HTMLbeforeForm=< SCRIPT LANGUAGE="JavaScript" >window.opener = top;< /SCRIPT >

3) The form, which closes the main-application needs a POST-FORM-trigger. /forms/html is a virtual-directory, which points to the close.html.

web.show_document ('/forms/html/close.html', '_self');

Used directories:

< DevSuite-Home > : Your Developer-Suite Home Directory
html-directory : < DevSuite-Home >\tools\web\html
server-directory : < DevSuite-Home >\forms\server
virtual-html-directory : /forms/html defined in forms.conf

Many thanks to Duncan Mills, Frank Nimphius and Richard Squires, who posted this code in the OTN years ago.

Pro) This technique works on IE 6 and IE 7, tested with JInitiator and Sun-Plugin.
Contra) No Firefox-Support. Since Firefox 2.0 it isn't allowed to close a window via JavaScript.

Important: The limitations of this blog forced me to write blanks after each "<" and before each ">". Don't write them, when you use this technique !

have fun
Gerd

June 02, 2008

Open-Form and the Exit-Strategy (2)

Sometimes you use your source-codes since years and think - there is no easier, better and smarter way to do something, like the way in that piece of code.

So here. After writing and testing my last post everything runs well!

Today I refactored some parts of my exit-strategy code and created this much easier solution (normally this is not the goal of refactoring !):

all you need is a

KEY-EXIT in the startform:


COPY ('TRUE', 'GLOBAL.EXIT_IMMEDIATE');
EXIT_FORM (no_validate);

and a WHEN-FORM-NAVIGATE in all other forms

DEFAULT_VALUE ('FALSE', 'GLOBAL.EXIT_IMMEDIATE');
IF :GLOBAL.EXIT_IMMEDIATE = 'TRUE' THEN
EXIT_FORM (no_validate);
END IF;


Now we have a chain reaction, when exiting the startform. Each closing form will let the focus jump to another open form. Then the WHEN-FORM-NAVIGATE triggers and closes this form too. Because the global variable was set to AUTOCLOSE = TRUE.

After the last form the whole application is closed and that's the best way to close an entire application.

If some of those forms started other forms through call_form, then you have to use the WHEN-WINDOW-ACTIVATED, because the WHEN-FORM-NAVIGATE won't trigger while getting the focus.

Isn't that a really easy solution?
Have fun with it
Gerd

May 26, 2008

Open-Form needs an Exit-Form-Strategy

This article is for all of us, who work with OPEN_FORM instead of CALL_FORM.

OPEN_FORM has benefits and problems. The user can easily switch between all open forms, but when he closes one of the forms, he only closes the current form.

Solution: Normally all applications have a startform, from where all other forms were opened. When the user is in this form and he presses exit-form, then he wants to close the whole application and not only the startform. In this case we need a method, which loops through all open forms and closes them.

Finding all open forms is a hard job. So, the best way is to store all of them in a global list named GLOBAL.OPEN_FORMS. Values are separated by semicolons, like: ;STARTFORM;EMP;DEPT;

We need a PRE-FORM and a POST-FORM-trigger for all forms, except the startform. The Pre-Form appends the name of the current form to the list, the Post-Form erases an entry.

PRE-FORM :


DEFAULT_VALUE (';', 'GLOBAL.OPEN_FORMS');
:GLOBAL.OPEN_FORMS := :GLOBAL.OPEN_FORMS ||
:SYSTEM.CURRENT_FORM || ';';

POST-FORM :

:GLOBAL.OPEN_FORMS := REPLACE (:GLOBAL.OPEN_FORMS,
';' || :SYSTEM.CURRENT_FORM || ';',
';');

Now we have the names of all open forms in a global list.

The KEY-EXIT trigger in the startform needs a loop, which closes all other forms and at then startform.


KEY-EXIT
in startform :

DECLARE
V_Form VARCHAR2 (30);
BEGIN
One_Time_Timer.Initialize ('EXIT_STARTFORM');
DEFAULT_VALUE (';', 'GLOBAL.OPEN_FORMS');
WHILE :GLOBAL.OPEN_FORMS != ';'
LOOP
V_Form := Substr (:GLOBAL.OPEN_FORMS,
2,
InStr (:GLOBAL.OPEN_FORMS, ';', 1, 2) - 2);
COPY ('J', 'GLOBAL.EXIT_IMMEDIATE');
GO_FORM (V_Form);
END LOOP;
END;

The startform is closed through WHEN-TIMER-EXPIRED :

IF One_Time_Timer.Get_Value = 'EXIT_STARTFORM' THEN
EXIT_FORM (no_validate);
END IF;

All other forms need a WHEN-FORM-NAVIGATE trigger:

DEFAULT_VALUE ('N', 'GLOBAL.EXIT_IMMEDIATE');
IF :GLOBAL.EXIT_IMMEDIATE = 'J' THEN
EXIT_FORM (no_validate);
END IF;


Now you have a powerful autoclose-method for all opened forms.

Have fun
Gerd


Remember the One-Time-Timer article or use this packages:

PACKAGE Const IS
gbl_One_Time_Timer CONSTANT VARCHAR2 (61) :=
upper ('global.One_Time_Timer');
END;

PACKAGE One_Time_Timer IS
FUNCTION Get_Value RETURN VARCHAR2;
PROCEDURE Initialize (P_Event IN VARCHAR2);
END;

PACKAGE BODY One_Time_Timer IS
FUNCTION Get_Value RETURN VARCHAR2 IS
BEGIN
Default_Value (NULL, Const.gbl_One_Time_Timer);
RETURN (NAME_IN (Const.gbl_One_Time_Timer));
END;

PROCEDURE Initialize (P_Event IN VARCHAR2) IS
tm_id timer;
tm_name VARCHAR2 (30) := 'ONE_TIME_TIMER';
BEGIN
tm_id := Find_Timer (tm_name);
IF ID_Null (tm_id) THEN
tm_id := Create_Timer (tm_name, 10, NO_REPEAT);
COPY (p_Event, Const.gbl_One_Time_Timer);
END IF;
END;
END One_Time_Timer;

February 08, 2008

LOV with splitted data

I found an easy technique to visualize data in lov's like this:



Use multiple UNION ALL's to concatenate the data :


select '---new colleagues---' ename, NULL job, NULL hiredate
from dual
UNION ALL
select ename, job, to_char (hiredate, 'DD.MM.YYYY')
from emp where hiredate >= to_date ('01.07.1981', 'DD.MM.YYYY')
UNION ALL
select '---before 07/81---' ename, NULL job, NULL hiredate
from dual
UNION ALL
select ename, job, to_char (hiredate, 'DD.MM.YYYY')
from emp where hiredate < to_date ('01.07.1981', 'DD.MM.YYYY')

have fun and use it
Gerd

January 11, 2008

Hotkey F1 in Forms 10g

Since Forms 10g we have problems with F1. He doesn't work like in the older versions.

The Key-Mapping for KEY-HELP e.g. is now Ctrl+H instead of the good old F1.

If you want to have it work like in Forms 6i, then you can change the fmrweb.res:

The internal ID of F1 is 112, the ID of KEY-HELP-Trigger is 30:


...
113 : 0 : "F2" : 95 : "List Tab Pages"
112 : 0 : "F1" : 30 : "Help"
72 : 2 : "Ctrl+H" : 30 : "Help"

have fun
Gerd