LinkLabel - Libary

dlfallen

Active Member
Licensed User
Longtime User
DoubleClick question

I'm building a program using the LinkLabel control and have successfully "wired" several controls to a single sub (sender works just fine). My question is with the speed (or lack of) to responding to a click.

A single click event works just fine. I have a simple piece of code that can detect a double click on a Button (dbltime is global):
Sub Button1_Click
dt =
Now - DblTime
If dt < 10000000ThenMsgbox("Double Click")
EndIf
dbltime = Now
End Sub

This code works great on a Button control, but works quite poorly on a LinkLabel control. When you double click rapidly, the second click is apparently not detected. And, of course, if you click too slowly the second click is ignored. If you are persistent and keep trying different clicking speeds, eventually you can get the double click routine to run.

I have attached a demo program so you can see the behavior differences between a Button and a LinkLabel.

Any insights on how to implement an effective double click using a LinkLabel control?
 

agraham

Expert
Licensed User
Longtime User
This will only work under .NET 2.0 or later on a device as DoubleClick is not supported on Compact Framework 1.0. This should work for any Control that you can get a reference to.

B4X:
' LblDblClk is a Door library Event
LblDblClk.New1(Label.Control,"DoubleClick") 

...

Sub LblDblClk_NewEvent
  Msgbox("Double Click")
End Sub
 

dlfallen

Active Member
Licensed User
Longtime User
Ariel Z:
Yes, double-clicking the Button I can get DT < 2,000,000. Double-clicking the LinkLabel my fastest dt was 5,772,032. So, apperently I have to hit a dt somewere between 5,772,032 (or there abouts) to 9,999,999 for the double click code to work with the linklabel. This isn't satisfactory.

agraham:
I tried your code example with partial success:

I can get your code to work with a linklabel, but not with a "normal" label.

I cannot get your code to work with a linklabel for a single click.

