2011-12-07 35 views
5

Ứng dụng của tôi là một ứng dụng cửa sổ thực hiện các thuật toán toán học phức tạp nhất định. Bởi vì tôi đã bắt đầu với ứng dụng từ lâu, hầu hết nó vẫn là một luồng đơn. Để chính xác hơn, luồng chính thực hiện tất cả logic tính toán phức tạp. Điều quan trọng cần lưu ý là trong quá trình tính toán, tôi cho thấy một số tiến bộ trên màn hình.Cách đánh lừa Windows nghĩ rằng ứng dụng của bạn vẫn đang bận, mặc dù nó không phản hồi

Trong hầu hết các trường hợp, thuật toán toán học chỉ mất vài giây, vì vậy sau khi người dùng khởi động tác vụ, một đồng hồ cát (hoặc vòng tròn đang chạy trong Windows 7) được hiển thị và một vài giây sau đó kết quả được hiển thị.

Trong một số trường hợp, thuật toán có thể mất vài phút. Trong thời gian này, tôi hiển thị đồng hồ cát và khi thuật toán bận, tôi hiển thị tiến trình trong cửa sổ của mình. Tuy nhiên, nếu người dùng nhấp vào ứng dụng sau khi đã bận trong một thời gian, Cửa sổ sẽ trở nên 'trắng hơn' (như thể một miếng nhựa không hoàn toàn trong suốt được đặt trên cửa sổ), Cửa sổ sẽ không được cập nhật nữa và các báo cáo của Windows 'ứng dụng không phản hồi'.

Tôi sử dụng Qt và tôi sử dụng chức năng Qt QWidget :: repaint để buộc một repaint trong khi thuật toán của tôi đang bận. Các repaint hoạt động trong một thời gian, nhưng như đã nói ở trên, Windows dường như để ngăn chặn điều này sau một thời gian.

Cách chính xác để cho Windows biết rằng ứng dụng của bạn vẫn đang bận để cửa sổ luôn cập nhật? Nếu tôi nhập một vòng lặp thông báo rõ ràng, người dùng có thể kích hoạt các hành động khác trong ứng dụng mà tôi không muốn.

  • Đủ để gọi PeekMessage?
  • Đủ để gọi GetMessage là đủ?
  • Hoặc tôi có nên gọi DispatchMessage không? Tôi có thể gọi một trong các thông báo này mỗi khi tôi cập nhật cửa sổ, hoặc tôi có thể giới hạn bản thân mình để gọi nó mỗi vài giây (10 giây). ?, 30 giây? ...)

Lưu ý rằng việc chuyển logic tính toán sang một chuỗi riêng biệt hiện không phải là một tùy chọn.

Tôi đang sử dụng Visual Studio 2010 trên Windows 7, kết hợp với Qt 4.7.

+0

Re "người dùng có thể kích hoạt các hành động khác trong ứng dụng mà tôi không muốn." Vì vậy, vô hiệu hóa các điều khiển đó. – ikegami

Trả lời

0

Chức năng DisableProcessWindowGhosting (xem http://msdn.microsoft.com/en-us/library/ms648415(v=vs.85).aspx) cho Windows biết rằng nó không được hiển thị 'cửa sổ ma' nếu ứng dụng không đáp ứng.

Đồng nghiệp của tôi đã làm một số thí nghiệm với nó và nhận thấy như sau:

  • các hình ảnh động cho thấy sự tiến bộ tiếp tục độc đáo (điều này thực sự là những gì tôi muốn đạt được)
  • người dùng vẫn có thể giảm thiểu, di chuyển, ... cửa sổ (tuyệt vời)
  • trên Nhược điểm: nếu ứng dụng được thực sự treo, người dùng phải sử dụng Task Manager để giết nó

Vì vậy, điều này giải quyết vấn đề của tôi.

1

Bạn có thể chỉ cần gọi QApplication::processEvents() theo thời gian, giả sử cứ sau 2 hoặc 3 giây hoặc lâu hơn. Điều đó sẽ kích hoạt một sự kiện repaint và làm mới thanh tiến trình của bạn và các yếu tố khác.

1

câu hỏi tương tự và rất nhiều thông tin ở đây: I need a message pump that doesn't mess up my open window

Tuy nhiên, như bạn có thể đã biết, điều này là khá một hack và nó sẽ được tốt hơn để cố gắng di chuyển mã để thread khác. Tại sao "không phải là một lựa chọn" này?

+0

Cảm ơn bạn đã liên kết. Di chuyển nó đến một chủ đề riêng biệt hiện không phải là một tùy chọn vì vẫn còn rất nhiều mã cũ trong thuật toán tính toán gọi qua-UI-code (nó thậm chí có thể hiển thị một hộp thoại :-)). – Patrick

5

Bạn nên tách GUI khỏi logic ứng dụng. Tất cả các giải pháp khác là hack. Việc chuyển logic tính toán sang một chuỗi riêng biệt có thể dễ dàng đạt được với Qt bằng cách sử dụng các nỗ lực nhỏ.

Tôi giả định rằng có một hàm (cho phép gọi nó là execute()) khi được gọi thực hiện tất cả các hoạt động toán học tốn thời gian này. Một tùy chọn là sử dụng Qt Concurrent API để gọi chức năng này trong một luồng riêng biệt, mà không cần sử dụng xử lý luồng cấp thấp.

Những gì bạn cần là QtConcurrent::run chức năng:

Các QtConcurrent :: run() chức năng chạy một hàm trong một thread riêng biệt. Giá trị trả lại của hàm được cung cấp thông qua API QFuture .

Thay vì chỉ đơn giản gọi execute() mà sẽ ngăn chặn giao diện người dùng của bạn, bạn có thể làm như sau (giả sử A là lớp trong đó execute() được định nghĩa):

QFuture<void> future = QtConcurrent::run(this, &A::execute); 

Bạn có thể sử dụng QFutrureWatcher để có được được thông báo về thời điểm hàm kết thúc.

+0

Thú vị. Tôi sẽ xem xét nó. – Patrick

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