2009-07-13 7 views
8

Đây có thể là một câu hỏi của người mới bắt đầu, nhưng tôi không thể cho cuộc sống của tôi tìm ra.Buộc Flex cập nhật màn hình?

Tôi đang sử dụng flex để phát triển GUI cho một dự án lớn, cụ thể là thanh trạng thái dọc theo phía dưới. Trong lớp StatusBar của tôi là một ProgressBar, các lớp khác đang làm việc có thể nói để cập nhật (thay đổi hoàn thành thanh và nhãn) khi chúng tiến triển. Vấn đề tôi đang gặp phải là flex sẽ không cập nhật whats hiển thị trên màn hình cho đến khi quá muộn, ví dụ

ProgressBar khởi tạo, 0% thực hiện
một số lớp đặt ProgressBar là 12% hoàn tất
một số lớp hiện một số công việc
một số lớp đặt ProgressBar là 56% thực hiện

Whats xảy ra là 12% thực hiện không bao giờ được hiển thị, nó chỉ bị treo tại 0% trong khi làm việc, sau đó bỏ qua tới 56%. Tôi đã cố gắng để hiểu vòng đời của một thành phần flex (vô hiệu và xác nhận), và tôi nghĩ rằng tôi hiểu nó và đang áp dụng nó một cách chính xác, nhưng nó không làm việc ở tất cả. Tôi cần phải nói flex để vẽ lại Statusbar của tôi (hoặc ít nhất là trong vòng ProgressBar) sau một số lớp bộ nó được 12% thực hiện, nhưng trước khi một số lớp bắt đầu làm công việc của mình. Làm thế nào để tôi làm điều này?

+0

Vấn đề này thực sự nên được coi là * cho phép * Flex cập nhật màn hình. Như đã chỉ ra bên dưới, Flash là một mô hình thực thi chuỗi đơn cho mã của bạn. Vì vậy, bạn cần phải chunk công việc của bạn cho phép người chơi để làm mới màn hình hiển thị giữa các khối. callLater() hoặc sử dụng bộ đếm thời gian để kiểm soát chunking mình là cơ chế cơ bản có sẵn. Hãy nhớ rằng nếu bạn làm * không * làm điều này, trình duyệt có thể sẽ chạy trình phát Flash sau 45 giây (mặc định FF) – verveguy

Trả lời

2

Hãy thử gọi invalidateDisplayList() sau mỗi thay đổi đối với thanh tiến trình của bạn. Một cái gì đó như:

Class StatusBar 
{ 

    public function set progress(value:uint):void 
    { 
     progressBar.value = value; 
     progressBar.invalidateDisplayList(); 
    } 
} 

Flex có chu kỳ làm mất hiệu lực để tránh vẽ lại màn hình mỗi lần thay đổi thuộc tính. Ví dụ: nếu giá trị của thuộc tính thay đổi 3 lần trong một khung, nó sẽ chỉ hiển thị với tập hợp giá trị cuối cùng. Bạn có thể buộc một thành phần được vẽ lại bằng cách gọi invidateDisplayList() có nghĩa là updateDisplayList sẽ được thực thi ngay lập tức thay vì đợi khung tiếp theo.

+1

Thực ra nó sẽ không gọi updateDisplayList() "ngay lập tức" nhưng nó sẽ gọi nó ở lần kế tiếp cập nhật màn hình/khung hình. Nếu nó đã làm nó ngay lập tức nó sẽ loại thất bại điểm của mô hình vô hiệu hóa/xác nhận hợp lệ. –

+0

Tệ của tôi, bạn hoàn toàn đúng. Thay vì gọi invalidateDisplayList(), bạn phải gọi trực tiếp updateDisplayList() –

2

Actionscript trong trình phát Flash, như Javascript trong trình duyệt, là giả đa luồng. Tức là, chúng là một luồng đơn, nhưng chúng có nhiều ngăn xếp thực thi. Điều này có nghĩa là bạn không thể "ngủ" trong một chủ đề cụ thể, nhưng bạn có thể sinh ra một chồng thực thi mới được trì hoãn cho đến một thời gian sau đó. Cách làm flex là thực hiện chức năng "callLater". Bạn cũng có thể sử dụng các hàm setTimeout/setInterval. Hoặc bạn có thể sử dụng đối tượng hẹn giờ được tích hợp vào trình phát flash. Hoặc thậm chí là trình nghe sự kiện "ENTER_FRAME". Tất cả những điều này về cơ bản sẽ cho phép bạn làm những gì bạn cần, nếu tôi chính xác về nguyên nhân của vấn đề của bạn.

