Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Add dragable tabs to the Delphi TPageView component

Posted on 2009-02-24
10
Medium Priority
?
765 Views
Last Modified: 2012-05-06
Hello Delphi Experts,

Delphi 6's Editor Window has tabs which can be dragged so you can have a different order.
e.g. if you have Unit1 Unit2 Unit3 you can change it to Unit3 Unit1 Unit2
(useful if you have a project with many files and you want some of them to be always visible)

However the TPageView component in D5 and D6 does not  have the same feature. Can some Delphi Expert create a new class based on the existing TPageView that does allow dragable tabs (with a property to enable it)? Can be for either D6 or D5. if I haven't explained clearly enough please ask.

Thank you.
0
Comment
Question by:WinRat
  • 7
  • 3
10 Comments
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 23720806
i didn't create a component,

just set TPageControl, dragmode to dmManual and add these events
procedure TForm1.PageControl1DragOver(Sender, Source: TObject; X,
  Y: Integer; State: TDragState; var Accept: Boolean);
var currTab, TargetTab: integer;
  pc: TPageControl;
begin
  Accept := Assigned(Sender) and Assigned(Source) and (Sender = Source) and (Sender is TPageControl);
  if Accept then
  begin
    pc := Sender as TPageControl;
    TargetTab := pc.IndexOfTabAt(X, Y);
    CurrTab := pc.Tag;
    if not ((TargetTab <> -1) and (TargetTab <> CurrTab)) then
      Accept := False;
  end;
end;
 
procedure TForm1.PageControl1DragDrop(Sender, Source: TObject; X,
  Y: Integer);
var
  currTab, TargetTab: integer;
  pc: TPageControl;
begin
  if Assigned(Sender) and Assigned(Source) and (Sender = Source) and (Sender is TPageControl) then
  begin
    pc := Sender as TPageControl;
    TargetTab := pc.IndexOfTabAt(X, Y);
    CurrTab := pc.Tag;
    if (CurrTab <> -1) and (TargetTab <> -1) and (TargetTab <> CurrTab) then
    begin
      pc.Pages[CurrTab].PageIndex := TargetTab;
    end;
  end;
end;
 
procedure TForm1.PageControl1StartDrag(Sender: TObject;
  var DragObject: TDragObject);
var pc: TPageControl;
  p: TPoint;
begin
  if Assigned(Sender) and (Sender is TPageControl) then
  begin
    pc := Sender as TPageControl;
    p := pc.ScreenToClient(Mouse.CursorPos);
    pc.Tag := pc.IndexOfTabAt(p.X, p.Y);
  end;
end;

Open in new window

0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 23720815
it does use the Tag of the PageControl
you may need to set it to a variable if you use the Tag yourself !
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 23720928
dunno if this works in D5, i did this in D7
0
Independent Software Vendors: 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!

 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 23721127
oops the click doesn't work anymore (changing tabs)
the DragMode had to be set to dmAutomatic, not dmManual

funny stuff this, i did a workaround for setting the tab order, or changing the tabs with a checkbox
but that's silly, i'll have a deeper look
0
 

Author Comment

by:WinRat
ID: 23721491
Geert_Gruwez:

I tried your solution in D5 and as you said you have to set DragMode to Auto and the tabs drag as wanted - but then you can't select different tabs. Stays on the first default one selected. good luck - half-way there!

0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 23721545
that's allways the problem ... it's allways the second half !
0
 
LVL 38

Accepted Solution

by:
Geert Gruwez earned 1200 total points
ID: 23722445
behold !!!

read em and weep !!!

it even works in Delphi 2007 !

PS: yes, it's a dirty way !
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, ComCtrls;
 
type
  TPageControl = class(ComCtrls.TPageControl)
  private
    fDraggingTab: Integer;
  protected
    procedure WndProc(var Message: TMessage); override;
  public
    constructor Create(AOwner: TComponent); override;
    property DraggingTab: integer read fDraggingTab;
  end;
 
  TForm1 = class(TForm)
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    TabSheet2: TTabSheet;
    TabSheet3: TTabSheet;
    procedure PageControl1DragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    procedure PageControl1DragDrop(Sender, Source: TObject; X, Y: Integer);
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
{ TPageControl }
 
