Time to change; using a timer OCX in OpenEdge
Tags: openedge, progress, datadigger, coding
Published: 2018-01-22 20:00:24

---
title: "Time to change; using a timer OCX in OpenEdge"
published: true
tags: OpenEdge, Progress, DataDigger, coding
canonical_url: https://datadigger.wordpress.com/2018/01/17/time-to-change/
---

_The DataDigger is an open source database browser for developers in OpenEdge. It enables them to view, update, delete, im- and export the data inside the database. The DataDigger is written fully in OpenEdge 4GL and has over 40,000 lines of code. Inside are some real treasures, so I will dissect the DataDigger, to reveal them. Today: using a timer to improve the UI._

Have you ever looked closely to what DataDigger does when you change files? If not, I would like to invite you to do so. Right now. Go ahead, I’ll wait. Startup DataDigger, set focus on the list of tables and press cursor-down once. At the right you will see the fields of the selected table:

![ablvtco](https://datadigger.files.wordpress.com/2018/01/ablvtco.png?w=840)

No news here. Press cursor-down again and immediately again. And again. Note what happens with the field browse. Did you notice? If you were fast enough, the field browse did not update. It skipped, because it knew that you did not intend to look at it anyway.

#### How did it know that?

It’s elementary my dear, because you didn’t stay long enough on the table name to show the fields. There is a small delay in showing the fields. I’ll show you how it is done.

I created a small demo that can be downloaded from [GitHub](https://github.com/patrickTingen/BlogSrc/tree/master/2018-01-17)&nbsp;to show how it’s done. If you download it and run&nbsp;wCustPerSalesrep1.w against the classic sports database you will see something like this:

![snvh001](https://datadigger.files.wordpress.com/2018/01/snvh001.png?w=840)

This is a very minimal implementation, but browse through the sales reps and you will see the related customers at once. Now imagine that in order to collect the child records (in this case the customers) might take some time. What would happen to the browse? Suppose you wanted to move from sales rep BBB to GPE using the cursor keys. That would mean 3 key presses. But on each sales rep that is in between, we would need to collect the data, which would be a waste of time. To illustrate this, just uncomment some code in the VALUE-CHANGED trigger of the left browse to make it look like this:

```
ON VALUE-CHANGED OF brSalesrep IN FRAME DEFAULT-FRAME
DO:
  ETIME(YES).
  DO WHILE ETIME < 500: END.
  {&OPEN-QUERY-brCustomer}
END.
```

This will simulate that the code that runs to collect the customers takes haf a second to complete. Who knows? It might be running on an appserver over a relative slow connection. Now&nbsp;run it again. Notice the annoying delay? Time to fix it.

#### Introducing the timer

The idea is as follows: if the user chooses another sales rep, then wait a few milliseconds to see if the user changes again (like we did when we pressed cursor-down 3 times). If it looks like he is not going to do that, perform the value-changed. The time to wait is delicate: too short has no effect while waiting too long is just as bad as the cause. In practice, a time of approximately 250-350ms is good. For the DataDigger I started with 350 but later brought it back to 300ms because it felt a bit snappier.

Run&nbsp;wCustPerSalesrep2.w and use the cursor keys to navigate through the sales rep records. If you are fast enough, you will see that the customer browse will not change as long as you keep changing tables. Release the keys and a after a short while the customer browse will refresh.

Let’s look at the code. The value-changed of the browse has changed a bit:

```
ON VALUE-CHANGED OF brSalesrep IN FRAME DEFAULT-FRAME
DO:
  chCtrlFrame:PSTimer:INTERVAL = 300.
  chCtrlFrame:PSTimer:ENABLED = TRUE.
END.
```

The code to actually refresh the customer browse can now be found in the pstimer.tick procedure:

```
PROCEDURE CtrlFrame.PSTimer.Tick.
  {&OPEN-QUERY-brCustomer}
  chCtrlFrame:PSTimer:ENABLED = FALSE.
END PROCEDURE.
```

You may notice that I turn the timer off and on. This is because we want the timer to start again every time we have a new record. In the timer.tick we turn the timer off. After all: we only need to wait until the user chooses another record.

#### Tweaking leads to tweaking

You will notice that once you start tweaking around, you often end up tweaking ad infinitum. Run the program and point to one of the sales reps with your mouse. Why is the program waiting now? You – as a user – pointed EXACTLY at the sales rep you had in mind. No need to wait for the program. So you might want to uncomment the code in the MOUSE-SELECT-CLICK event to make it look like:

```
ON MOUSE-SELECT-CLICK OF brSalesrep IN FRAME DEFAULT-FRAME
DO:
  {&OPEN-QUERY-brCustomer}
  RETURN NO-APPLY.
END.
```

This will take care of the small delay when selecting with the mouse. Run it again and you will notice that once you select with the mouse, the customer browse is refreshed instantly

&nbsp;

That’s it. Let me know if you have used a technique like this in your own project. In a next post I will show you what to do if you have multiple delayed events that you want to take care of. For now: have fun!