2010-08-20 46 views
14

Tôi đã tạo ra một dẫn xuất TForm hoạt động như phần thả xuống của một combo, hoặc một cửa sổ gợi ý, hoặc một menu popup - một điều tạm thời. Nó không có chú thích - BorderStyle của nó được đặt thành bsNone. Biểu mẫu được hiển thị không theo cách thức bằng cách sử dụng Hiển thị, đã đặt vị trí của nó.TForm không biên giới với bóng đổ

Để làm nổi bật, nó cần một bóng đổ xung quanh đường viền của nó. Tuy nhiên, hậu quả của việc thiết lập đường viền của nó thành bsNone là bóng đổ biến mất.

nguồn Google khác nhau cho thấy sự thay đổi về điều này:

procedure TdlgEditServiceTask.CreateParams(var Params: TCreateParams); 
const 
    CS_DROPSHADOW = $00020000; 
begin 
    inherited; 
    { Enable drop shadow effect on Windows XP and later } 
    if (Win32Platform = VER_PLATFORM_WIN32_NT) and 
    ((Win32MajorVersion > 5) or 
     ((Win32MajorVersion = 5) and (Win32MinorVersion >= 1))) then 
    Params.WindowClass.Style := Params.WindowClass.Style or 
      CS_DROPSHADOW; 
end; 

nhưng nó không hoạt động - cái bóng không được hiển thị (trừ khi tôi cũng thiết lập một biên giới thay đổi kích thước với bộ WS_THICKFRAME, trông khủng khiếp). Đây là một cửa sổ bật lên, không phải cửa sổ con, vì vậy tôi không thấy lý do tại sao nó không thành công.

Đề nghị vui lòng?

NB: đây là câu hỏi tương tự với câu hỏi this chưa được trả lời.

NB2: Có một thành phần VCL tối nghĩa được gọi là TShadowWindow trông giống như nó sẽ làm điều đúng, nhưng hóa ra là quá thô lỗ được viết là thực tế.

Cập nhật: Làm theo ý kiến ​​của Andreas bên dưới, tôi đã điều tra thêm về điều này và tìm thấy một số yếu tố thú vị.

Trong Windows 7, tôi phát hiện ra rằng bóng không xuất hiện khi cửa sổ bật lên nếu nó nằm trên một cửa sổ khác từ cùng một ứng dụng.

Đây là ứng dụng Delphi đơn giản, sử dụng CreateParams trên cửa sổ bật lên để yêu cầu bóng như mô tả ở trên.

Windows 7 with shadow only over desktop

Xem cách thả bóng xuất hiện nơi nó vượt ra ngoài cửa sổ chính?

Nhưng tôi muốn sử dụng cửa sổ không viền làm cửa sổ bật lên trên cửa sổ chính. Bóng đổ phân biệt popup từ cửa sổ bên dưới. Tất cả các mô tả của tôi ở trên đề cập đến hoàn cảnh này. Rõ ràng một số cơ chế Windows đang can thiệp ở đây.

Tôi cũng đã thử cùng một ứng dụng trong Windows XP. Đây là cách nó trông.

Same application under XP

này hoạt động một cách chính xác với bóng ở khắp mọi nơi *. Gah!

Vì vậy, nó có vẻ là một điều Vista/W7, như Andreas gợi ý.

(* Một phiên bản trước của văn bản này và screendump gợi ý rằng không có bóng xuất hiện. Tuy nhiên, điều này hóa ra là vì tôi đã có 'Shadows dưới menu' màn hình hiển thị tùy chọn Windows XP tắt. Duh.)

+0

tôi không hoàn toàn hiểu cách bạn muốn cửa sổ của bạn. Bạn * không * muốn nó giống như cửa sổ bật lên Code Insight (có đường viền có thể thay đổi kích thước dày) trong RAD Studio IDE, phải không? –

+0

@Andreas: Đúng. Tôi không muốn một biên giới có thể thay đổi kích thước - đây là những gì tôi có thể nhận được bằng cách thiết lập WS_THICKFRAME như đã đề cập trong câu hỏi. Tôi muốn đường viền của nó trông giống như một thực đơn, tức là một đường kẻ mỏng với bóng. Thực tế, bây giờ bạn đề cập đến nó, tôi nhận thấy Code Insight hiển thị ít nhất ba loại cửa sổ khác nhau, tùy thuộc vào ngữ cảnh. Tôi muốn giống như những người không có biên giới có thể thay đổi kích cỡ! :-) – willw

