Solved

Drag of label with an OnClick event

Posted on 1999-01-13
13
768 Views
Last Modified: 2010-04-06
I have a label that I want to be able to drag from and drop onto another control.
I have the DragMode set to dmManual
In the OnMouseDown event, I do BeginDrag(false).
In StartDrag I do a little processing, and EndDrag do a little more to setup global vars needed for the Drop on the other control.
All of this works fine.  The problem is that I also need to do some different processing if the user actually Clicks on the label.
If I define an OnClick event with the above scenario, the OnClick event fires immediately when I hit the MouseDown instead of its normal behaviour of waiting for the mouse to come up.

How can I get around this problem?
0
Comment
Question by:kdw
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 6
13 Comments
 
LVL 20

Expert Comment

by:Madshi
ID: 1356439
Could we please see your OnMouseDown, StartDrag and EndDrag code?
Thank you...

Regards, Madshi.
0
 

Author Comment

by:kdw
ID: 1356440
on Start Drag is setting a global var used eventually on the drop
procedure TMainConsole.TitleLabelStartDrag(Sender: TObject;
  var DragObject: TDragObject);
begin
  if LastURL <> nil then
    begin;
    MainConsole.DragURL := LastURL;
    end;
end;

onEndDrag just clears that setting
procedure TMainConsole.TitleLabelEndDrag(Sender, Target: TObject; X,
  Y: Integer);
begin
  MainConsole.DragURL := nil;
end;

OnMouseDown checks to make sure it is left mouse button and that there is a valid reason to allow the drag (good data)
procedure TMainConsole.TitleLabelMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  tmpLabel : TLabel;
begin
  tmpLabel := (TObject(Sender) as TLabel);
  if (Button = mbLeft) AND (LastURL.Address <> '') then
    tmpLabel.BeginDrag(false) ;
end;

OnMouseClick is just a message at the moment, but will be something usefull once it works

procedure TMainConsole.DragLabelClick(Sender: TObject);
begin
  ShowMessage('For an easy way to set a preset to the currently playing station,' + Chr(13) +
              'just press your mouse here, and drag to the desired preset button.');
end;

Again, the problem is, with this code, the OnMouseClick event fires as soon as mousedown goes (I'm assuming caused by the BeginDrag(false), since when that line is removed, click is normal, but no drag happens).

0
 
LVL 20

Expert Comment

by:Madshi
ID: 1356441
Hmmm. You're right. I checked Delphi's "controls.pas" and found that in BeginDrag this is called:
      Perform(WM_LBUTTONUP, 0, Longint(PointToSmallPoint(P)));
Now how to get around this problem...

I think you'll have to write your own TLabel component. Something like this should do it:

type TDragLabel = class(TLabel)
     private
       FIgnoreNextMouseUp : boolean;
     protected
       procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
     public
       procedure BeginDrag(Immediate: boolean);
     end;

procedure TDragLabel.MouseUp;
begin
  if FIgnoreNextMouseUp then FIgnoreNextMouseUp:=false
  else inherited MouseUp(Button, Shift, X, Y);
end;

procedure TDragLabel.BeginDrag(immediate: boolean);
begin
  FIgnoreNextMouseUp:=true;
  inherited BeginDrag(Immediate);
end;

Regards, Madshi.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:kdw
ID: 1356442
Close, but not quite there.  I think the problem now is in
procedure TControl.WMLButtonUp(var Message: TWMLButtonUp);
begin
  inherited;
  if csCaptureMouse in ControlStyle then MouseCapture := False;
  if csClicked in ControlState then
  begin
    Exclude(FControlState, csClicked);
    if PtInRect(ClientRect, SmallPointToPoint(Message.Pos)) then Click;
  end;
  DoMouseUp(Message, mbLeft);
end;

When the MouseUp from BeginDrag is processed by above, the Click event gets called, so I need to find a way around that.  The overide of MouseUp is too late in the process.

0
 
LVL 20

Expert Comment

by:Madshi
ID: 1356443
Hmmm. It works with my SpeedButton component, but probably because it's descendend from another type.

Have you tried to directly overwrite the WMLButtonUp procedure?

type TDragLabel = class(TLabel)
     private
       FIgnoreNextMouseUp : boolean;
       procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
     public
       procedure BeginDrag(Immediate: boolean);
     end;

procedure TDragLabel.WMLButtonUp(var Message: TWMLButtonUp);
begin
  if FIgnoreNextMouseUp then FIgnoreNextMouseUp:=false
  else inherited WMLButtonUp(Message);
end;

procedure TDragLabel.BeginDrag(immediate: boolean);
begin
  FIgnoreNextMouseUp:=true;
  inherited BeginDrag(Immediate);
end;

Regards, Madshi.
0
 

Author Comment

by:kdw
ID: 1356444
It sounds right, but just won't compile.  This is a TLabel I'm inherited from.  With code as you typed, down in the WMLButtonUp def, the compiler dies on the
 else inherited WMLButtonUp(Message);
line with
Undeclared Identifier: WMLButtonUp

If in the declaration at top I add "override" to the procedure line, it says procedure not found in base class.

I appreciate the help.
0
 
LVL 20

Accepted Solution

by:
Madshi earned 200 total points
ID: 1356445
Ok, here comes finally the working solution - I tested it...    :-)