Có vẻ như bạn có một "chủ đề" làm hầu hết công việc của mình, không bao giờ dừng lại để cho phép ngăn xếp thực khác (đề *) để chạy.

Vấn đề có thể là những gì Pez đang nói, nhưng nếu điều đó không giúp đỡ, bạn có thể muốn thử một số cuộc gọi hoãn lại cho các lớp lao động. Vì vậy, quá trình của bạn có thể trông giống như sau:

  1. Tiến trình khởi tạo.
  2. Thực hiện một số công việc.
  3. Cập nhật thanh tiến trình thành 12. (danh sách hiển thị không hợp lệ)
  4. setTimeout (doMoreWork, 100);
  5. Cập nhật thanh tiến trình thành 52.

(nếu nhân viên của bạn là UIcomponent, bạn có thể sử dụng uicomp.callLater (...), nếu không, bạn cần sử dụng setTimeout/timers/enter_frame cho lớp AS3 thuần túy).

9

Như đã đề cập trong các câu trả lời khác, trình phát flash đơn luồng, nếu bạn không chia nhỏ công việc của mình thành các phần riêng biệt có thể được thực hiện trong "khung" riêng biệt, bạn sẽ thấy các bước nhảy và méo trong ui, đó là những gì bạn thấy.

Nếu bạn thực sự thấy thông báo 12%, thì không đủ để vô hiệu danh sách hiển thị, vì danh sách hiển thị không có cơ hội cập nhật cho đến sau khi hoàn thành 56% công việc, bạn phải ngắt chu kỳ sự kiện tự nhiên với một cuộc gọi đến validateNow() sau khi tin nhắn của bạn đã được thiết lập.

Tuy nhiên, đây không phải là cách tốt nhất để làm việc nếu hiệu suất là mối quan tâm. Bạn có thể nhận được bằng cách sử dụng tư pháp callLater() để lên lịch từng đoạn công việc, vì điều này sẽ cho phép người chơi có khả năng hoàn thành chu kỳ khung (và cập nhật danh sách hiển thị) trước khi thử bước tiếp theo trong quy trình của bạn.

+0

Tôi vẫn không thể nhận được nó, tôi gọi invalidateDisplayList() theo sau ngay lập tức bằng validateNow() và nó không xuất hiện để cập nhật. Lớp StatusBar của tôi cũng như ProgressBar và ProgressBarSkin đang bị vô hiệu hóa và sau đó được xác nhận, nó đi tất cả các cách mặc dù và thậm chí là drawRect() để vẽ lại phần đầy của ProgressBar, nhưng nó vẫn chưa thực sự cập nhật màn hình. –

+1

Bạn đã thử gọi hàmLocal, setTimeout hoặc tương tự, như tôi đã đề xuất chưa? Có vẻ như quá trình xử lý của bạn đang chặn trình kết xuất khỏi cập nhật màn hình. Bạn cần phải tạm dừng, và để cho nó thở. – Glenn

+0

Aha! Nói về kỳ lạ, tôi có thể làm cho nó cập nhật khi tôi muốn sử dụng setTimeout, miễn là thời gian thực hiện phần còn lại của hàm sau khi setTimeout (doWork, X) mất ít hơn X. Nói cách khác, tôi phải để flash đi nhàn rỗi (để biết thêm sau đó 25ms). Điều này tuy nhiên phá vỡ nếu tôi đặt breakpoint ở sai vị trí hoặc nếu tôi thử và bước qua mã. –

3

Glenn,

Đó không phải là cách tất cả các luồng trong Flex hoạt động như thế nào. Giống như nhiều giao diện người dùng, nó có một máy bơm thông điệp trên luồng giao diện người dùng chính (chúng làm việc đó trong các khung). Khi bạn gọi callLater() nó đặt con trỏ hàm được truyền vào cuối hàng đợi của máy bơm (trên khung tiếp theo) và trả về ngay lập tức. Chức năng này sau đó được gọi khi máy bơm tin nhắn đã xử lý xong tất cả các thông báo trước (như nhấp chuột).

