2011-01-05 21 views
6

Tôi gặp sự cố với wxPython. Một phiên bản đơn giản của mã được đăng bên dưới (không gian trắng, chú thích, v.v ... được xóa để giảm kích thước - nhưng định dạng chung cho chương trình của tôi được giữ nguyên như nhau). Khi tôi chạy tập lệnh, văn bản tĩnh kết thúc chính xác như mong muốn, nhưng các mục khác trong bảng điều khiển không di chuyển xuống (chúng hoạt động như thể statictext chỉ là một dòng và do đó không phải mọi thứ đều hiển thị). Nếu tôi thay đổi kích thước cửa sổ/khung hình theo cách thủ công, thậm chí chỉ là một số lượng nhỏ, mọi thứ sẽ được sửa và hiển thị như mong muốn. Tôi chụp ảnh màn hình để hiển thị hành vi này, nhưng tôi vừa tạo tài khoản này và do đó không có 10 điểm danh tiếng được yêu cầu để được phép đăng ảnh.Các vấn đề về wxPython với Gói StaticText

Tại sao màn hình không hiển thị chính xác để bắt đầu? Tôi đã thử tất cả các loại kết hợp của GetParent(). Refresh() hoặc Update() và GetTopLevelParent(). Update() hoặc Refresh(). Tôi đã thử tất cả mọi thứ tôi có thể nghĩ đến nhưng không thể làm cho nó hiển thị chính xác mà không cần thay đổi kích thước khung/cửa sổ theo cách thủ công. Khi kích thước lại, nó hoạt động chính xác như tôi muốn.

Thông tin:
Windows XP
Python 2.5.2
wxPython 2.8.11.0 (MSW-unicode)

Bất kỳ lời đề nghị? Cảm ơn!

Code:

#! /usr/bin/python 

import wx 

class StaticWrapText(wx.PyControl): 
    def __init__(self, parent, id=wx.ID_ANY, label='', pos=wx.DefaultPosition, 
       size=wx.DefaultSize, style=wx.NO_BORDER, 
       validator=wx.DefaultValidator, name='StaticWrapText'): 
     wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name) 
     self.statictext = wx.StaticText(self, wx.ID_ANY, label, style=style) 
     self.wraplabel = label 
     #self.wrap() 
    def wrap(self): 
     self.Freeze() 
     self.statictext.SetLabel(self.wraplabel) 
     self.statictext.Wrap(self.GetSize().width) 
     self.Thaw() 
    def DoGetBestSize(self): 
     self.wrap() 
     #print self.statictext.GetSize() 
     self.SetSize(self.statictext.GetSize()) 
     return self.GetSize() 

class TestPanel(wx.Panel): 
    def __init__(self, *args, **kwargs): 
     # Init the base class 
     wx.Panel.__init__(self, *args, **kwargs) 
     self.createControls() 
    def createControls(self): 
     # --- Panel2 ------------------------------------------------------------- 
     self.Panel2 = wx.Panel(self, -1) 
     msg1 = 'Below is a List of Files to be Processed' 
     staticBox  = wx.StaticBox(self.Panel2, label=msg1) 
     Panel2_box1_v1 = wx.StaticBoxSizer(staticBox, wx.VERTICAL) 
     Panel2_box2_h1 = wx.BoxSizer(wx.HORIZONTAL) 
     Panel2_box3_v1 = wx.BoxSizer(wx.VERTICAL) 

     self.wxL_Inputs = wx.ListBox(self.Panel2, wx.ID_ANY, style=wx.LB_EXTENDED) 

     sz = dict(size=(120,-1)) 
     wxB_AddFile = wx.Button(self.Panel2, label='Add File',  **sz) 
     wxB_DeleteFile = wx.Button(self.Panel2, label='Delete Selected', **sz) 
     wxB_ClearFiles = wx.Button(self.Panel2, label='Clear All',  **sz) 
     Panel2_box3_v1.Add(wxB_AddFile, 0, wx.TOP, 0) 
     Panel2_box3_v1.Add(wxB_DeleteFile, 0, wx.TOP, 0) 
     Panel2_box3_v1.Add(wxB_ClearFiles, 0, wx.TOP, 0) 

     Panel2_box2_h1.Add(self.wxL_Inputs, 1, wx.ALL|wx.EXPAND, 2) 
     Panel2_box2_h1.Add(Panel2_box3_v1, 0, wx.ALL|wx.EXPAND, 2) 

     msg = 'This is a long line of text used to test the autowrapping ' 
     msg += 'static text message. ' 
     msg += 'This is a long line of text used to test the autowrapping ' 
     msg += 'static text message. ' 
     msg += 'This is a long line of text used to test the autowrapping ' 
     msg += 'static text message. ' 
     msg += 'This is a long line of text used to test the autowrapping ' 
     msg += 'static text message. ' 
     staticMsg = StaticWrapText(self.Panel2, label=msg) 

     Panel2_box1_v1.Add(staticMsg,  0, wx.ALL|wx.EXPAND, 2) 
     Panel2_box1_v1.Add(Panel2_box2_h1, 1, wx.ALL|wx.EXPAND, 0) 
     self.Panel2.SetSizer(Panel2_box1_v1) 

     # --- Combine Everything ------------------------------------------------- 
     final_vbox = wx.BoxSizer(wx.VERTICAL) 
     final_vbox.Add(self.Panel2, 1, wx.ALL|wx.EXPAND, 2) 
     self.SetSizerAndFit(final_vbox) 

