How to make a canvas (rectangle) in wxpython? - python

I am trying to make a windows canvas type rectangle, here is an image if you are having issues understanding what i mean,
Is there any way todo this in wxpython? ( also, is there a way to set it to automatically adjust to the window width -20px?, so a radius around the window, and will adjust to the users window size.

EDIT: I asked on the wxPython IRC channel and a fellow named "r4z" came up with the following edit to my code which worked for me on Windows 7.
import wx
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
self.Bind(wx.EVT_PAINT, self.OnPaint)
#----------------------------------------------------------------------
def OnPaint(self, event):
""""""
pdc = wx.PaintDC(self)
try:
dc = wx.GCDC(pdc)
except:
dc = pdc
w, h = self.GetSizeTuple()
w = w - 10
h = h - 10
dc.Clear()
dc.DrawRectangle(x=5, y=5, width=w, height=h)
#----------------------------------------------------------------------
def OnSize(event):
event.EventObject.Refresh()
event.Skip()
if __name__ == "__main__":
app = wx.App(False)
frame = wx.Frame(None, title="Test")
panel = MyPanel(frame)
frame.Bind(wx.EVT_SIZE, OnSize)
frame.Show()
app.MainLoop()
Alternately, you might look at the wx.StaticBox widget.
EDIT #2: You could also just set the frame's style like this and skip the whole OnSize business:
frame = wx.Frame(None, title="Test", style=wx.DEFAULT_FRAME_STYLE|wx.FULL_REPAINT_ON_RESIZE)

Related

How to move window out of display with wxpython on linux

i have a little GUI app, which runs on Windows 7 and 10 well. With self.Move(x,y) I can move the window, if x, or y is negative, part of my window or the whole window is out of screen. I want to achieve this behavior on Linux. On ubuntu 16.04 I tried on unity and kde, but it didnt work, the whole window is always visible. Can you show me way to move my window out of screen on linux?
import wx
class MainFrame(wx.Frame):
def __init__(self, *args, **kwds):
# kwds["pos"] = (10,10)
self.frame = wx.Frame.__init__(self, *args, **kwds)
self.SetTitle("Move around the screen")
self.InitUI()
def InitUI(self):
self.location1 = wx.Point(-30,-100)
self.location2 = wx.Point(500,500)
self.panel1 = wx.Panel(self)
self.button1 = wx.Button(self.panel1, -1, label="Move", size=(80,25), pos=(10,10))
self.button1.Bind(wx.EVT_BUTTON, self.OnItem1Selected)
self.Show()
self.Move(self.location1)
def OnItem1Selected(self, event):
self.MoveAround()
def MoveAround(self):
curr_location = self.GetPosition() #or self.GetPositionTuple()
if curr_location == self.location1:
print ("moving to ", self.location2)
self.Move(self.location2)
else:
print ("moving to ", self.location1)
self.Move(self.location1)
if __name__ == '__main__':
app = wx.App()
frame = MainFrame(None)
app.MainLoop()

Set wx.Frame size (wxPython - wxWidgets)

I am new to wxPython and I am finding some issues while seting a given size for both frames and windows (widgets). I have isolated the issue to the simplest case where I try to create a Frame of 250x250 pixels.
Running the code I get a window of an actual size of 295 width by 307 height (taking into consideration the Windows´s top window bar)
I am using Python 2.7 in Windows 10.
What am I missing?
#!/bin/env python
import wx
# App Class
class MyAppTest7(wx.App):
def OnInit(self):
frame = AppFrame(title = u'Hello World', pos=(50, 60), size=(250, 250))
frame.Show()
self.SetTopWindow(frame)
return True
# AppFrame
class AppFrame(wx.Frame):
def __init__(self, title, pos, size):
wx.Frame.__init__(self, parent=None, id=-1, title=title, pos=pos, size=size)
if __name__ == '__main__':
app = MyAppTest7(False)
app.MainLoop()
An addtional test to further show issue:
#!/bin/env python
import wx
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None, title="The Main Frame")
self.SetTopWindow(self.frame)
self.frame.Show(True)
return True
class MyFrame(wx.Frame):
def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, size=(400,100), style=wx.DEFAULT_FRAME_STYLE, name="MyFrame"):
super(MyFrame, self).__init__(parent, id, title, pos, size, style, name)
self.panel = wx.Panel(self)
if __name__ == "__main__":
app = MyApp(False)
app.MainLoop()
And the result:
As you can see displayed window (frame) has 482 pixels (-see Paint's bottom bar-) instead of the expected 400.
Window size measured in pixels
Add this before your call to app.MainLoop():
import wx.lib.inspection
wx.lib.inspection.InspectionTool().Show()
That will let you easily see the actual size (and other info) for each widget in the application, like this:

GetSubBitmap() return empty bitmap on windows7

I'm using wx.Bitmap's GetSubBitmap() API. On linux (ubuntu, fedora) everything OK. Trying to port code to windows7, GetSubBitmap() return empty bitmap, which result in black bitmap.
Here is simple example that draws periodically green rectangle somewhere on panel. On windows7 it turn to black rectangle.
import wx
import random
class mypanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.buffer = wx.EmptyBitmap(700, 500)
self.SetBackgroundColour("BLUE")
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.ID_TIMER = 1
self.timer = wx.Timer(self, self.ID_TIMER)
self.Bind(wx.EVT_TIMER, self.OnTimer, id=self.ID_TIMER)
self.timer.Start(1000, wx.TIMER_CONTINUOUS)
self.BufferPaint()
self.Refresh(False)
def OnTimer(self, event):
print "OnTimerEvent " + str(event.Id)
self.BufferPaint()
def BufferPaint(self):
dc = wx.MemoryDC()
dc.SelectObject(self.buffer)
dc.SetBackground(wx.Brush("green"))
dc.Clear()
sub = self.buffer.GetSubBitmap(wx.Rect(5,5,30,30))
dc.SetBackground(wx.Brush("red"))
dc.Clear()
dc.DrawBitmap(sub, random.randint(0,600), random.randint(0,400))
self.Refresh(False)
def OnPaint(self, event=None):
dc = wx.BufferedPaintDC(self, self.buffer)
class myframe(wx.Frame):
"""Draw a line to a panel."""
def __init__(self, parent):
wx.Frame.__init__(self, parent, title="Draw on Panel", size=(800,600))
self.panel1 = mypanel(self)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.panel1, 2, wx.EXPAND)
self.SetSizer(self.sizer)
app = wx.App(False)
frame = myframe(None)
frame.Show()
app.MainLoop()
def BufferPaint(self):
dc = wx.MemoryDC()
dc.SelectObject(self.buffer)
dc.SetBackground(wx.Brush("red"))
dc.Clear()
dc.SetBrush(wx.Brush("green"))
dc.DrawRectangleRect( wx.Rect(random.randint(0,600),random.randint(0,400),30,30) )
self.Refresh(False)
I modified BufferPaint in your sample code to use DrawRectangleRect so that we explicitly paint with "green". Your code may be relying on default behavior how GetSubBitmap inherit the color which may be platform dependent.
My edit worked on my win7 machine.

