it is possible to add things into a StaticBox, in wxPython?
I know this is a rather simple question however I cannot seem to find anything on Google.
I would like to actually be able to add things into the StaticBox, such as buttons.
Looking at the code from one of my old projects, it looks like I used a StaticBoxSizer, and added the elements to this sizer.
Quick test:
app = wx.App(redirect=False)
frame = wx.Frame(None)
static_box = wx.StaticBox(frame, label='Label')
sizer = wx.StaticBoxSizer(static_box, wx.VERTICAL)
for i in range(5):
sizer.Add(wx.Button(frame, label='Button ' + str(i)))
frame.Sizer = sizer
frame.Sizer.Fit(frame)
frame.Show()
app.MainLoop()
Related
I have a collection of buttons arranged in a row.
Here is a simplified example of my code:
import wx
app = wx.App(False)
frame = wx.Frame(None)
panel = wx.Panel(frame, wx.ID_ANY)
box = wx.BoxSizer(wx.HORIZONTAL)
for i in range(10):
btn = wx.Button(panel, wx.ID_ANY, "Test")
box.Add(btn, 1, wx.FIXED_MINSIZE)
panel.SetSizer(box)
frame.Show()
app.MainLoop()
Making the window smaller leads to the buttons being hidden, as would be expected. However, I want the buttons to retain their dimensions and be moved to a second row instead of shrinking and finally disappearing. I have tried using different settings and different types of sizers but with no avail. How can I go about doing this?
Any help would be greatly appreciated.
I just found out that wxPython has a sizer that does this. For some reason I didn't notice it on the docs before. For anyone stumbling on this in the future, you'll want to use wx.WrapSizer instead of wx.BoxSizer.
In a GTK 3 release, the ListBox widget added supported for multiple elements being selected from the list:
I'd like to achieve the same effect with GTK 2. I'm considering using a ScrolledWindow with a VBox of CheckButton's. I fear it's not going to look very good though; like this, but with a scrollbar:
Does anyone know a good way to emulate the functionality in the first image using GTK 2?
It turns out there was a method of doing just this buried in the documentation! In fact, you should find it all the way back to GTK 2.0, but the selection constant might have had a different name (SELECTION_MULTI).
The widget looks like this:
The color scheme is inherited from my GNOME theme, so don't mind the window styling too much. This widget works with both Ctrl and Shift keys. It doesn't automatically have multiple selection just clicking on the different items.
Here's the (Python 2) MWE I made for this:
import gtk
class UI(gtk.Window):
def __init__(self):
gtk.Window.__init__(self)
self.set_position(gtk.WIN_POS_CENTER)
self.set_default_size(250, 150)
store = gtk.ListStore(str)
for i in range(7):
# The list notation here is odd, but required.
store.append(["Item %d" % i])
tree_view = gtk.TreeView()
tree_view.set_model(store)
# The view can support a whole tree, but we want just a list.
renderer = gtk.CellRendererText()
column = gtk.TreeViewColumn("Multiple Selection", renderer, text=0)
tree_view.append_column(column)
# This is the part that enables multiple selection.
tree_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
scrolled_tree = gtk.ScrolledWindow()
scrolled_tree.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
scrolled_tree.add_with_viewport(tree_view)
self.add(scrolled_tree)
def main():
win = UI()
win.connect("destroy", gtk.main_quit)
win.show_all()
gtk.main()
if __name__ == "__main__":
main()
I am using wxPython to make a gui. Currently I have a menubar, and three panels. I want to have a grid show up in the second panel when I click a button. However. When I click on the button, all I get is a small grey rectangle.
Here is the code for the button:
self.Bind(wx.EVT_BUTTON, self.OnCo, id=self.submit.GetId())
and here is the code for the "OnCo" event when the button is clicked:
def OnCo(self, e):
#to get rid of stuff that was previously in the panel
for child in self.panel2.GetChildren():
child.Destroy()
for child in self.panel3.GetChildren():
child.Destroy()
mygrid = gridlib.Grid(self.panel2, -1)
mygrid.CreateGrid(500,7)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(mygrid, -1, wx.EXPAND)
self.panel2.SetSizer(sizer)
mygrid.SetColLabelValue(0, 'S')
mygrid.SetColLabelValue(1, 'PB')
mygrid.SetColLabelValue(2, 'P')
mygrid.SetColLabelValue(3, 'T')
mygrid.SetColLabelValue(4, 'D')
Any help on how I can get my grid to show? Thanks.
It's possible that the grid is not sizing correctly; your items may be there, but it's not showing everything. After changing values in a grid, I always make sure to update the sizing of it. I usually just add a simple function to the class like this:
def SetGridSize(self):
self.mygrid.AutoSizeRows()
self.mygrid.AutoSizeColumns()
self.sizer.Fit(self)
and then call SetGridSize() whenever I change the values to make sure the whole thing shows on the screen instead of getting cut off.
Of course, you'll have to adapt it a bit to your names and whatnot. This implementation assumes the class is a wx.Frame object.
wxpython 2.8.11.0, python 2.7
If i put some Sizer with some controls directly into a Frame like
import wx
app=wx.App()
frm = wx.Frame(None, title='title')
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(wx.SpinCtrl(frm))
sizer.Add(wx.SpinCtrl(frm))
frm.SetSizerAndFit(sizer)
frm.Show()
app.MainLoop()
the Frame will automagically have a correct minimum size to contain the Sizer and it is not possible to make it smaller.
If there is a Panel in between (as needed for tabbing between controls) this does not work, the window can be made too small.
import wx
app=wx.App()
frm = wx.Frame(None, title='title')
pan = wx.Panel(frm)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(wx.SpinCtrl(pan))
sizer.Add(wx.SpinCtrl(pan))
pan.SetSizerAndFit(sizer)
frm.Show()
app.MainLoop()
Additionally frm.Fit() and frm.SetMinSize(frm.GetEffectiveMinSize()) are required to get the same behavior. Full Code:
import wx
app=wx.App()
frm = wx.Frame(None, title='title')
pan = wx.Panel(frm)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(wx.SpinCtrl(pan))
sizer.Add(wx.SpinCtrl(pan))
pan.SetSizerAndFit(sizer)
frm.Fit()
frm.SetMinSize(frm.GetEffectiveMinSize())
frm.Show()
app.MainLoop()
I am okay with frm.Fit(), but i dislike frm.SetMinSize(frm.GetEffectiveMinSize()). Isn't there a better solution so that the Frame automatically considers the minimum size of the Panel just like with the Sizer before? I'm considered with what happens if the EffectiveMinSize changes after another control is added to the sizer.
Edit:
Apparently
panel.SetSizerAndFit(sizer)
frm.Fit()
frm.SetMinSize(frm.GetEffectiveMinSize())
should be replaced by
panel.SetSizer(sizer)
sizer.SetSizeHints(frm)
which looks somewhat cleaner. So in total this looks like
import wx
app=wx.App()
frm = wx.Frame(None, title='title')
pan = wx.Panel(frm)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(wx.SpinCtrl(pan))
sizer.Add(wx.SpinCtrl(pan))
pan.SetSizer(sizer)
sizer.SetSizeHints(frm)
frm.Show()
app.MainLoop()
Is this the preferred way to do this?
If widgets are added later on even the first approach with the Sizer directly on the Frame doesn't get it right without intervention, so i think that is a totally different question.
The most elegant way (IMHO) is given in phineas' answer. It is slightly inefficient to have an extra otherwise unneeded sizer but I don't think it can really be noticeable.
Some people do call SetSizeHints() manually, as in your last example, and this works as well and might be more clear (whenever I use an extra sizer I feel the need to leave a comment explaining why it shouldn't be removed).
Unfortunately there is no better way and I am not sure if we can even add one because you need to do something with all of the panel, the sizer and the frame and this means that you can't do it with a single method call without passing unrelated parameters to it. I.e. we could have something like
panel.SetSizerAndFitParent(sizer, frame);
but it's not really clear whether this would be better.
What about introducing a sizer that manages the frame content (e.g. the panel)? Since you didn't include a minimal example, I haven't tested it yet.
frameSizer = wx.BoxSizer(wx.VERTICAL)
frameSizer.Add(panel)
frm.SetSizerAndFit(frameSizer)
I am having a problem with wxPython. I am attempting to have a scrollable window without a visible scroll bar. I still want to be able to use the mouse wheel to scroll as well as use the keyboard shortcuts that I have written.
I have the following simplified code:
import wx
import wx.stc
app = wx.App(0)
frame = wx.Frame(None, wx.ID_ANY, "Sample Scroll pane")
textViewer = wx.stc.StyledTextCtrl(frame, wx.ID_ANY)
textViewer.Text = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22"
textViewer.SetUseVerticalScrollBar(False)
textViewer.ScrollLines(1)
frame.Show()
app.MainLoop()
I am using the "ScrollLines" function to scroll my text programatically. On a windows machine this works as expected and scrolls down one line. However, on Ubuntu, the text does not scroll if the "SetUseVerticalScrollBar" is false.
How can I hide my scrollbar while maintaining it's functionality in a cross platform manner?
ScrollToLine seems to work consistently on Windows and Linux, so you could replace the ScrollLines call with something like this:
first = textViewer.GetFirstVisibleLine()
textViewer.ScrollToLine(first + n)
where n is the number of lines to scroll down.