constructor TPageControl.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  fDraggingTab := -1;
end;
 
procedure TPageControl.WndProc(var Message: TMessage);
var P: TPoint;
begin
  inherited WndProc(Message);
  case Message.Msg of
    WM_LBUTTONDOWN:
    begin
      P := Point(TWMMouse(Message).XPos, TWMMouse(Message).YPos);
      if htOnItem in GetHitTestInfoAt(P.X, P.Y) then
        fDraggingTab := IndexOfTabAt(P.X, P.Y)
      else
        fDraggingTab := -1;
    end;
    WM_MOUSEMOVE:
      if (csLButtonDown in ControlState) and (fDraggingTab <> -1) then
        BeginAutoDrag;
  end;
end;
 
{ TForm1 }
 
procedure TForm1.PageControl1DragDrop(Sender, Source: TObject; X,
  Y: Integer);
var
  TargetTab: integer;
  pc: TPageControl;
begin
  if Assigned(Sender) and Assigned(Source) and (Sender = Source) and (Sender is TPageControl) then
  begin
    pc := Sender as TPageControl;
    TargetTab := pc.IndexOfTabAt(X, Y);
    if (pc.DraggingTab <> -1) and (TargetTab <> -1) and (TargetTab <> pc.DraggingTab) then
      pc.Pages[pc.DraggingTab].PageIndex := TargetTab;
  end;
end;
 
procedure TForm1.PageControl1DragOver(Sender, Source: TObject; X,
  Y: Integer; State: TDragState; var Accept: Boolean);
var
  TargetTab: integer;
  pc: TPageControl;
begin
  Accept := Assigned(Sender) and Assigned(Source) and (Sender = Source) and (Sender is TPageControl);
  if Accept then
  begin
    pc := Sender as TPageControl;
    TargetTab := pc.IndexOfTabAt(X, Y);
    if not ((TargetTab <> -1) and (TargetTab <> pc.DraggingTab)) then
      Accept := False;
  end;
end;
 
end.

Open in new window

0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 23722452
forgot to say, set PageControl DragMode = dmManual
0
 

Author Comment

by:WinRat
ID: 23722873
Geert_Gruwez:
I got it to work already. Drag mode defaults to Manual.
Going to award you the points since you answered my question perfectly! Good work and fast!

Having used it I see some aspect that could be improved. If you have many pages and several of the tabs are not visible i.e.you need to use the scroll buttons to get to them, would it be feasible to have the following behaviour:

You want to drag hidden tab 6 to be the first one.
You scroll right to get one of the hidden tabs, then drag it to the left when you get to the end of the pagecontrol tab 1 you keep dragging and the tabs scroll right automatically until you get to Tab 1.
Same thing in the other direction, i.e. dragging tab1 to be the last one.
Not sure if i explained this well but if you try it you will see what I mean.

If you think it is possible I will submit as a new question as an enhancement to this solution.

Thanks so much!
Have to go home now so won't be on-line until later this evening.
0
 

Author Closing Comment

by:WinRat
ID: 31550527
I didn't know you could redefine a component within a unit like that, even after you have dropped it on the form. Clever. Please see extra comments.
Thanks again. Sure will be of general interest.
PS: Did you see my related question about Delphi 5's Editor Window tabs? Didn't get a way of adding to D5. D6 has it already.
http://www.experts-exchange.com/Programming/Editors_IDEs/Delphi/Q_24161533.html
0

Featured Post

Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

Question has a verified solution.

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

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
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…
Look below the covers at a subform control , and the form that is inside it. Explore properties and see how easy it is to aggregate, get statistics, and synchronize results for your data. A Microsoft Access subform is used to show relevant calcul…
How can you see what you are working on when you want to see it while you to save a copy? Add a "Save As" icon to the Quick Access Toolbar, or QAT. That way, when you save a copy of a query, form, report, or other object you are modifying, you…
Suggested Courses
Course of the Month12 days, 5 hours left to enroll

564 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