type TDragLabel = class(TLabel)
     private
       FIgnoreNextMouseUp : boolean;
     protected
       procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
     public
       procedure DoEndDrag(Target: TObject; X, Y: integer); override;
       procedure BeginDrag(Immediate: boolean);
     end;

procedure TDragLabel.WMLButtonUp(var Message: TWMLButtonUp);
begin
  if FIgnoreNextMouseUp then FIgnoreNextMouseUp:=false
  else inherited;
end;

procedure TDragLabel.DoEndDrag(Target: TObject; X, Y: integer);
var P : TPoint;
begin
  inherited DoEndDrag(Target,X,Y);
  if not csDestroying in ComponentState then begin
    GetCursorPos(P); P:=ScreenToClient(P); Perform(WM_LBUTTONUP,0,integer(PointToSmallPoint(P)));
  end;
end;

procedure TDragLabel.BeginDrag(immediate: boolean);
begin
  FIgnoreNextMouseUp:=true;
  inherited BeginDrag(Immediate);
end;

Regards, Madshi.
0
 

Author Comment

by:kdw
ID: 1356446
I increased points since I'm being such a pain.
I feel like an idiot at the moment, but the line

if not csDestroying in ComponentState then begin
generates
operator not applicable to this operand type.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1356447
Hmmm. You're surely not an idiot! This is really quite hard stuff...
Thanx for increasing the points (was not nessecary)...  :-)

I'm not sure about this line. It compiles fine with my Delphi4. Perhaps it will work on your Delphi this way:

if not (csDestroying in ComponentState) then begin

Regards, Madshi.
0
 

Author Comment

by:kdw
ID: 1356448
if I comment out that one line, it seems to work well.  What problem does the csDestroying line prevent?
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1356449
If you destroy this component while the user is dragging, there could be some problems. So this line asks if you're destroying the component in the moment and then does not perform the WM_MOUSEUP message.
However, it's not no important. I've copied this part of my sources from my own speedButton component, where I had such problems. I think you can leave it away. However, I would really like to know why you can't compile it...
Have you tried it with the "()" (as suggested in my last comment)? Doesn't this work, either?

Regards, Madshi.
0
 

Author Comment

by:kdw
ID: 1356450
I'm not sure, but I can't imagine a scenario of destroying while dragging, so I'm going to go with this.  I really appreciate the help.  I learned a lot about inheritance in the process.

Thanks.

If you are interested, the program is at
http://www.digiband.com/dbindex.html

The version with your changes will be out this evening.

0
 
LVL 20

Expert Comment

by:Madshi
ID: 1356451
I'm just glad that I could help you...   :-)
0

Featured Post

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Michael from AdRem Software explains how to view the most utilized and worst performing nodes in your network, by accessing the Top Charts view in NetCrunch network monitor (https://www.adremsoft.com/). Top Charts is a view in which you can set seve…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
Suggested Courses
Course of the Month7 days, left to enroll

623 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question