class TestFrame(wx.Frame): 
    def __init__(self, *args, **kwargs): 
     # Init the base class 
     wx.Frame.__init__(self, *args, **kwargs) 
     panel = TestPanel(self) 
     self.SetClientSize(wx.Size(500,500)) 
     self.Center() 

class wxFileCleanupApp(wx.App): 
    def __init__(self, *args, **kwargs): 
     # Init the base class 
     wx.App.__init__(self, *args, **kwargs) 
    def OnInit(self): 
     # Create the frame, center it, and show it 
     frame = TestFrame(None, title='Test Frame') 
     frame.Show() 
     return True 

if __name__ == '__main__': 
    app = wxFileCleanupApp() 
    app.MainLoop() 

EDIT:
Xem bài của tôi dưới đây cho một giải pháp mà làm việc!

Trả lời

3

Sử dụng mã của Mike Driscoll làm đường cơ sở, tôi hy vọng điều này thể hiện sự cố của tôi. Có hai phiên bản khác nhau của việc sử dụng "txt". Dưới đây là ba điều tôi muốn bạn thử:

  1. Chạy như vậy. Với StaticWrapText của tôi. Nó hiển thị sai lúc đầu, nhưng lại kích thước cửa sổ và nó hoạt động chính xác như tôi muốn. Không có lãng phí không gian trống/dưới văn bản trước khi "nút"

  2. Thay đổi hai dòng sau (thay đổi ý kiến):
    txt = wx.StaticText (bảng điều khiển, label = text)
    #txt = StaticWrapText (bảng điều khiển, nhãn = văn bản)
    Bây giờ bạn sẽ thấy không có gói và văn bản luôn ở trên một dòng. Chắc chắn không phải những gì chúng tôi muốn. Điều này là do "sizer.Add (txt, 0, wx.EXPAND, 5)" ... do đó hãy chuyển sang Phần 3 ...

  3. Giữ thay đổi từ Phần 2 và cũng thay đổi:
    sizer .Thêm (txt, 0, wx.EXPAND, 5)
    tới:
    sizer.Thêm (txt, 1, wx.EXPAND, 5)
    Vì vậy, bây giờ statictext sẽ mở rộng. Đây là CLOSE để làm việc ...NHƯNG Tôi không muốn tất cả không gian lãng phí giữa văn bản và nút. Nếu bạn làm cho cửa sổ lớn, có rất nhiều không gian lãng phí. Xem Phần 1 sau khi cửa sổ được tái kích thước để thấy sự khác biệt.

Code:

import wx 

class StaticWrapText(wx.PyControl): 
    def __init__(self, parent, id=wx.ID_ANY, label='', pos=wx.DefaultPosition, 
       size=wx.DefaultSize, style=wx.NO_BORDER, 
       validator=wx.DefaultValidator, name='StaticWrapText'): 
     wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name) 
     self.statictext = wx.StaticText(self, wx.ID_ANY, label, style=style) 
     self.wraplabel = label 
     #self.wrap() 
    def wrap(self): 
     self.Freeze() 
     self.statictext.SetLabel(self.wraplabel) 
     self.statictext.Wrap(self.GetSize().width) 
     self.Thaw() 
    def DoGetBestSize(self): 
     self.wrap() 
     #print self.statictext.GetSize() 
     self.SetSize(self.statictext.GetSize()) 
     return self.GetSize() 

class MyForm(wx.Frame): 
    def __init__(self): 
     wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial") 

     # Add a panel so it looks the correct on all platforms 
     panel = wx.Panel(self, wx.ID_ANY) 

     text = "I'm subclasses the statictext because I want it to act exactly like a static text, but correctly wordwrap as needed. I've found several examples of it on the web, but none that worked how I wanted. The wordwrap makes it look much nicer when the user may decide to re-size the window, so I would definitely like to have it be wordwrapped. I know about the wx.lib.wordwrap, but chose to use the built in Wrap function of the statictext control instead. It basically does the same thing from what I understand." 
     #txt = wx.StaticText(panel, label=text) 
     txt = StaticWrapText(panel, label=text) 
     wxbutton = wx.Button(panel, label='Button', size=wx.Size(120,50)) 
     sizer = wx.BoxSizer(wx.VERTICAL) 
     sizer.Add(txt,  0, wx.EXPAND, 5) 
     sizer.Add(wxbutton, 1, wx.EXPAND, 5) 
     panel.SetSizer(sizer) 

