2015-09-08 19 views
11

Đây là ở ngã ba Phoenix của wxPython.Các chủ đề wxPython chặn

Tôi đang cố gắng chạy một vài luồng vì lợi ích của việc không chặn GUI.

Hai chủ đề của tôi hoạt động tốt, nhưng một trong số các chủ đề khác dường như không bao giờ đạt đến hàm kết quả bị ràng buộc. Tôi có thể nói rằng nó đang chạy, nó dường như không đúng để đăng sự kiện.

Dưới đây là các chức năng kết quả cho chủ đề tính chính:

def on_status_result(self, event): 
    if not self.panel.progress_bar.GetRange(): 
     self.panel.progress_bar.SetRange(event.data.parcel_count) 
    self.panel.progress_bar.SetValue(event.data.current_parcel) 
    self.panel.status_label.SetLabel(event.data.message) 

Đây là cách tôi đang ràng buộc họ:

from wx.lib.pubsub.core import Publisher 
PUB = Publisher() 

Đây là cách tôi đang ràng buộc phương pháp:

def post_event(message, data): 
    wx.CallAfter(lambda *a: Publisher().sendMessage(message, data=data)) 

Và đây là các chủ đề. Người đầu tiên không làm việc, nhưng thứ hai hai làm:

class PrepareThread(threading.Thread): 
    def __init__(self, notify_window): 
     threading.Thread.__init__(self) 
     self._notify_window = notify_window 
     self._want_abort = False 

    def run(self): 
     while not self._want_abort: 
      for status in prepare_collection(DATABASE, self._previous_id, self._current_id, self._year, self._col_type, 
              self._lock): 
       post_event('prepare.running', status) 
     post_event('prepare.complete', None) 
     return None 

    def abort(self): 
     self._want_abort = True 


class SetupThread(threading.Thread): 
    def __init__(self, notify_window): 
     threading.Thread.__init__(self) 
     self._notify_window = notify_window 
     self._want_abort = False 

    def run(self): 
     while not self._want_abort: 
      do_more_stuff_with_the_database() 
      return None 

    def abort(self): 
     self._want_abort = True 


class LatestCollectionsThread(threading.Thread): 
    def __init__(self, notify_window): 
     threading.Thread.__init__(self) 
     self._notify_window = notify_window 
     self._want_abort = False 

    def run(self): 
     while not self._want_abort: 
      do_stuff_with_my_database() 
      return None 

    def abort(self): 
     self._want_abort = True 

prepare_collection là một chức năng mà mang lại Status đối tượng trông như thế này:

class Status: 
    def __init__(self, parcel_count, current_parcel, total, message): 
     self.parcel_count = parcel_count 
     self.current_parcel = current_parcel 
     self.total = total 
     self.message = message 

Đây là cách tôi đang tạo/bắt đầu/đăng ký các PrepareThread:

MainForm(wx.Form): 
    prepare_thread = PrepareThread(self) 
    prepare_thread.start() 

    self.pub = Publisher() 
    self.pub.subscribe(self.on_status_result, 'prepare.running') 
    self.pub.subscribe(self.on_status_result, 'prepare.complete') 

    def on_status_result(self, event): 
     if not self.panel.progress_bar.GetRange(): 
      self.panel.progress_bar.SetRange(event.data.parcel_count) 
     self.panel.progress_bar.SetValue(event.data.current_parcel) 
     self.panel.status_label.SetLabel(event.data.message) 

tôi đã cố gắng loại bỏ dần từng prepare_collection với range(10), nhưng tôi vẫn không bao giờ nhấn eve nt xử lý.

+0

hey morgan xin lỗi ... tôi có lẽ sẽ không có cơ hội tối nay để xem xét điều này ... chỉ siêu bận rộn:/ –

+0

@joran Đó là tất cả tốt. –

+0

oh dang ... xin lỗi ... Tôi sẽ cố gắng và giúp đỡ cuối tuần này của bạn chỉ là một tuần điên rồ –

Trả lời

4

Đây có thể là một câu trả lời khá tham gia và đó là một chút khó khăn để tìm ra chính xác của các đoạn mã của bạn có trong mỗi phần của mã của bạn (nghĩa là các tệp mà tất cả chúng đều có trong đó). Tôi giả định rằng bạn muốn giữ phương thức pubsub để làm điều này (tôi nghĩ đó là một ý tưởng hay). Nếu cấu trúc của dự án thực sự của bạn là rất phức tạp, bạn có thể cần quản lý phức tạp hơn của Publisher hơn tôi sử dụng ở đây - cho tôi biết ...


Ở đây đi - Tôi sẽ đưa spoiler đầu tiên - đây là một one file solution cho những gì bạn muốn - một bảng điều khiển có nút khởi động chuỗi chuẩn, thanh trạng thái và trình xử lý khi chuẩn bị xong. Thử nghiệm với wxPython Phoenix 64 bit Python 3 và cũ wxPython trên Python 2.7. Cả hai trên Windows - nhưng tôi có thể quay nó trong một hộp Linux nếu cần thiết.