I need to have a single double click subroutine that 40 different linklabels can be wired to. I can wire linklabel's built-in click event to one sub, but I can't seem to wire the linklabels to one sub (unless I put in "
LblDblClk.New1(Label1.control,
"DoubleClick") " 40 times with different Label references.

Even if I could wire all the linklabels to one doubleclick event, I need to be able to identify which label was doubleclicked. Sender returns "lbldblclk" and LblDblClk.tostring returns "Door.Event".

Obviously, I'm kind of lost here. In summary, I can use linklabel's built-in click event and capture the sender in the sub. I can use the door library to get access to the double click event, "hand wire" (40 lines of code) each linklabel to a double click sub, but cannot determine which label caused the sub to execute.
 

agraham

Expert
Licensed User
Longtime User
Here's how to do single and double click on LinkLabel and an ordinary label. Note that you always get a single click event before a double click event, that's unavoidable - it's how Windows does things.

In general you do need a separate event Sub for each LinkLabel because they are external library objects. Assuming that all the LinkLabels are pre-defined I would put all their event Subs in a module to hide them and make each a single line call to a main event with Sender as a parameter.
 

dlfallen

Active Member
Licensed User
Longtime User
Thanks. For a regular label, I was mimicking the LinkLabel syntax, using
LblClk.New1(obj1.Control,"Click") instead of
LblClk.New1(obj1.Value,"Click").

You say that "In general you do need a separate event Sub for each LinkLabel because they are external library objects." I guess you are referring to the new event (doubleclick). Several linklabels can be wired to a single click event.

Also implicit in your quote is that I could use just one sub for ordinary labels - correct? If so, that still doesn't solve the problem of identifying the sending label.

Finally, as I was waking up this morning it dawned on me that a double click begins with a single click (as you pointed out). Using linklabel's click event I can set a global variable (CurLabel) equal to the sender, and then retrieve that information in the new double click event.

I think I have enough to finish the project now. THANKS FOR YOUR HELP!
 

agraham

Expert
Licensed User
Longtime User
You say that "In general you do need a separate event Sub for each LinkLabel because they are external library objects." I guess you are referring to the new event (doubleclick).
Sorry, sloppy phraseology. I meant that an external objects with an event added by the Door library they can't be identified in that event except by the name of the new event.

Also implicit in your quote is that I could use just one sub for ordinary labels - correct? If so, that still doesn't solve the problem of identifying the sending label.
No. I'm afraid this is getting a bit complicated for a simple brief explanation but you got the right idea below. If a control already supports an event then you can always identify the control as it raises the event itself and correctly sets Sender even if you wire several to a common event using AddEvent instead of the normal automatic event Sub assignment. If you add a "missing" event with the Door library you can't identify the control by Sender (except by association with the new event object) as it is the new event object that raises the event and sets Sender.

Using linklabel's click event I can set a global variable (CurLabel) equal to the sender, and then retrieve that information in the new double click event.
Nice idea! I overlooked that possibility.
 

dlfallen

Active Member
Licensed User
Longtime User
I've about finished my app do-over, and have the single and double click routines working well. It compiles without error, but when I try to run the EXE I get the following error:

(On the device):
An error occurred on sub __main_llclick
InvalidCastException
-------------------------------------------------------
(On the desktop):
An error occurred on sub _main_llclick
Unable to cast object of type 'LinkLabel.LinkLabel' to type 'Dbasic.|Text'.

I haven't been able to figure out what that means or how to correct the code to eliminate that error. Here is the sub generating that error message"
-------------------------------------------
Sub LLclick
'Global variables: CurLabel, ThisMonth, OldLbl, CellText
CurLabel = Sender
'ignore impossible cells:
clbl = Sender
If Sender = OldLbl Then Return 'ignore if 2d click on same cell
clbl = SubString (clbl,5, StrLength (clbl) - 5)
clbl = clbl - MOS
If clbl < 1 OR clbl > intMonthDays(ThisMonth-1) Then Return
Control(Sender,"LinkLabel").backcolor = Rgb(224,255,255)
Control(OldLbl,"LinkLabel").backcolor = cWhite
OldLbl = Sender
CellText = Sender.text
tx = ""
x=StrIndexOf(Sender.text,CRLF,0)
If x > 0 Then
CellDate = SubString(Sender.text,0,x)
tx = SubString(Sender.text,x+2,StrLength(Sender.text)-x-2)
End If
ExpTxt.Text = tx
End Sub
-------------------------------------------

Any suggestions?
 

agraham

Expert
Licensed User
Longtime User
Does it run OK in the IDE? I suspect this line but the error is not what I would expect.

Control(OldLbl,"LinkLabel").backcolor = cWhite

Sender is a keyword, not just a variable so it is treated specially.
Control(Sender ... works
as does
Sender.someproperty
but
Control(clbl .. I would not expect to work because you used
clbl = Sender
and not
clbl = SenderFullname and Control needs a module qualified name

You can use my http://www.b4x.com/forum/additional...-legacy-optimised-applications.html#post27120 to find out the line number where an error occur in optimised compiled apps. It can also single step them and inspect and change controls and global variables.

EDIT:- Forget the above explanation, I was trying to run your code but must have made an editing mistake as I have just tried building it up from scratch and not got the same error. Still puzzled!

EDIT:- It's this line
CellText = Sender.text
use
CellText = Control(Sender,"LinkLabel").text
instead
 
Last edited:

dlfallen

Active Member
Licensed User
Longtime User
Yes, it runs just fine on the IDE and compiles without error.

I tried your suggestion:
CellText = Control(Sender,"LinkLabel").text
but received the same error. I'll take a look at your debugging suite - I hope I can cope with it. Thanks for your help.

In case you are really curious, attached is the whole source code and both EXE files: ViewCal_Win.exe is the desktop compile, the other is the optimized device compile.
 

dlfallen

Active Member
Licensed User
Longtime User
OK, I got it!

You were correct,
CellText = Sender.text
was causing an error, corrected by changing it to
CellText = Control(Sender,"LinkLabel").text

:sign0161:What I was slow to grasp, was that it was not JUST that line, but ALL lines containing "Sender.text" (I think there were 4 such lines in that Sub).

Substituting "Control(Sender,"LinkLabel").text" for "Sender.text" in all cases resolved the problem.

Many, many thanks!
 

dlfallen

Active Member
Licensed User
Longtime User
agraham:

I appreciate your help with all of this. In the end, I did have to write seperate event subs (double click) for each linklabel, but it wasn't that simple.

The labels were created within a loop.

(1) If I included
LLDblClick.New1(Control("Label" & i,"LinkLabel").Control,"DoubleClick")
within the loop, all labels get wired to the same sub (LLDblClick_NewEvent). It works just fine in the IDE, but when compiled only the last control activates the double click event.

(2) My first solution was to have separate subs and include
AddObject("LLDblClick" & i,"Event")
within the loop, and outside the loop have a series of lines:
LLDblClick1.New1(Control("Label1","LinkLabel").Control,"DoubleClick")
LLDblClick2.New1(Control("Label2","LinkLabel").Control,"DoubleClick")
etc. This works fine in the IDE, but when attempting to compile, I get an error "Unknown control type. Use Control("_main_lldblclick1,Type) instead."

(3) Leaving these lines alone, I deleted the AddObject within the loop and created the series of objects using the Tools menu. Doing this, the code works both in the IDE and when compiled.

Attached are examples of the three versions.

Also you will note the empty LLclick subroutine. If the single click event is not created, when compiled I get an "Unhandled exception" error when a label is clicked.

So, in the end my code is ugly and with 42 linklables quite tedious, but at least I can move on to something else. Thanks for the experience.
 

agraham

Expert
Licensed User
Longtime User
but when compiled only the last control activates the double click event.
That is the behaviour I would expect because you are reusing the same event object each time. On NEW it should be disposed and recreated. That looks a bit like a bug in IDE, I'll point Erel at it.
LLDblClick1.New1(Control("Label1","LinkLabel").Control,"DoubleClick")
etc. This works fine in the IDE, but when attempting to compile, I get an error "Unknown control type. Use Control("_main_lldblclick1,Type) instead."
I think it is telling you to use this
Control("Main.LLDblClick1", "Event").New1(Control("Label1", "LinkLabel").Control,"DoubleClick")
You could probably put this in the loop using Main.LLDblClick & i. I haven't checked this code fragment so there may be errors but you get the idea.
If the single click event is not created, when compiled I get an "Unhandled exception" error when a label is clicked.
That's a bug in LinkLabel (which I didn't write :))
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Objects in the IDE are not being disposed implicitly due to the way the IDE holds references to objects.
Explicitly disposing the object will prevent this discrepancy.
B4X:
Sub App_Start