# Run the program 
if __name__ == "__main__": 
    app = wx.PySimpleApp() 
    frame = MyForm().Show() 
    app.MainLoop() 

EDIT:

AHHH ... cuối cùng! Tôi đã thử sử dụng phương thức Layout() trên hầu hết mọi cấp độ của chương trình, nhưng tôi thực sự cần sử dụng Layout() trên SIZER được tìm thấy với phương thức GetSizer() - hoặc bạn có thể gửi SendSizeEvent() tới panel (nhận xét) trong mã dưới đây). Vì vậy, sau đây bây giờ không chính xác những gì tôi muốn! Cảm ơn đã giúp đỡ. Sự thay đổi duy nhất khác là lưu bảng điều khiển bằng self.panel trong lớp khung. Như một lưu ý, tôi đã phải đặt câu lệnh này SAU frame.Show() hoặc nó không hoạt động chính xác.

Code:

import wx 

class StaticWrapText(wx.PyControl): 
    def __init__(self, parent, id=wx.ID_ANY, label='', pos=wx.DefaultPosition, 
       size=wx.DefaultSize, style=wx.NO_BORDER, 
       validator=wx.DefaultValidator, name='StaticWrapText'): 
     wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name) 
     self.statictext = wx.StaticText(self, wx.ID_ANY, label, style=style) 
     self.wraplabel = label 
     #self.wrap() 
    def wrap(self): 
     self.Freeze() 
     self.statictext.SetLabel(self.wraplabel) 
     self.statictext.Wrap(self.GetSize().width) 
     self.Thaw() 
    def DoGetBestSize(self): 
     self.wrap() 
     #print self.statictext.GetSize() 
     self.SetSize(self.statictext.GetSize()) 
     return self.GetSize() 

class MyForm(wx.Frame): 
    def __init__(self): 
     wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial") 

     # Add a panel so it looks the correct on all platforms 
     self.panel = wx.Panel(self, wx.ID_ANY) 

     text = "I'm subclasses the statictext because I want it to act exactly like a static text, but correctly wordwrap as needed. I've found several examples of it on the web, but none that worked how I wanted. The wordwrap makes it look much nicer when the user may decide to re-size the window, so I would definitely like to have it be wordwrapped. I know about the wx.lib.wordwrap, but chose to use the built in Wrap function of the statictext control instead. It basically does the same thing from what I understand." 
     txt = StaticWrapText(self.panel, label=text) 
     wxbutton = wx.Button(self.panel, label='Button', size=wx.Size(120,50)) 
     sizer = wx.BoxSizer(wx.VERTICAL) 
     sizer.Add(txt,  0, wx.EXPAND, 5) 
     sizer.Add(wxbutton, 1, wx.EXPAND, 5) 
     self.panel.SetSizer(sizer) 

# Run the program 
if __name__ == "__main__": 
    app = wx.PySimpleApp() 
    frame = MyForm() 
    frame.Show() 
    #frame.panel.SendSizeEvent() 
    frame.panel.GetSizer().Layout() 
    app.MainLoop() 

Là một lưu ý cuối cùng, trong chương trình ban đầu của tôi được đăng, dòng sau cần phải được bổ sung ngay trước khi hoặc sau khi frame.Show():
frame.panel.Panel2.GetSizer() .Layout()

Thật thú vị ... với ví dụ ban đầu này có thể là trước hoặc sau frame.Show() nhưng ví dụ khác yêu cầu phải sau frame.Show(). Tôi không chắc chắn tại sao, nhưng chỉ cần đặt nó sau và bạn an toàn.

+0

Tôi nên nghĩ về điều đó. Bạn thường muốn gọi Bố cục hoặc trên phụ huynh của các tiện ích hoặc trình chỉnh sửa chứa các tiện ích con. Oh well. Xin lỗi tôi đã không phát hiện ra điều đó. –

+0

Cảm ơn sự giúp đỡ! Nó vẫn không hoàn toàn hoạt động vì nó nên khi tôi phóng to/thu nhỏ cửa sổ. Nhưng hiện tại, nó là đủ tốt. –

+0

Ah, điều này làm cho nó hoạt động ngay cả khi nút tối đa được sử dụng ... trong hàm bọc, sử dụng self.statictext.Wrap (self.GetParent(). GetSize(). Width) thay vì self.statictext.Wrap (self .GetSize(). Chiều rộng) –

2

Tại sao bạn lại phân loại nó? Bạn có cần wordwrap không? Nếu vậy, có một mô-đun cho điều đó trong wx.lib.wordwrap mà bạn có thể sử dụng.

