Is it possible to make a wxPython window only re-sizable to a certain ratio? I know you can disable resizing; however, I'd like it so when the window was resized it stuck to a certain width to height ratio.
One obvious way to do this would be to bind wx.EVT_SIZE to a function that constrains the aspect ratio. I'm not certain this is The Right Way to do this, but it works:
import wx
class SizeEvent(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Centre()
self.SetSizeWH(400, 300)
self.Show(True)
def OnSize(self, event):
hsize = event.GetSize()[0] * 0.75
self.SetSizeHints(minW=-1, minH=hsize, maxH=hsize)
self.SetTitle(str(event.GetSize()))
app = wx.App()
SizeEvent(None, 1, 'sizeevent.py')
app.MainLoop()
(The boilerplate is borrowed from here.)
I'm not too familiar with wxPython, but can't you just reset the window size to your max/min size that you want once the user pass that? Preferably in the event that detects resizing?
Related
I would like to know if it is possible to change the formatting of a grid object in wxPython.
Specifically I would like to know how to change the background color, font type, font color, and border color of the header labels and the row labels.
Here is a simple grid that I would like to change the formatting of:
import wx
import wx.grid as gridlib
class MyForm(wx.Frame):
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, parent=None, title="A Simple Grid")
panel = wx.Panel(self)
myGrid = gridlib.Grid(panel)
myGrid.CreateGrid(12, 8)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(myGrid, 1, wx.EXPAND)
panel.SetSizer(sizer)
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm().Show()
app.MainLoop()
Thanks in advance!
First off, wx.PySimpleApp has been deprecated for a very long time and you really shouldn't use it any more. Use wx.App instead.
As for your question you would need to use wx.lib.mixins.gridlabelrenderer. The demo has an example in it called GridLabelRenderer that you can use. Basically you subclass GridLabelRenderer and modify its Draw method. Then you call each column's SetColLabelRenderer method and set it to use your custom renderer.
I'm taking the first steps to move from .NET to Python but I'm already having a few headaches regarding the GUI design.
For some reason, passing the size attribute to a wx.Button seems to be kind of ignored. And I say "kind of" because the actual space seems to change but the actual button keeps occupying the same space:
import wx
class Example(wx.Frame):
def __init__(self, *args, **kwargs):
super(Example, self).__init__(*args, **kwargs)
self.InitUI()
def InitUI(self):
self.SetSize((800, 600))
self.SetTitle('Main Menu')
self.Centre()
self.Show(True)
''' Fill the form '''
self.lblUsername = wx.StaticText(self, size=(80, -1), pos=(20,20), label="Username:" )
self.txtUsername = wx.TextCtrl(self, size=(140, -1), pos=(100,20), style=wx.TE_PROCESS_ENTER)
self.lblPassword = wx.StaticText(self, size=(80, -1), pos=(20,50), label="Password:" )
self.txtPassword = wx.TextCtrl(self, size=(140, -1), pos=(100,50), style=wx.TE_PROCESS_ENTER)
self.btnOK = wx.Button( self, label="OK", pos=(260, 16), size=(50,50))
self.btnOK.Bind(wx.EVT_BUTTON, self.onClickOK)
self.statusbar = self.CreateStatusBar()
self.statusbar.SetStatusText('Ready')
def onClickOK(self, e):
print "Button triggered"
def main():
ex = wx.App()
Example(None)
ex.MainLoop()
if __name__ == '__main__':
main()
No matter what size I set, the Button won't stretch (it will be centered as if all the space was actually being used, but will still be small).
Can anyone spot what am I doing wrong?
This is a limit imposed by OSX. The way the native button widget is drawn only allows it to be stretched horizontally, and the vertical size is fixed. Or rather, as you've discovered, the widget itself can be larger than normal vertically, but it will only draw itself at a fixed height within that space. It seems less neccessary with modern versions of OSX, but if you look at buttons in OSX from a few years ago you can probably see why this is so. The esthetic graphical effect of the "tic-tack" or "capsule" buttons would be totally ruined if they were a non-standard vertical size, causing the images used to draw the buttons to be stretched. wxWidgets follows the native plaform look and feel standards where possible, in this case it happens that Apple's standard is imposed upon us and wx can't offer the same level of flexibility that it usually does.
You do have some options however if you really want taller than normal buttons. The native widgets have a few different standard sizes, which you can select using the SetWindowVariant method, although I don't think the variants would get as tall as you want. Or you could use a generic button widget instead of a native one, such as wx.lib.buttons.ThemedGenButton.
Same problem in my little Software EventSoundControl.
Just a workaround: Use a multiline label and sizes of wxButton will work as desired!
If you want the button to stretch when you resize the frame, then you cannot use static sizes and positioning. You will need to put your widgets in a sizer. Then the sizer will manage the position / size of the widget(s) as you change the size of the frame. There are many examples on the wxPython wiki that demonstrate how to use sizers. You might also find the following tutorial helpful:
http://zetcode.com/wxpython/layout/
I am trying to add a feature to a calculator i have made with wxpython, i want there to be a button , that when clicked changes the background colour (the panel). To show you my code i have made a smaller program, that should only change colour, and even in this one i get the same outcome:
the background colour doesn't change, nothing happens when i click the button, and i dont even receive any errormessahe.Actually, the calculator does change colour, but not in the way i want it to, it only changes the colour of the text (a wx.StaticText), and it's not really meant to do that.
Anyway, here is the code :
import wx
class calc(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,"Calculator",size=(400,400))
global panel
panel=wx.Panel(self)
a=wx.Button(panel,label="GO",pos=(100,100),size=(50,50))
self.Bind(wx.EVT_BUTTON, self.change, a)
def change(self,event):
panel.SetBackgroundColour("red")
if __name__=="__main__":
app=wx.App(False)
frame=calc(parent=None,id=-1)
frame.Show()
app.MainLoop()
when i run this, the frame with the button show up, and when i click on the button, nothing happens!! Does anybody know what is wrong with this?
Thanks in advice!!!
While your code worked for me on Xubuntu 14.04, wxPython 2.8.12 and Python 2.7, I went ahead and rewrote it slightly to remove the global and clean it up a bit:
import wx
class calc(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="Calculator", size=(400,400))
self.panel = wx.Panel(self)
a = wx.Button(self.panel, label="GO", pos=(100,100), size=(50,50))
self.Bind(wx.EVT_BUTTON, self.change, a)
def change(self,event):
self.panel.SetBackgroundColour("red")
self.Refresh() # for windows
if __name__=="__main__":
app = wx.App(False)
frame = calc()
frame.Show()
app.MainLoop()
This also works for me.
I have a simple wxPython application. It basically has a image and a text-entry field (a wx.TextCtrl).
I want to be able to immediately be able to start entering text as soon as the window opens. Right now, I have to first click in the text control, and then I can start entering text.
Here is a minimal app that demonstrates the issue:
import wx
class MyFrame(wx.Frame):
""" We simply derive a new class of Frame. """
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(200, 100))
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
mainSizer.Add(self.control, 1, wx.EXPAND)
self.SetSizer(mainSizer)
self.Show(True)
app = wx.App(False)
frame = MyFrame(None, 'Small editor')
app.MainLoop()
I've poked around with wx.SetInsertionPoint, but that does not seem to have any effect.
Ah, derp. I had to look further up the inheritance chain.
You can simply call SetFocus() on the control (in this case, self.control.SetFocus()).
SetFocus() is a member function of wxWindow. I was only looking at the docs for wxTextCtrl.
Of course, I didn't think to look up the inheritance chain until I had already asked the question.
I'm leaving this here, as this is a pretty hard to google issue. Hopefully this will help someone else.
import wx
class TestDraw(wx.Panel):
def __init__(self,parent=None,id=-1):
wx.Panel.__init__(self,parent,id)
self.SetBackgroundColour("#FFFFFF")
self.Bind(wx.EVT_PAINT,self.onPaint)
def onPaint(self, event):
event.Skip()
dc=wx.PaintDC(self)
dc.BeginDrawing()
width=dc.GetSize()[0]
height=dc.GetSize()[1]
if height<width:
self.drawTestRects(dc)
else:
dc.Clear()
dc.EndDrawing()
def drawTestRects(self,dc):
dc.SetBrush(wx.Brush("#000000",style=wx.SOLID))
dc.DrawRectangle(50,50,50,50)
dc.DrawRectangle(100,100,100,100)
class TestFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(640,480))
self.mainPanel=TestDraw(self,-1)
self.Show(True)
app = wx.App(False)
frame = TestFrame(None,"Test App")
app.MainLoop()
This code should draw the test rectangles only when the height is less than the width, and otherwise the window should remain clear. However, if you mess with resizing the window, the panel isn't actually redrawn unless it is moved off the window. What am I doing wrong?
You can bind a method to handle wx.EVT_SIZE or the panel and invalidate it there. Alternatively simply use the wx.FULL_REPAINT_ON_RESIZE for the panel.
The documentation for a SizeEvent claims that there may be some complications when drawing depends on the dimensions of the window. I do not know exactly what is going on behind the scenes. I followed the suggestion on the link and added the call self.Refresh() to the top of onPaint() and this seems to give the desired behavior. See mghie's answer for a more efficient example of working code.