While I was browsing wxPython demo, I found a really nifty window called wx.MiniFrame.
I thought it was nice for my app but soon realized it's wx.Frame. I wanted it inside my application to draw a graph. I didn't want one of my nodes to travel outside my application window and join Firefox, so I decided to make a similar one as a panel.
Can you see which one is MiniFrame and which is MiniPanel?
One that cannot' be outside the application window is MiniPanel!
(well, anybody talked about close but something? I don't know... (works on Windows))
I haven't finished minor tunings, e.g. the title is embedded in the code, but it's already resizable.
Jul. 15 added:
I tested on (Python2.6, wxPython-2.8.10.1, Fedora11) and (Python 2.6.2, wxPython 2.8.10.1, WindowsXP). Not tested on Mac.
import wx import wx.lib.resizewidget as resizewidget import cStringIO as StringIO batten = '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x11\x00\x00\x00\x10\x08\x02\x00\x00\x00\x7fS\x03\x08\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\x04gAMA\x00\x00\xb1\x8f\x0b\xfca\x05\x00\x00\x00 cHRM\x00\x00z&\x00\x00\x80\x84\x00\x00\xfa\x00\x00\x00\x80\xe8\x00\x00u0\x00\x00\xea`\x00\x00:\x98\x00\x00\x17p\x9c\xbaQ<\x00\x00\x00`IDAT8OcdX\xf9\x9f\x81d\x00\xd4C*B\xd6\xf0\x1f7@1\x17\xce\x01\xaa\xc7c!\x8a,\xa6\x1edi8\x1b\x9f\x1e\xb8\xeb\x80f\xa1\xb1\x11\xae\xc0j\x0f\xb2\xbf \n\x08\xb8\r\xcd\x06\xa2\xf4\xa0\x05\x1ea=\xe4\xfb\x07\x7f`2P\x14?\xc8^\xc7L\x0f\xd8\xd3\x01\t\xa9\x8e\x04\xa5\xf0\xa4L\x86\x1e\x00\xbc\xf4\xfe\xa6\xcaO\x9a\x16\x00\x00\x00\x00IEND\xaeB`\x82' bmpstream = StringIO.StringIO(batten) try: image = wx.ImageFromStream(bmpstream) finally: bmpstream.close() class _TitleBarPanel(wx.Panel): def __init__(self, parent, titleFGColour, titleBGColour, barWidth, fontSize, title): wx.Panel.__init__(self, parent, pos = (0, 0), size = (0, barWidth)) self.SetBackgroundColour(titleBGColour) self.SetMaxSize((100000, barWidth)) self.parent = parent self.gparent = parent.GetParent() self.restwin = None #Title static text. self.titlest = titlest = wx.StaticText(self, -1, title, size = (100000, barWidth)) titlest.SetForegroundColour(titleFGColour) font = titlest.GetFont() font.SetPointSize(fontSize) titlest.SetFont(font) #Close bitmap button. bfi = wx.BitmapFromImage(image) self.closeb = b = wx.BitmapButton(self, -1, bfi, (0, 0), (barWidth, barWidth), style = wx.BU_EXACTFIT) b.SetToolTipString("Delete this node.") hsizer = wx.BoxSizer(wx.HORIZONTAL) hsizer.Add(titlest, 1, wx.EXPAND | wx.CENTER) hsizer.Add(b, 0, wx.RIGHT) self.SetSizer(hsizer) self.titlest.Bind(wx.EVT_BUTTON, self.onClose, b) self.Bind(wx.EVT_BUTTON, self.onClose, b) self.titlest.Bind(wx.EVT_LEFT_DOWN, self.onTitleMouseLeftDown) self.titlest.Bind(wx.EVT_LEFT_UP, self.onTitleMouseLeftUp) self.Bind(wx.EVT_LEFT_UP, self.onTitleMouseLeftUp) self.titlest.Bind(wx.EVT_MOTION, self.onTitleMouseMotion) self.Bind(wx.EVT_MOTION, self.onTitleMouseMotion) self.titlest.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.onTitleMouseCaptureLost) self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.onTitleMouseCaptureLost) def onClose(self, ev): self.parent.Close() def onTitleMouseLeftDown(self, ev): self.titlest.CaptureMouse() x, y = ev.GetPosition() sx, sy = self.titlest.GetScreenPosition() gx, gy = self.gparent.GetPosition() self.px, self.py = sx + x, sy + y self.gx, self.gy = gx, gy def onTitleMouseLeftUp(self, ev): if self.titlest.HasCapture(): self.titlest.ReleaseMouse() def onTitleMouseMotion(self, ev): if ev.Dragging(): x, y = ev.GetPosition() sx, sy = self.titlest.GetScreenPosition() px, py = sx + x, sy + y if self.restwin: fsx, fsy = self.restwin.GetScreenPosition() fw, fh = self.restwin.GetSize() margin = self.margin if px < fsx + margin or py < fsy + margin or px > fsx + fw - margin or py > fsy + fh - margin: return self.gparent.SetPosition((self.gx + px - self.px, self.gy + py - self.py)) def onTitleMouseCaptureLost(self, ev): self.titlest.ReleaseMouse() def setDragRestrictWindow(self, window, margin): self.restwin = window self.margin = margin class NodePanel(wx.Panel): def __init__(self, parent, id = wx.ID_ANY, pos=wx.DefaultPosition, size = wx.DefaultSize, style = wx.TAB_TRAVERSAL|wx.NO_BORDER, name=wx.PanelNameStr, borderColour = wx.BLACK, minSize = (0, 0), maxSize = (-1, -1), bgColour = wx.NullColour, titleFGColour = wx.WHITE, titleBGColour = wx.Colour(80, 167, 255), barWidth = 13, fontSize = 8, title = 'MiniPanel'): wx.Panel.__init__(self, parent, id, pos, size, style | wx.FULL_REPAINT_ON_RESIZE, name) self.borderColour = borderColour rw = resizewidget.ResizeWidget(parent, pos = pos, style = wx.FULL_REPAINT_ON_RESIZE) self.SetMinSize(minSize) self.SetMaxSize(maxSize) rw.SetManagedChild(self) self.tb = tb = _TitleBarPanel(self, titleFGColour, titleBGColour, barWidth, fontSize, title) self.clientPanel = clientPanel = wx.Panel(self) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(tb, 0, wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border = 3) sizer.Add(clientPanel, 1, wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.RIGHT, border = 3) self.SetSizer(sizer) self.SetBackgroundColour(bgColour) clientPanel.SetBackgroundColour(bgColour) rw.SetSize(size) self.Bind(wx.EVT_PAINT,self.OnPaint) self.Bind(wx.EVT_IDLE,self.OnPaintOnIdle) def OnPaintOnIdle(self, ev): #self._onPaint(wx.ClientDC(self)) pass def OnPaint(self, ev): self._onPaint(wx.PaintDC(self)) def _onPaint(self, dc): #Use double buffering as you like. #(wxPython-demo dir)/samples/pySketch/pySketch.py has a good example of it. dc.SetPen(wx.Pen(self.borderColour)) x, y = self.GetSize() dc.DrawLine(0, 0, x-1, 0) dc.DrawLine(0, 0, 0, y-1) dc.DrawLine(x-1, 0, x-1, y-1) dc.DrawLine(0, y-1, x-1, y-1) def setDragRestrictWindow(self, window, margin = 0): #If you don't set this, the Panel will go outside the window. Is there a nice way? :( self.tb.setDragRestrictWindow(window, margin) def getClientPanel(self): return self.clientPanel def getTitleStaticText(self): return self.tb.titlest def Destroy(self): #The resize handle is the parent of the Panel(reparented). We want to destroy #the handle too. We'll override Destroy() to make sure it is destroyed. self.GetParent().Destroy() if __name__ == '__main__': myapp=wx.PySimpleApp() frame = wx.Frame(None, -1, "Title", size = wx.Size(300, 400)) scroll = wx.ScrolledWindow(frame, -1) scroll.SetScrollbars(50,50,10,10) np = NodePanel(scroll, pos = (30, 30), size = (200, 200), borderColour = (128, 128, 128)) np.setDragRestrictWindow(scroll, 15) print np.getTitleStaticText().GetLabel() def OnClose(ev): if ev.CanVeto(): dlg = wx.MessageDialog(None, 'Are you sure?', 'msgb', wx.YES_NO) if dlg.ShowModal() == wx.ID_YES: np.GetParent().Destroy() dlg.Destroy() else: np.Destroy() np.Bind(wx.EVT_CLOSE, OnClose, np) def CloseIt(ev): np.Close() clientAreaCloseButton = wx.Button(np.getClientPanel(), -1, "Close Me", pos = (20, 20)) np.Bind(wx.EVT_BUTTON, CloseIt, clientAreaCloseButton) frame.Show() myapp.MainLoop()
1 comment:
Nice sample, am learning wxPython too ... and looking for the wx.lib.resizewidget, your example is working in my environment. Thanks! Good Job!
Post a Comment