2010-04-08 13 views
9

मेरे पास TPageControl है जिनके पृष्ठ ManualDock() का उपयोग कर जुड़े सभी विभिन्न रूप हैं। उपयोगकर्ता को खींचकर टैब को पुनर्व्यवस्थित करने में सक्षम होना चाहिए, जो पहले से ही काम करता है। हालांकि, डॉक किए गए फॉर्मों को अनदेखा करना भी संभव होना चाहिए।डेल्फी ड्रैगिंग को डॉकिंग करने के लिए "प्रचारित" किया जा सकता है?

अभी के लिए मैं निम्नलिखित कोड है,

procedure TMainForm.PageControlMouseDown(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
begin 
    if (Button = mbLeft) and (Shift * [ssShift, ssCtrl] = []) 
    and PageControl.DockSite 
    then begin 
    PageControl.BeginDrag(False, 32); 
    end; 
end; 

या तो शिफ्ट या Ctrl कुंजी दबाए आयोजित कर रहे हैं, तो एक डॉकिंग आपरेशन शुरू कर दिया हो जाएगा अन्यथा टैब से पुनर्व्यवस्थित किया जा सकता उन्हें खींच रहा है।

हालांकि संशोधक के रूप में कुंजी का उपयोग करना अजीब है। जब माउस कर्सर पृष्ठ नियंत्रण के टैब क्षेत्र से बाहर होता है, तो सक्रिय ड्रैग ऑपरेशन को रद्द करने का कोई तरीका है, और बच्चे के रूप को डॉक करना प्रारंभ करें? यह डेल्फी 200 9 के साथ है।

+0

मुझे नहीं पता, लेकिन मुझे संदेह है कि यदि आपने पृष्ठ नियंत्रण से बाहर निकलने के दौरान begindrag करने का प्रयास किया है, तो आप एक डिस्प्ले ड्रैग/माउस रिलेशनशिप के साथ समाप्त हो जाएंगे। यानी माउस उस चीज से एक इंच दूर है जिसे आप खींच रहे हैं। यह एक उत्तर नहीं है, अगर आपको कोई जवाब नहीं मिलता है और छोड़ने की तरह महसूस होता है तो केवल एक सांत्वना। –

उत्तर

7

मेरे पास अब एक समाधान है जो मेरे लिए काम करता है, इसलिए मैं खुद का जवाब दूंगा - शायद किसी के पास इसका भी उपयोग है।

चलिए एक छोटा सा नमूना अनुप्रयोग शुरू करते हैं जो 8 डॉक किए गए फॉर्मों के साथ TPageControl बनाता है, कोड के रनटाइम रीडरिंग के लिए अनुमति देने के लिए कोड के साथ। टैब्स को लाइव ले जाया जाएगा, और जब खींचने रद्द कर दिया गया सक्रिय टैब सूचकांक अपने मूल मूल्य पर लौट जाएगा:

unit uDragDockTest; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    ComCtrls; 

type 
    TForm1 = class(TForm) 
    procedure FormCreate(Sender: TObject); 
    private 
    fPageControl: TPageControl; 
    fPageControlOriginalPageIndex: integer; 
    function GetPageControlTabIndex(APosition: TPoint): integer; 
    public 
    procedure PageControlDragDrop(Sender, Source: TObject; X, Y: Integer); 
    procedure PageControlDragOver(Sender, Source: TObject; X, Y: Integer; 
     AState: TDragState; var AAccept: Boolean); 
    procedure PageControlEndDrag(Sender, Target: TObject; X, Y: Integer); 
    procedure PageControlMouseDown(Sender: TObject; AButton: TMouseButton; 
     AShift: TShiftState; X, Y: Integer); 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.FormCreate(Sender: TObject); 
const 
    FormColors: array[1..8] of TColor = (
    clRed, clGreen, clBlue, clYellow, clLime, clMaroon, clTeal, clAqua); 
var 
    i: integer; 
    F: TForm; 
begin 
    fPageControlOriginalPageIndex := -1; 

    fPageControl := TPageControl.Create(Self); 
    fPageControl.Align := alClient; 
    // set to False to enable tab reordering but disable form docking 
    fPageControl.DockSite := True; 
    fPageControl.Parent := Self; 

    fPageControl.OnDragDrop := PageControlDragDrop; 
    fPageControl.OnDragOver := PageControlDragOver; 
    fPageControl.OnEndDrag := PageControlEndDrag; 
    fPageControl.OnMouseDown := PageControlMouseDown; 

    for i := Low(FormColors) to High(FormColors) do begin 
    F := TForm.Create(Self); 
    F.Caption := Format('Form %d', [i]); 
    F.Color := FormColors[i]; 
    F.DragKind := dkDock; 
    F.BorderStyle := bsSizeToolWin; 
    F.FormStyle := fsStayOnTop; 
    F.ManualDock(fPageControl); 
    F.Show; 
    end; 
end; 

const 
    TCM_GETITEMRECT = $130A; 

function TForm1.GetPageControlTabIndex(APosition: TPoint): integer; 
var 
    i: Integer; 
    TabRect: TRect; 
begin 
    for i := 0 to fPageControl.PageCount - 1 do begin 
    fPageControl.Perform(TCM_GETITEMRECT, i, LPARAM(@TabRect)); 
    if PtInRect(TabRect, APosition) then 
     Exit(i); 
    end; 
    Result := -1; 
end; 

procedure TForm1.PageControlDragDrop(Sender, Source: TObject; X, Y: Integer); 
var 
    Index: integer; 
begin 
    if Sender = fPageControl then begin 
    Index := GetPageControlTabIndex(Point(X, Y)); 
    if (Index <> -1) and (Index <> fPageControl.ActivePage.PageIndex) then 
     fPageControl.ActivePage.PageIndex := Index; 
    end; 
end; 

procedure TForm1.PageControlDragOver(Sender, Source: TObject; X, Y: Integer; 
    AState: TDragState; var AAccept: Boolean); 
var 
    Index: integer; 
begin 
    AAccept := Sender = fPageControl; 
    if AAccept then begin 
    Index := GetPageControlTabIndex(Point(X, Y)); 
    if (Index <> -1) and (Index <> fPageControl.ActivePage.PageIndex) then 
     fPageControl.ActivePage.PageIndex := Index; 
    end; 
end; 

procedure TForm1.PageControlEndDrag(Sender, Target: TObject; X, Y: Integer); 
begin 
    // restore original index of active page if dragging was canceled 
    if (Target <> fPageControl) and (fPageControlOriginalPageIndex > -1) 
    and (fPageControlOriginalPageIndex < fPageControl.PageCount) 
    then 
    fPageControl.ActivePage.PageIndex := fPageControlOriginalPageIndex; 
    fPageControlOriginalPageIndex := -1; 
end; 

procedure TForm1.PageControlMouseDown(Sender: TObject; AButton: TMouseButton; 
    AShift: TShiftState; X, Y: Integer); 
begin 
    if (AButton = mbLeft) 
    // undock single docked form or reorder multiple tabs 
    and (fPageControl.DockSite or (fPageControl.PageCount > 1)) 
    then begin 
    // save current active page index for restoring when dragging is canceled 
    fPageControlOriginalPageIndex := fPageControl.ActivePageIndex; 
    fPageControl.BeginDrag(False); 
    end; 
end; 

end. 

संपादक में चिपकाएं और इसे चलाने, सभी आवश्यक घटक और उनके गुणों बनाया है और स्थापित किया जाएगा रनटाइम पर।

ध्यान दें कि फ़ॉर्म को अनदेखा करना केवल टैब पर डबल-क्लिक करके संभव है। यह कुछ हद तक बदसूरत है कि टैब से दूरी के बावजूद, बाएं माउस बटन जारी होने तक ड्रैग कर्सर दिखाया जाएगा। ड्रैगिंग स्वचालित रूप से रद्द हो जाने पर यह बेहतर होगा और इसके बजाय फॉर्म को अनदेखा किया जाएगा, जब माउस पृष्ठ नियंत्रण टैब क्षेत्र के बाहर कुछ पिक्सल मार्जिन के साथ होता है।

यह पृष्ठ नियंत्रण से OnStartDrag हैंडलर में एक कस्टम DragObject बनाने के द्वारा प्राप्त किया जा सकता। इस ऑब्जेक्ट में माउस कैप्चर किया जाता है, इसलिए ड्रैग करते समय सभी माउस संदेश इसे नियंत्रित किए जा सकते हैं। जब माउस कर्सर टैब प्रभाव के बाहर आयत है खींचने रोक दी गई है, और सक्रिय पेज नियंत्रण शीट में फार्म के लिए एक डॉकिंग आपरेशन के बजाय शुरू कर दिया गया है:

type 
    TConvertDragToDockHelper = class(TDragControlObjectEx) 
    strict private 
    fPageControl: TPageControl; 
    fPageControlTabArea: TRect; 
    protected 
    procedure WndProc(var AMsg: TMessage); override; 
    public 
    constructor Create(AControl: TControl); override; 
    end; 

constructor TConvertDragToDockHelper.Create(AControl: TControl); 
const 
    MarginX = 32; 
    MarginY = 12; 
var 
    Item0Rect, ItemLastRect: TRect; 
begin 
    inherited; 
    fPageControl := AControl as TPageControl; 
    if fPageControl.PageCount > 0 then begin 
    // get rects of first and last tab 
    fPageControl.Perform(TCM_GETITEMRECT, 0, LPARAM(@Item0Rect)); 
    fPageControl.Perform(TCM_GETITEMRECT, fPageControl.PageCount - 1, 
     LPARAM(@ItemLastRect)); 
    // calculate rect valid for dragging (includes some margin around tabs) 
    // when this area is left dragging will be canceled and docking will start 
    fPageControlTabArea := Rect(
     Min(Item0Rect.Left, ItemLastRect.Left) - MarginX, 
     Min(Item0Rect.Top, ItemLastRect.Top) - MarginY, 
     Max(Item0Rect.Right, ItemLastRect.Right) + MarginX, 
     Max(Item0Rect.Bottom, ItemLastRect.Bottom) + MarginY); 
    end; 
end; 

procedure TConvertDragToDockHelper.WndProc(var AMsg: TMessage); 
var 
    MousePos: TPoint; 
    CanUndock: boolean; 
begin 
    inherited; 
    if AMsg.Msg = WM_MOUSEMOVE then begin 
    MousePos := fPageControl.ScreenToClient(Mouse.CursorPos); 
    // cancel dragging if outside of tab area with margins 
    // optionally start undocking the docked form (can be canceled with [ESC]) 
    if not PtInRect(fPageControlTabArea, MousePos) then begin 
     fPageControl.EndDrag(False); 
     CanUndock := fPageControl.DockSite and (fPageControl.ActivePage <> nil) 
     and (fPageControl.ActivePage.ControlCount > 0) 
     and (fPageControl.ActivePage.Controls[0] is TForm) 
     and (TForm(fPageControl.ActivePage.Controls[0]).DragKind = dkDock); 
     if CanUndock then 
     fPageControl.ActivePage.Controls[0].BeginDrag(False); 
    end; 
    end; 
end; 

वर्ग TDragControlObjectEx से बजाय इतना TDragControlObject से उतरता है कि यह स्वचालित रूप से मुक्त हो जाएगा। अब नमूना आवेदन में TPageControl के लिए कोई हैंडलर बनाया है (और पेज नियंत्रण वस्तु के लिए सेट):

procedure TForm1.PageControlStartDrag(Sender: TObject; 
    var ADragObject: TDragObject); 
begin 
    // do not cancel dragging unless page control has docking enabled 
    if (ADragObject = nil) and fPageControl.DockSite then 
    ADragObject := TConvertDragToDockHelper.Create(fPageControl); 
end; 

तो टैब को खींचते रद्द करते समय टैब से माउस चालें, दूर बहुत दूर है और अगर हो जाएगा सक्रिय पृष्ठ एक डॉक्यूबल फॉर्म है, इसके लिए एक डॉकिंग ऑपरेशन शुरू किया जाएगा, जिसे अभी भी ईएससी कुंजी के साथ रद्द किया जा सकता है।

+0

अद्भुत। धन्यवाद - मेरे पास पहले से इसका उपयोग है। – SourceMaid