Trong câu trả lời nhận xét của OP, check this out:

import wx 

class MyForm(wx.Frame): 

    def __init__(self): 
     wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial") 

     # Add a panel so it looks the correct on all platforms 
     panel = wx.Panel(self, wx.ID_ANY) 

     text = "I'm subclasses the statictext because I want it to act exactly like a static text, but correctly wordwrap as needed. I've found several examples of it on the web, but none that worked how I wanted. The wordwrap makes it look much nicer when the user may decide to re-size the window, so I would definitely like to have it be wordwrapped. I know about the wx.lib.wordwrap, but chose to use the built in Wrap function of the statictext control instead. It basically does the same thing from what I understand." 
     txt = wx.StaticText(panel, label=text) 
     sizer = wx.BoxSizer(wx.HORIZONTAL) 
     sizer.Add(txt, 1, wx.EXPAND, 5) 
     panel.SetSizer(sizer) 

# Run the program 
if __name__ == "__main__": 
    app = wx.PySimpleApp() 
    frame = MyForm().Show() 
    app.MainLoop() 

Tôi đã từng nhận xét của OP cho các văn bản. Dù sao, điều này làm việc tốt cho tôi trên Windows XP, Python 2.5 và wxPython 2.8.10.1.

+0

tôi lớp con các statictext vì tôi muốn nó hoạt động chính xác như một văn bản tĩnh, nhưng chính xác wordwrap khi cần thiết. Tôi đã tìm thấy một số ví dụ về nó trên web, nhưng không có ví dụ nào làm việc theo cách tôi muốn. Các wordwrap làm cho nó trông đẹp hơn nhiều khi người dùng có thể quyết định tái kích thước cửa sổ, vì vậy tôi chắc chắn muốn có nó được wordwrapped. Tôi biết về wx.lib.wordwrap, nhưng đã chọn sử dụng chức năng Wrap trong xây dựng của điều khiển statictext thay thế. Về cơ bản nó cũng giống như những gì tôi hiểu. –

+0

Bạn có thể muốn sử dụng SetSizeHints để giữ cho khung không bị thu nhỏ quá nhỏ. –

+0

OK, ví dụ của bạn nhỏ hơn, vì vậy sẽ dễ dàng hơn khi làm việc. Xem câu trả lời của tôi cho một sửa đổi mã của bạn mà chứng minh vấn đề của tôi (rõ ràng hơn, tôi hy vọng). –

5

tôi sử dụng

width = 200 # panel width 
txt = wx.StaticText(panel, label=text) 
txt.Wrap(width) 

này hoạt động tuyệt vời và các vật dụng tiếp theo được định vị một cách chính xác. Bạn có thể dễ dàng thực hiện txt.Wrap(width) động.

+0

cảm ơn! Điều này là đơn giản và hoạt động tuyệt vời – Harry

1

Tôi đã tìm thấy những gì tôi nghĩ là một cách dễ dàng và tự động hơn để xử lý vấn đề này.

Sau khi tạo điều khiển StaticText, liên kết điều khiển wx.EVT_SIZE với trình xử lý gọi hàm Wrap() của StaticText với sự kiện GetSize() [0] làm đối số (và sau đó bỏ qua sự kiện).

Một ví dụ:

class MyDialog(wx.Dialog): 
    def __init__(self, parent): 
     wx.Dialog.__init__(self, parent = parent, title = "Test Dialog", style = wx.CAPTION) 

     bigstr = "This is a really long string that is intended to test the wrapping functionality of the StaticText control in this dialog. If it works correctly, it should appear as multiple lines of text with a minimum of fuss." 

     self.__label__ = wx.StaticText(parent = self, label = bigstr) 
     self.__actionbutton__ = wx.Button(parent = self, label = "Go") 

     self.__label__.Bind(wx.EVT_SIZE, self.__WrapText__) 
     self.__actionbutton__.Bind(wx.EVT_BUTTON, self.__OnButton__) 

     sizer = wx.BoxSizer(wx.VERTICAL) 
     sizer.Add(self.__label__, flag = wx.ALL | wx.EXPAND, border = 5) 
     sizer.Add(self.__actionbutton__, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.CENTER, border = 0) 
     self.SetSizer(sizer) 

     self.Layout() 

    def __OnButton__(self, event): 
     self.EndModal(wx.ID_OK) 

    def __WrapText__(self, event): 
     self.__label__.Wrap(event.GetSize()[0]) 

     event.Skip() 

Đây là những gì nó trông giống như trên hệ thống của tôi (MSW, Python 2.7.5, wx 2.8.12.1): StaticText Wrapping Dialog

+0

Gọi điện thoại bọc bên trong một xử lý EVT_SIZE dường như gọi cùng một xử lý một lần nữa, lần này với một kích thước khác nhau. – Pod