2009-12-09 2 views
1

Я хочу, чтобы изменить размер окна html, но сохранить положение прокрутки. Этот пример почти работает, но мерцает.
Для теста:
- загрузить хороший размер HTML-файл с помощью кнопки
Нагрузки файла HTML - прокрутка вниз
- изменить размер окна.Как сохранить wx.html.HtmlWindow в той же позиции во время изменения размера (без мерцания)?

Окно сохраняет свое положение по размерам, но оно ужасно мерцает. Я думаю, код для htmlwindow сбрасывает положение прокрутки до 0 каждого размера. Я бы хотел, чтобы он не перерисовывался до тех пор, пока позиция прокрутки не будет зафиксирована в функции post_resize.

Я пробовал различные комбинации замораживания/оттаивания и пытался подключиться к событиям краски, но не имел успеха. Предложения?

import wx 
import wx.html 

_POST_RESIZE_EVENT = wx.NewEventType() 

class _PostResizeEvent(wx.PyEvent): 
    def __init__(self, pos): 
     wx.PyEvent.__init__(self) 
     self.SetEventType(_POST_RESIZE_EVENT) 
     self.pos = pos 

def EVT_POST_RESIZE(win, func): 
    win.Connect(-1, -1, _POST_RESIZE_EVENT, func) 


class MyHtmlPanel(wx.Panel): 
    """ 
    class MyHtmlPanel inherits wx.Panel and adds a button and HtmlWindow 
    """ 
    def __init__(self, parent, id): 
     # default pos is (0, 0) and size is (-1, -1) which fills the frame 
     wx.Panel.__init__(self, parent, id) 
     self.SetDoubleBuffered(True) 
     self.SetBackgroundColour("yellow") 
     self.html1 = wx.html.HtmlWindow(self, id, pos=(0,30), size=(602,310)) 

     self.btn1 = wx.Button(self, -1, "Load Html File", pos=(0,0)) 
     self.btn1.Bind(wx.EVT_BUTTON, self.OnLoadFile) 

     self.btn2 = wx.Button(self, -1, "Clear Page", pos=(120,0)) 
     self.btn2.Bind(wx.EVT_BUTTON, self.OnClearPage) 

     sizer = wx.BoxSizer(wx.VERTICAL) 
     sizer.Add(self.btn1, 0) 
     sizer.Add(self.btn2, 0) 
     sizer.Add(self.html1, 1, wx.EXPAND) 
     self.SetSizer(sizer) 

     self.html1.Bind(wx.EVT_SCROLLWIN, self.OnScroll) 
     self.Bind(wx.EVT_SIZE, self.OnSize) 
     EVT_POST_RESIZE(self.html1, self.post_resize) 
     self.hist=0 

    def OnScroll(self, evt): 
     self.hist = self.html1.GetViewStart()[1] 
     evt.Skip() 

    def OnSize(self, evt): 
     wx.PostEvent(self.html1, _PostResizeEvent(self.hist)) 
     evt.Skip() 

    def post_resize(self, evt): 
     self.html1.Scroll(0, evt.pos) 

    def OnLoadFile(self, event): 
     dlg = wx.FileDialog(self, wildcard = '*.html', style=wx.OPEN) 
     if dlg.ShowModal(): 
      path = dlg.GetPath() 
      self.html1.LoadPage(path) 
     dlg.Destroy() 

    def OnClearPage(self, event): 
     self.html1.SetPage("") 


app = wx.PySimpleApp() 
# create a window/frame, no parent, -1 is default ID, title, size 
frame = wx.Frame(None, -1, "HtmlWindow()", size=(610, 380)) 
# call the derived class, -1 is default ID 
MyHtmlPanel(frame,-1) 
# show the frame 
frame.Show(True) 
# start the event loop 
app.MainLoop() 

ответ

0

Я обошел эту проблему, используя ScrolledPanel (который не приводит к сбросу позиции своих scrollsbars' на изменение размера) и прямой рендеринг текста. (Я использовал панель html только для текста цветового кода).

Полученный класс:

import wx 
import wx.lib.scrolledpanel as scrolledpanel 


class ScrollableText(scrolledpanel.ScrolledPanel): 
    def __init__(self, parent, id=-1, text=[[('black', 'adsf')]]): 
     scrolledpanel.ScrolledPanel.__init__(self, parent, id) 

     self.SetBackgroundColour('white') 
     self.SetVirtualSize((1500, 1500)) 
     self.SetupScrolling(True, True) 

     # a list of lists of (color, string) tuples 
     self.Bind(wx.EVT_PAINT, self.redraw) 
     self.Bind(wx.EVT_SIZE, self.resize) 

     # setup the font 
     self.font = wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL) 
     if not self.font.IsFixedWidth(): 
      self.font = wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.NORMAL, wx.NORMAL) 
     assert self.font.IsFixedWidth() 

     self.text = text 
     self.set_longest_line() 

    def set_text(self, text): 
     self.text = text 
     self.set_longest_line() 
     self.resize(None) 
     self.Refresh() 

    def set_longest_line(self): 
     if len(self.text) > 0: 
      self.longest_line = max([sum([len(s) for c, s in l]) for l in self.text]) 
     else: 
      self.longest_line = 1 

    def draw_lines(self, DC, start, end, lineheight): 
     mw = 0 
     DC.SetFont(self.font) 
     for idx in range(max(0, start), min(end, len(self.text))): 
      l = self.text[idx] 
      combined = "".join([s[1] for s in l]) 
      extents = [0] + DC.GetPartialTextExtents(combined) 
      for str in l: 
       DC.SetTextForeground(str[0]) 
       DC.DrawText(str[1], extents[0], idx * lineheight) 
       extents = extents[len(str[1]):] 

    def resize(self, evt): 
     DC = wx.ClientDC(self) 
     DC.SetFont(self.font) 

     # find line width and height 
     extent = DC.GetFullTextExtent('X'*self.longest_line) 
     lineheight = extent[1] 
     maxwidth = extent[0] 

     # set virtual area 
     vsize = (maxwidth, len(self.text) * lineheight) 
     if self.GetVirtualSize() != vsize: 
      self.SetVirtualSize(vsize) 

    def redraw(self, evt): 
     DC = wx.PaintDC(self) 
     self.PrepareDC(DC) 
     extent = DC.GetFullTextExtent('x'*self.longest_line) 
     lineheight = extent[1] 
     vs = self.GetViewStart() 
     ppu = self.GetScrollPixelsPerUnit() 
     ri = wx.RegionIterator(self.GetUpdateRegion()) 
     mmin, mmax = len(self.text), 0 
     while ri: 
      rect = ri.GetRect() 
      # find the lines that need rendering 
      min_y = rect[1] + vs[1] * ppu[1] 
      max_y = rect[1] + rect[3] + vs[1] * ppu[1] 
      min_line = int(min_y/lineheight) - 1 
      max_line = int(max_y/lineheight) + 2 
      mmin = min(min_line, mmin) 
      mmax = max(max_line, mmax) 
      ri.Next() 
     self.draw_lines(DC, mmin, mmax, lineheight) 



if __name__ == '__main__': 
    class MainFrame(wx.Frame): 
     def __init__(self, parent): 
      wx.Frame.__init__(self, parent, -1) 
      t = [[('black', l[:len(l)/2]), ('red', l[len(l)/2:])] for l in open('scrollable_text.py')] 
      self.scrollable = ScrollableText(self, -1, t) 

    app = wx.PySimpleApp(None,-1) 
    frame = MainFrame(parent=None) 
    frame.Show() 
    app.MainLoop() 
Смежные вопросы