Tổng hợp tình hình (không nồi hơi-tấm) bit quan trọng của tập tin đó

Bạn cần một đối tượng duy nhất Publisher rằng chủ đề của bạn gửi tin nhắn đến và chủ đề chính của bạn (MainForm trong ví dụ của bạn tôi đoán) đăng ký. Bạn có thể quản lý một Publisher cho mỗi chủ đề, nhưng tôi nghĩ ở đây bạn chỉ cần một cho PrepareThread, vì vậy tôi sẽ đi với mô hình đó cho bây giờ.

Ở phía trên cùng của tập tin của bạn, sử dụng

from wx.lib.pubsub import pub 

này cho phép quản lý việc pubsub instantiating một đối tượng duy nhất Publisher.

Trong chủ đề của bạn, như bạn đang làm, công bố thông điệp đó - một ammendment nhẹ để post_event helper của bạn:

def post_event(message, data): 
    wx.CallAfter(lambda *a: pub.sendMessage(message, data=data)) 

Trong chủ đề chính của bạn - đăng ký vào các thông điệp. Tôi muốn nói nó thường dễ nhất để có một bộ xử lý cho mỗi tin nhắn, chứ không phải gửi hai thông điệp khác nhau để xử lý giống như bạn được, vì vậy tôi đã đi cho

pub.subscribe(self.on_status_result, 'prepare.running') 
pub.subscribe(self.on_status_finished, 'prepare.complete') 

Bạn có thể để lại on_status_result vì nó là và xác định một tương tự on_status_finished. Trong ví dụ của tôi, tôi đã có cái này sau cho phép một nút mới cho phép bạn thực hiện một số công việc thực tế.

N.B. Bạn cần phải cẩn thận khi đặt tên cho tải trọng của tin nhắn của bạn - pubsub cung cấp khá nhiều thông tin về những gì nó mong đợi ở đó và nó bắt gặp tôi lúc đầu.


P.S. Ngay khi kết thúc chuẩn bị câu trả lời này - tôi đã tìm thấy this blog post. Nó nói một cái gì đó tương tự như những gì tôi có ở trên, vì vậy tôi sẽ không tái tạo nó, nhưng họ sử dụng phương pháp khác của instantiating Publisher() như ví dụ ban đầu của bạn - ngụ ý rằng nên làm việc quá. Bạn có thể thích từ ngữ ở đó. Simlarly - bạn có thể tìm thấy trang this wxPython wiki hữu ích.

+0

Điều này trông giống như những gì tôi cần. Hãy cho tôi khoảng một giờ và sau đó tôi sẽ thử nó! –

+0

Nó hoạt động! J, bạn là một người đàn ông đẹp. –

+0

công việc tốt .. xin lỗi tôi đã bận ... trong cuộc gọi wx2.8 tới nhà xuất bản đăng ký sendMessage được chia sẻ trên tất cả các trường hợp (trên thực tế Publisher() có thể trả lại cùng một trường hợp ...) –

4

vấn đề là hệ thống sự kiện kết thúc bằng cách gọi hàm cập nhật (bộ điều khiển sự kiện) từ chính chuỗi, bạn nên không bao giờ làm điều đó (về cơ bản bạn kết thúc với điều kiện và hiện vật lạ) ... gọi lại trong chuỗi chính.

wxPython đã xem xét điều này và mọi phương thức được gọi với wx.CallAfter sẽ được gọi từ vòng lặp chương trình chính luôn chạy trong chuỗi chính. này kết hợp với các mô-đun wx.pubsub cho phép bạn tạo khung làm việc sự kiện riêng của bạn một cách dễ dàng ... một cái gì đó như thế này

def MyPostEvent(event_name,event_data): 
    #just a helper that triggers the event with wx.CallAfter 
    wx.CallAfter(lambda *a:Publisher().sendMessage(event_name,data=event_data)) 

#then to post an event 

MyPostEvent("some_event.i_made_up",{"payload":True}) 

#then in your main thread subscribe 

def OnEventHandler(evt): 
    print "EVT.data",evt.data 

pub = Publisher() 
pub.subscribe("some_event.i_made_up",OnEventHandler) 
+0

Liệu "some_event.i_made_up" có giống với thông tin tôi chuyển đến MyPostEvent không?Ngoài ra, điều này làm việc với Phoenix? –

+0

nó sẽ hoạt động trên phượng hoàng (có thể cần một số sửa đổi nhỏ ... nhưng khái niệm nói chung được áp dụng) –

+0

có đó là những gì bạn sẽ vượt qua: P (xem các ví dụ về nhận và phát sự kiện) –

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