Solved

Drag of label with an OnClick event

Posted on 1999-01-13
13
734 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
  • 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
 

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
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

744 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now