Trả lời

6

Tìm thấy nó ở đây là bằng chứng:.

alt text

Như bạn có thể thấy, thả bóng hiện nay cho thấy đúng so với hình thức

Sự cố là một trong Z-order. Nó chỉ ra rằng cái bóng chính nó là một cửa sổ riêng biệt được duy trì bởi chính Windows. Trong Windows 7, nó dường như hiển thị bóng bên dưới cửa sổ chính. Để làm cho nó hiển thị đúng, người ta cần di chuyển nó lên.

Một thiên tài được gọi là Łukasz Płomiński giải thích điều này trong một chủ đề trong nhóm tin tức Embarcadero. Đây là mã của mình để sắp xếp nó ra:

procedure TForm1.FixSysShadowOrder; 

    function FindSysShadowOrderProc(WindowHandle: HWND; // handle to window 
    Form: TForm1 // application-defined value, 32-bit 
    ): BOOL; stdcall; 
    var 
    Buffer: array [0 .. 255] of char; 
    Rect: TRect; 
    begin 
    Result := True; 
    if IsWindowVisible(WindowHandle) then 
    begin 
     // this code search for SysShadow window created for this window. 
     GetClassName(WindowHandle, Buffer, 255); 
     if 0 <> AnsiStrComp(Buffer, PChar('SysShadow')) then 
     Exit; 

     GetWindowRect(WindowHandle, Rect); 
     if (Rect.Left <> Form.Left) or (Rect.Top <> Form.Top) then 
     Exit; 

     Form.FSysShadowHandle := WindowHandle; 
     // stop enumeration 
     Result := False; 
    end; 
    end; 

begin 
    if not(csDesigning in ComponentState) and 
    ((GetClassLong(Handle, GCL_STYLE) and CS_DROPSHADOW) = CS_DROPSHADOW) 
    and IsWindowVisible(Handle) then 
    begin 
    // for speed, proper SysShadow handle is cached 
    if FSysShadowHandle = 0 then 
     EnumThreadWindows(GetCurrentThreadID(), @FindSysShadowOrderProc, 
     lParam(Self)); 
    // if SysShadow exists, change its z-order, and place it directly below this window 
    if FSysShadowHandle <> 0 then 
     SetWindowPos(FSysShadowHandle, Handle, 0, 0, 0, 0, 
     SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOOWNERZORDER or SWP_NOSIZE); 
    end; 
end; 

Bạn phải làm việc ra khi gọi FixSysShadowOrder(), bởi vì đơn đặt hàng Z thay đổi, và nó sẽ không ở ngay. Łukasz đề nghị gọi nó trong một thói quen nhàn rỗi (ví dụ như khi cập nhật một hành động), và khi nhận được thông báo WM_WINDOWPOSCHANGED.

+0

Hm ... Tôi tự hỏi liệu có ai có thể gọi đây là lỗi trong Microsoft Windows hay không. –

+0

Dưới d2010 dòng này không thể biên dịch, 'Form.FSysShadowHandle' ... –

+0

@Edwin Yip: Có thể. Bạn tự khai báo FSysShadowHandle trong TForm1 để nhớ cache xử lý, như đã nêu trong nhận xét của mã. – willw

3

"Nó hoạt động trên máy tính của tôi."

http://privat.rejbrand.se/shdw.png
(High-res)

Nhưng nó là khá buồn cười, vì tôi có một ký ức mờ nhạt làm cho kết luận tương tự khi bạn thực hiện, có nghĩa là, rằng CS_DROPSHADOW không hoạt động mà không có sự dày, thay đổi kích thước, khung. Bạn vẫn ?! chạy Windows Vista, có lẽ

+0

Đây là một điểm tuyệt vời - cảm ơn rất nhiều. Tôi đã sử dụng Windows 7, và từ thử nghiệm của riêng tôi mà làm cho một sự khác biệt ... nó không hoạt động trong ít nhất hai cách khác nhau! Tôi tắt để chỉnh sửa câu hỏi của tôi để phản ánh phức tạp hơn tôi biết tình hình. – willw

3

Đối với việc thả bóng để làm việc, chúng ta phải gọi SystemParametersInfo win32 API với tham số SPI_SETDROPSHADOW, để bật hiệu ứng đổ bóng toàn bộ hệ thống, để biết thêm thông tin, vui lòng tham khảo:

SystemParametersInfo

Các vấn đề liên quan