Vấn đề là khi thay đổi thuộc tính gây ra các sự kiện giao diện người dùng được kích hoạt, sau đó đặt thông điệp của riêng chúng trên máy bơm hiện tại sau khi phương thức của bạn gọi là số callLater().

Flex không có nhiều chuỗi nhưng chúng ở đó vì lý do riêng của Adobe và do đó không thể truy cập được. Tôi không biết nếu có một cách để đảm bảo rằng một cập nhật giao diện người dùng sẽ xảy ra tại một điểm cụ thể, nhưng một tùy chọn là gọi callLater một số lần cho đến khi hoạt động xảy ra. Bắt đầu với một số lượng nhỏ và tăng cho đến khi số lần lặp lại tạo ra kết quả bạn muốn. Ví dụ:

// Change this to a number that works... it will probably be over 1, depending on what you're doing. 
private const TOTAL_CALL_COUNT:int = 5; 

private var _timesCalled:int = 0; 

//---------------------------------------------------------------- 
private function set Progress(progress:int):void 
{ 
    progressBar.value = progress; 
    DoNextFunction(); 
} 

//---------------------------------------------------------------- 
private function DoNextFunction():void 
{ 
    if(_timesCalled >= TOTAL_CALL_COUNT) 
    { 
     _timesCalled = 0; 
     Function(); 
    } 
    else 
    { 
     _timesCalled++; 
     callLater(DoNextFunction); 
    } 
} 
+0

Bạn đang hiểu nhầm phản hồi của tôi. Tôi đã nói về AS3/Flash chủ yếu, không phải Flex. "callLater" là một triển khai Flex trên đó. Nó chỉ sử dụng các sự kiện như ENTER_FRAME để hoạt động ở chế độ nền. – Glenn

+1

Chuyển ra callLater cho setTimeout sẽ làm cho nó hoạt động trong AS3. –

0

Tôi đang sử dụng Flash Builder 4.6 và tôi cũng gặp sự cố khi hiển thị thanh tiến trình của mình. Tôi mở một cửa sổ mới, nơi tôi bắt đầu một lớp đa cấp mới (39 Mo nội dung). Cửa sổ mới được mở ở chế độ nền và cửa sổ chính hiển thị thanh tiến trình cho đến khi lớp multiloader kết thúc công việc của anh ta. Tuy nhiên cửa sổ đang mở đang chặn hoạt ảnh của cửa sổ chính của tôi. Tôi biết nó không phải là lớp multiloader vì tôi thấy nó chạy một cách chính xác.

Nhưng tôi sẽ cố gắng tìm một số cách làm mới.

Mục đích chính của bài đăng của tôi là adobe phức tạp đã xây dựng xung quanh flash. Khi bạn tìm kiếm tài nguyên cho ứng dụng hoặc câu trả lời cho câu hỏi của riêng bạn, đó là một nỗi đau thực sự để tìm nguồn tài nguyên tốt. Có một tổng số hỗn hợp lên (ở bên adobe và ở phía người dùng) giữa AS3, Flex, Flash CS, Flash Builder, AiR, ... Nếu bạn cố gắng phát triển trong AS3, bạn sẽ thấy rằng một số ví dụ sẽ không hoạt động vì nó không được triển khai trong SDK của bạn. Bạn có ngày càng nhiều diễn đàn cung cấp cho bạn câu trả lời "thực hành tốt nhất" hoặc mỉa mai dựa trên trải nghiệm trên nền tảng phát triển khác nhau.

Ví dụ: chỉ ở đây, tôi thấy progressBar.value = value; Với kinh nghiệm của tôi, tôi có thể nói rằng trong Flash Builder 4.6, thuộc tính này là chỉ đọc. Nhưng nó có thể là một lớp tùy chỉnh được thực hiện bởi người sử dụng nhưng những người có thể nói.

1

Đôi khi thiết lập cần thiết của nó bằng 0 trước khi gán giá trị khác. tiến trìnhBar.setProgress (0, progressBar.maximum); tiến trìnhBar.setProgress (newValue, progressBar.maximum);