For i = 1 To 3
    AddObject("Label" & i,"LinkLabel")
    Control("Label" & i,"LinkLabel").New1("Form1",35,45*i,33,33)    
    Control("Label" & i,"LinkLabel").BackColor = cWhite
    Control("Label" & i,"LinkLabel").fontsize = 6
    Control("Label" & i,"LinkLabel").text = "Lbl " & i
    Control("Label" & i,"LinkLabel").underline = False
    AddEvent ("Label" & i,Click,"LLclick")
    If i > 1 Then LLDblClick.Dispose
    AddObject("LLDblClick","Event")
    LLDblClick.New1(Control("Label" & i,"LinkLabel").Control,"DoubleClick")
Next i
        
    Form1.Show
End Sub

You need to add an Event object for each event:
B4X:
Sub App_Start

For i = 1 To 3
    AddObject("Label" & i,"LinkLabel")
    Control("Label" & i,"LinkLabel").New1("Form1",35,45*i,33,33)    
    Control("Label" & i,"LinkLabel").BackColor = cWhite
    Control("Label" & i,"LinkLabel").fontsize = 6
    Control("Label" & i,"LinkLabel").text = "Lbl " & i
    Control("Label" & i,"LinkLabel").underline = False
    AddEvent ("Label" & i,Click,"LLclick")
    AddObject("LLDblClick" & i,"Event")
    Control("LLDblClick" & i, Event).New1(Control("Label" & i,"LinkLabel").Control,"DoubleClick")
    AddEvent("LLDblClick" & i, NewEvent, "LLDblClick_NewEvent")
Next i
        
    Form1.Show
End Sub

We plan to add a simpler syntax for runtime controls/objects which will make it simpler as it will allow the IDE to show the list of properties and methods for these objects as well.

I will describe the new syntax with following example:
Control("tree" & i, TreeView).Node will be equal to:
TreeView("tree" & i).Node
 
Top