wxpython - Erase background erases non-background components

In wxpython, I want to have a window with a picture that changes based on use of toolbar buttons with text controls on top of the picture. When I click the toolbar buttons, I am posting an erase background event, then capturing the erase event, and redrawing the new background from there (base on this).
Mostly works well, except that the text controls cease to be drawn once I redraw the background. They're still there, just not drawn.
Here is a simplified code that demonstrates the problem. If you run this code and click the button to toggle drawing the background image or not, the text controls disappear.:
import wx
import wx.lib.inspection
class PanelWithDrawing(wx.Panel):
def __init__(self, parent):
super(PanelWithDrawing, self).__init__(parent, size=(100, 40))
self.showbmp = False
self.txt = wx.TextCtrl(self, pos=(10, 10))
def onErase(self, dc):
if self.showbmp:
# dc.DrawBitmap(wx.Bitmap('background.png', 0, 0)
dc.DrawRectangle(0, 0, 40, 40) # use a drawing instead so you don't have to find a png
class Toolbar(wx.ToolBar):
def __init__(self, parent):
super(Toolbar, self).__init__(parent, -1)
self.AddLabelTool(wx.ID_SAVE, "Record", wx.Bitmap("picture.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, "", "")
class Example(wx.Frame):
def __init__(self, parent, title):
super(Example, self).__init__(parent, title=title)
self.toolbar = Toolbar(self)
self.SetToolBar(self.toolbar)
self.toolbar.Realize()
self.panel = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
self.panel1 = PanelWithDrawing(self.panel)
vbox.Add(self.panel1)
# self.panel2 = PanelWithText(self.panel)
# vbox.Add(self.panel2)
self.panel.SetSizer(vbox)
self.Centre()
self.Show()
self.toolbar.Bind(wx.EVT_TOOL, self.onButton)
self.panel1.Bind(wx.EVT_ERASE_BACKGROUND, self.onErase)
def onErase(self, evt):
try:
dc = evt.GetDC()
except:
dc = wx.ClientDC(self)
rect = self.GetUpdateRegion().GetBox()
dc.SetClippingRect(rect)
dc.Clear()
self.panel1.onErase(dc)
def onButton(self, evt):
self.panel1.showbmp = not self.panel1.showbmp
wx.PostEvent(self.panel1, wx.PyCommandEvent(wx.wxEVT_ERASE_BACKGROUND))
if __name__ == '__main__':
app = wx.App()
Example(None, title='Example')
wx.lib.inspection.InspectionTool().Show() # use this for debugging GUI design
app.MainLoop()
How do I tell wxpython to draw all the non-background stuff again? Alternatively, how do I not un-draw it in the first place?
After working on it for a few days, I got it! And the answer is trivially simple (as usual).
wx.PostEvent(self.panel1, wx.PyCommandEvent(wx.wxEVT_ERASE_BACKGROUND)) should be replaced with self.Refresh() to refresh the whole frame and not just force a specific (and apparently unsafe) redraw.

Creating ScrolledWindow in wxPython

I am trying to make a ScrolledWindow that can scroll over a grid of images, but the scrollbar isn't appearing. wxWidgets documentation says:
The most automatic and newest way [to set the scrollbars in wxScrolledWindow] is to simply let sizers determine the scrolling area. This is now the default when you set an interior sizer into a wxScrolledWindow with wxWindow::SetSizer. The scrolling area will be set to the size requested by the sizer and the scrollbars will be assigned for each orientation according to the need for them and the scrolling increment set by wxScrolledWindow::SetScrollRate
So I try to set the sizer of my ScrolledWindow with a GridSizer but it's not working. The code:
import wx
class MyFrame(wx.Frame):
def __init__(self, parent, id=-1,title="",pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE,
name="frame"):
wx.Frame.__init__(self,parent,id,title,pos,size,style,name)
self.panel = wx.ScrolledWindow(self,wx.ID_ANY)
menuBar = wx.MenuBar()
menu1 = wx.Menu()
m = menu1.Append(wx.NewId(), "&Blah", "Show Pictures")
menuBar.Append(menu1,"&Blah")
self.Bind(wx.EVT_MENU,self.OnInit,m)
self.SetMenuBar(menuBar)
def OnInit(self, event):
sizer = wx.GridSizer(rows=7,cols=3)
filenames = []
for i in range(20):
filenames.append("img"+str(i)+".png")
for fn in filenames:
img = wx.Image(fn,wx.BITMAP_TYPE_ANY)
sizer.Add(wx.StaticBitmap(self.panel,wx.ID_ANY,wx.BitmapFromImage(img)))
self.panel.SetSizer(sizer)
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(parent=None,title="Frame")
self.frame.Show()
self.SetTopWindow(self.frame)
return True
if __name__ == "__main__":
app = MyApp()
app.MainLoop()
Insert this
self.panel.SetScrollbars(1, 1, 1, 1)
after self.panel = wx.ScrolledWindow(self,wx.ID_ANY)
If you want some info on the SetScrollBars method then look at this wxwidgets documentation page

Categories