2010-02-02 35 views
5

Câu hỏi này là về việc giữ giao diện GUI trong các tác vụ dài hơn (một vài giây trong hầu hết các trường hợp).Làm thế nào để giữ ứng dụng Delphi Responsive trong khi cập nhật GUI?

Tôi sử dụng rộng rãi các chủ đề và mẫu nhiệm vụ để thực hiện tác vụ tốn kém trong chuỗi nền. Nhưng những gì về cập nhật GUI mất một thời gian? Ví dụ, điền vào một chuỗi lớn lưới hoặc xem cây? Một chủ đề không giúp được ở đây vì mọi thứ cần phải được đồng bộ với luồng chính.

Tôi biết sự cố của Application.ProcessMessages, nhưng hiện tại nó có vẻ như giải pháp duy nhất để thực hiện cuộc gọi đến ProcessMessages bên trong phương thức cập nhật GUI.

Bất kỳ ý tưởng nào tốt hơn?

+1

Tôi không nghĩ rằng thẻ 'đa luồng' áp dụng cho câu hỏi. – gabr

+0

@gabr: đã đồng ý và chỉnh sửa. – jpfollenius

Trả lời

5

IMO nếu bản cập nhật giao diện là nút cổ chai (ngay cả khi BeginUpdate/EndUpdate được sử dụng như @ The_Fox gợi ý) thì đã đến lúc xem xét lại các điều khiển GUI được sử dụng. Các lưới standart, treeview, listboxes không chỉ đơn giản là cắt để xử lý số lượng lớn các mục. Có rất nhiều điều khiển bên thứ ba thực hiện cả miễn phí và thương mại cho mục đích đó.

Để khởi động, hãy xem VirtualTreeview nếu nút cổ chai nằm trong khung lưới, chế độ xem trang hoặc ngữ cảnh hộp danh sách.

+2

Thay đổi chế độ xem danh sách hoặc chế độ xem dạng cây thành [VirtualTreeView] [1]. Trong Delphi 2009/2010, các thông báo gỡ lỗi "danh sách xem" thực sự là một khung nhìn ảo vì các điều khiển khác có các mục được chèn liên tục, cập nhật quá chậm để theo kịp kỳ vọng của người dùng. Bạn có một vấn đề tương tự, có vẻ như. Những gì bạn muốn là một điều khiển GUI nhanh hơn. [1]: http://www.delphi-gems.com/index.php?option=com_content&task=view&id=12&Itemid=38 –

+0

+1 VirtualTreeView là ý tưởng đầu tiên của tôi! – Remko

-2

Bạn đã thử thành phần AntiFreeze từ Indy chưa?

+0

Ông đã đề cập đến các vấn đề khi làm đầy các thành phần GUI, không bị đóng băng do tính chất chặn của khung công tác Indy TCP/IP. –

+0

Bạn nghĩ gì về AntiFreeze trong nội bộ? –

4

Có vấn đề gì với Application.ProcessMessages trong trường hợp của bạn? Phương thức Application.ProcessMessages là chính xác cho các trường hợp như vậy. Vấn đề với Application.ProcessMessages là mã như thế này:

repeat 
    Application.ProcessMessages; 
until SomethingHappens; 

Đó là xấu vì nó là tải CPU vô dụng, và cần được thay thế bằng

repeat 
    Application.HandleMessage; 
until SomethingHappens; 

trong đó sản lượng thời gian xử lý để đề khác. Single Application.ProcessMessages các cuộc gọi (không phải trong vòng lặp) là OK.

+0

Đó không phải là vấn đề duy nhất. Bạn cũng có thể dễ dàng nhận được các vấn đề reentrance và các công cụ như thế. – jpfollenius

+0

Reentrace là vấn đề của logic ứng dụng. Bạn không thể đổ lỗi cho một phương pháp xử lý tin nhắn chung cho nó. Chắc chắn một số sự kiện sẽ được xử lý khác nhau trong khi bạn đang thực hiện một cái gì đó tốn thời gian trong chủ đề GUI. – kludg

+0

Tôi biết điều đó và hiện tại tôi đang sử dụng 'ProcessMessages'. Tôi không biết nếu có gì sai với nó ... đó là lý do tại sao tôi hỏi. – jpfollenius

5

Khi điền Grids, Lists, DataSets, v.v., hãy gọi BeginUpdate/EndUpdate DisableControls/EnableControls. Điều này sẽ giúp bạn tiết kiệm thời gian. Tôi cũng đã có một thread mà đã làm một số tính toán, nhưng vẫn GUI là chậm, cho đến khi tôi được gọi là DisableControls trên datasets đã được sửa đổi và không nhìn thấy bởi vì các điều khiển trên tabsheet khác.

Ngoài ra, khi cập nhật kiểm soát, có tất cả dữ liệu bạn cần chuẩn bị, vì vậy bạn chỉ cần điền vào danh sách của mình mà không thực hiện các phép tính có thể làm chậm quá trình này.

+0

Tôi đã làm điều đó. Tuy nhiên, việc cập nhật có thể mất vài giây. – jpfollenius

+0

@Smasher: Nếu bạn có thể sử dụng các điều khiển không phù hợp cho các tập dữ liệu lớn. Sử dụng ví dụ điều khiển cây ảo (hoặc các điều khiển ảo tương tự) không nên có sự chậm trễ. Tải dữ liệu theo yêu cầu (ví dụ khi các nút cây được mở rộng) cũng sẽ giúp ích. Ngoài ra, có thể có quá nhiều dữ liệu hiển thị cùng một lúc mà người dùng không thể xử lý tất cả? Lọc có thể là một tùy chọn sau đó. – mghie

+0

@mghi: Tôi sử dụng thành phần lưới chuỗi TMS và câyView mặc định (mà tôi biết rất chậm). Dù sao, tôi muốn tránh (nếu có thể) chuyển sang thành phần khác vì nó sẽ rất khó để giữ cho cùng một cái nhìn và cảm nhận (Tôi chủ yếu quan tâm về lưới chuỗi ở đây). Ngoài ra, có các tùy chọn lọc nhưng tôi không thể buộc người dùng thực sự sử dụng chúng. – jpfollenius

1

Nếu bạn chỉ muốn xử lý các thông điệp sơn và không có gì khác: sử dụng sau đây thay vì Application.ProcessMessages:

procedure ProcessPaintMessages; 
var 
    Msg: TMsg; 
    i: Integer; 
begin 
    i := 0; 
    repeat 
    if Windows.PeekMessage(Msg, 0, 0, 0, PM_REMOVE or (QS_PAINT shl 16)) then begin 
     TranslateMessage(Msg); 
     DispatchMessage(Msg); 
    end else Break; 
    Inc(i); 
    until i > 1000; // Breakout if we are in a paint only loop! 
end; 
+0

Thú vị. Nhưng điều kiện vòng lặp đến từ đâu? Nó sẽ khá tốn kém nếu mỗi lần tôi gọi chức năng 1000 repaints phải được thực hiện ... – jpfollenius

+0

Tôi sử dụng nó ở một nơi mà tôi gọi nó chỉ mỗi 200 ms để xử lý 1000 tin nhắn có vẻ không quá nhiều. Bạn có thể cung cấp số vòng lặp tối đa làm tham số. Lưu ý rằng thông thường, hàm này xử lý không hoặc 1 thông báo. Điều kiện này chỉ để tránh một "runaway" bởi các tin nhắn sơn. –

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