我希望能够调整html窗口的大小但保持滚动位置。这个例子几乎可行,但闪烁
测试:
- 使用Load Html File按钮加载一个大小合适的html文件
- 向下滚动
- 调整窗口大小。
窗口通过调整大小保持相同的位置,但它可怕地闪烁。我认为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 :(得分:0)
我使用ScrolledPanel(在调整大小时不重置其滚动条的位置)并直接渲染文本来回避问题。 (我只使用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()