overflow text in label - python

I have this code
import wx, time
def GetRoundBitmap( w, h, r ):
maskColor = wx.Color(0,0,0)
shownColor = wx.Color(5,5,5)
b = wx.EmptyBitmap(w,h)
dc = wx.MemoryDC(b)
dc.SetBrush(wx.Brush(maskColor))
dc.DrawRectangle(0,0,w,h)
dc.SetBrush(wx.Brush(shownColor))
dc.SetPen(wx.Pen(shownColor))
dc.DrawRoundedRectangle(0,0,w,h,r)
dc.SelectObject(wx.NullBitmap)
b.SetMaskColour(maskColor)
return b
def GetRoundShape( w, h, r ):
return wx.RegionFromBitmap( GetRoundBitmap(w,h,r) )
class FancyFrame(wx.Frame):
def __init__(self):
style = ( wx.CLIP_CHILDREN | wx.STAY_ON_TOP | wx.FRAME_NO_TASKBAR |
wx.NO_BORDER | wx.FRAME_SHAPED )
wx.Frame.__init__(self, None, title='Fancy', style = style)
self.SetBackgroundColour(wx.BLACK)
self.SetTransparent( 150 )
self.panel = wx.Panel(self)
self.lblname = wx.StaticText(self.panel, label="Your name aaaa:")
#self.lblname.Wrap(210)
self.lblname.SetForegroundColour((91,91,91)) # set text color
self.sizer = wx.GridBagSizer(500, 500)
self.sizer.Add(self.lblname, (1, 0))
if wx.Platform == '__WXGTK__':
self.Bind(wx.EVT_WINDOW_CREATE, self.SetRoundShape)
else:
self.SetRoundShape()
self.Show(True)
def SetRoundShape(self, event=None):
w, h = self.GetSizeTuple()
w=250
h=50
self.SetShape(GetRoundShape( w,h, 10 ) )
dw, dh = wx.DisplaySize()
#w, h = self.GetSize()
x = dw - w
x = (dw/2) - (w/2)
y = dh - h - 50
self.SetPosition((x, y))
app = wx.App()
f = FancyFrame()
app.MainLoop()
I need to have "Your name aaaa:" aligned to center but I dont know why it is cut. How to solve it?

Your gridbagsizer is a bit out and you aren't setting the sizer.
Try:
self.sizer = wx.GridBagSizer(1,1)
self.sizer.Add(self.lblname,pos=(1,2),flag=wx.ALIGN_CENTER)
and:
self.panel.SetSizer(self.sizer)
self.Show(True)

Related

Refresh a grid with GridTableBase Class

I am trying to dynamically load a wxGrid with a pandas Dataframe depending on what table is selected in the combobox. I can get the grid to load on intialization, but can't figure out how to get refresh the GridTableClass and grid. Right now I am trying to test with a random Dataframe.
class PageOne(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
#wx.StaticText(self, -1, "This is a PageOne object", (20,20))
class PageTwo(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
#wx.StaticText(self, -1, "This is a PageTwo object", (40, 40))
class PageThree(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
#wx.StaticText(self, -1, "This is a PageThree object", (60, 60))
class DataTable(gridlib.GridTableBase):
def __init__(self, data):
gridlib.GridTableBase.__init__(self)
self.data = data
#self.colnames = colnames
#Store the row and col length to see if table has changed in size
self._rows = self.GetNumberRows()
self._cols = self.GetNumberCols()
self.odd=gridlib.GridCellAttr()
self.odd.SetBackgroundColour((217,217,217))
self.even=gridlib.GridCellAttr()
self.even.SetBackgroundColour((255,255,255))
def GetAttr(self, row, col, kind):
attr = [self.even, self.odd][row % 2]
attr.IncRef()
return attr
def GetNumberRows(self):
return len(self.data)
def GetNumberCols(self):
return len(self.data.columns) + 1
def IsEmptyCell(self, row, col):
return False
def GetValue(self, row, col):
#if col == 0:
# return None #self.data.index[row]
return self.data.iloc[row, col-1]
def SetValue(self, row, col, value):
self.data.iloc[row, col - 1] = value
def GetColLabelValue(self, col):
if col == 0:
return None
#pass
#return 'Index' if self.data.index.name is None else self.data.index.name
return self.data.columns[col - 1] #[col-1]
#return None
#---------------------------------------------------------------------------
class DataGrid(gridlib.Grid):
def __init__(self, parent, data): # data
gridlib.Grid.__init__(self, parent, - 1) #,colnames,-1 # data
#data = pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD'))
#data.reset_index(drop=True, inplace=True)
table = DataTable(data)
print ("passed")
# The second parameter means that the grid is to take ownership of the
# table and will destroy it when done. Otherwise you would need to keep
# a reference to it and call it's Destroy method later.
self.SetTable(table, True)
self.Bind(gridlib.EVT_GRID_CELL_RIGHT_CLICK, self.OnCellRightClick)
def OnCellRightClick(self, event):
print ("OnCellRightClick: (%d,%d)\n" % (event.GetRow(), event.GetCol()))
#-------------------------------------------------------------------------------
class MainFrame(wx.Frame):
def __init__(self, parent, data): # (self, parent, data):
wx.Frame.__init__(self, parent, -1, "Varkey Foundation") #, size=(640,480))
#Create a panel
self.p = wx.Panel(self)
self.Maximize(True)
#Create blank dataframe
data = pd.DataFrame() #pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD')
#data = pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD'))
#data.reset_index(drop=True, inplace=True)
self.data = DataTable(data)
self.nb = wx.Notebook(self.p)
self.p.SetBackgroundColour( wx.Colour( 0, 0, 0 ) ) # 38,38,38
self.nb.SetBackgroundColour(wx.Colour(58, 56, 56) )
#self.SetBackgroundColour( wx.Colour( 255, 255, 56 ) )
#create the page windows as children of the notebook
self.page1 = PageOne(self.nb)
self.page2 = PageTwo(self.nb)
self.page3 = PageThree(self.nb)
# add the pages to the notebook with the label to show on the tab
self.nb.AddPage(self.page1, "Data")
self.nb.AddPage(self.page2, "Analyze")
self.nb.AddPage(self.page3, "Change Log")
#Create the grid and continue layout
self.grid = DataGrid(self.page1, data)
#grid.SetReadOnly(5,5, True)
#CreateFonts
self.b_font = wx.Font(14,wx.ROMAN,wx.NORMAL,wx.BOLD, True)
self.lbl_font = wx.Font(14,wx.ROMAN,wx.NORMAL,wx.NORMAL, True)
self.cb_font = wx.Font(11,wx.SCRIPT,wx.ITALIC,wx.NORMAL, True)
self.h_font = wx.Font(18,wx.DECORATIVE,wx.ITALIC,wx.BOLD, True)
#Create Title bmp
ico = wx.Icon('varkey_bmp.bmp', wx.BITMAP_TYPE_ICO) #'varkey_frame.bmp'
self.SetIcon(ico)
#Page 1 sizers and widgets
self.title = wx.StaticText(self.page1,label="TITLE",style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE)
self.title.SetForegroundColour((255,255,255))
self.title.SetFont(self.h_font)
self.p1_sizer = wx.BoxSizer(wx.VERTICAL)
self.p1_sizer.Add(self.title,0,wx.EXPAND,5)
self.p1_sizer.Add(self.grid,3,wx.EXPAND | wx.ALL ,25)
#self.p1_sizer.Add(self.btn_new,-0,wx.ALIGN_CENTER,5)
self.page1.SetSizer(self.p1_sizer)
#Page 2 sizers and widgets
self.analyze_grid = gridlib.Grid(self.page2)
self.analyze_grid.CreateGrid(0, 10)
self.p2_sizer = wx.BoxSizer(wx.VERTICAL)
self.p2_sizer.Add(self.analyze_grid,1,wx.EXPAND)
self.page2.SetSizer(self.p2_sizer)
#Page 3 sizers and widgets
self.log_grid = gridlib.Grid(self.page3)
self.log_grid.CreateGrid(0, 9)
self.log_grid.EnableEditing(False)
self.p3_sizer = wx.BoxSizer(wx.VERTICAL)
self.p3_sizer.Add(self.log_grid,1,wx.EXPAND)
self.page3.SetSizer(self.p3_sizer)
#Create widgets for top sizer
#Insert Image
self.staticbitmap = wx.StaticBitmap(self.p)
self.staticbitmap.SetBitmap(wx.Bitmap('varkey_logo2.jpg'))
self
self.lbl_user = wx.StaticText(self.p,label="Username:")
self.lbl_password = wx.StaticText(self.p,label="Password:")
self.lbl_interaction = wx.StaticText(self.p,label="Interaction:")
self.lbl_table = wx.StaticText(self.p,label="Table:")
#SetForground colors
self.lbl_user.SetForegroundColour((255,255,255))
self.lbl_password.SetForegroundColour((255,255,255))
self.lbl_interaction.SetForegroundColour((255,255,255))
self.lbl_table.SetForegroundColour((255,255,255))
#Set Fonts
self.lbl_user.SetFont(self.lbl_font)
self.lbl_password.SetFont(self.lbl_font)
self.lbl_interaction.SetFont(self.lbl_font)
self.lbl_table.SetFont(self.lbl_font)
self.tc_user =wx.TextCtrl(self.p,value='cmccall95',size = (130,25))
self.tc_password =wx.TextCtrl(self.p,value='Achilles95', style=wx.TE_PASSWORD | wx.TE_PROCESS_ENTER,size = (130,25))
#self.tc_password.Bind(wx.EVT_TEXT_ENTER,self.onLogin)
self.tc_user.SetFont(self.cb_font)
self.tc_password.SetFont(self.cb_font)
self.btn_login = wx.Button(self.p,label="Login", size=(105,30))
self.btn_login.SetBackgroundColour(wx.Colour(198, 89, 17))
self.btn_login.SetFont(self.b_font)
self.btn_login.Bind(wx.EVT_BUTTON, self.onLogin) #connect_mysql
self.btn_logout = wx.Button(self.p,label="Logout",size=(105,30))
self.btn_logout.SetBackgroundColour(wx.Colour(192,0,0))
self.btn_logout.SetFont(self.b_font)
#self.btn_logout.Bind(wx.EVT_BUTTON, self.onLogout)
self.combo_interaction = wx.ComboBox(self.p, size = (160,25),style = wx.CB_READONLY | wx.CB_SORT | wx.CB_SORT)
#self.combo_interaction.Bind(wx.EVT_COMBOBOX, self.onComboInteraction)
self.combo_table = wx.ComboBox(self.p, size = (160,25),style = wx.CB_READONLY | wx.CB_SORT | wx.CB_SORT)
#self.combo_table.Bind(wx.EVT_COMBOBOX, self.onHideCommands)
self.combo_interaction.SetFont(self.cb_font)
self.combo_table.SetFont(self.cb_font)
#self.combo_table.Bind(wx.EVT_COMBOBOX ,self.OnComboTable)
self.btn_load = wx.Button(self.p,label="Load Table", size=(105,30))
self.btn_load.SetBackgroundColour(wx.Colour(31, 216, 6))
self.btn_load.SetFont(self.b_font)
#self.btn_load.Bind(wx.EVT_BUTTON, self.onLoadData)
self.btn_load.Bind(wx.EVT_BUTTON, self.test_return)
self.lc_change = wx.ListCtrl(self.p,-1,style = wx.TE_MULTILINE | wx.LC_REPORT | wx.LC_VRULES)
self.lc_change.InsertColumn(0,"User ID")
self.lc_change.InsertColumn(1,"Status")
self.lc_change.InsertColumn(2,"Description")
self.lc_change.InsertColumn(3,"Date/Time")
#Set column widths
self.lc_change.SetColumnWidth(0, 75)
self.lc_change.SetColumnWidth(1, 75)
self.lc_change.SetColumnWidth(2, 450)
self.lc_change.SetColumnWidth(3, 125)
#Create Filler text
self.lbl_filler = wx.StaticText(self.p,label="",size = (125,20))
#Create FlexGridSizers(For top half)
self.left_fgs = wx.FlexGridSizer(3,4,25,15)
self.left_fgs.AddMany([(self.lbl_user,1,wx.ALIGN_LEFT | wx.LEFT,15),(self.tc_user,1,wx.EXPAND),(self.lbl_interaction,1,wx.ALIGN_RIGHT|wx.RIGHT, 10),(self.combo_interaction,1,wx.EXPAND),
(self.lbl_password,1,wx.ALIGN_LEFT| wx.LEFT,15),(self.tc_password,1,wx.EXPAND),(self.lbl_table,1,wx.ALIGN_RIGHT|wx.RIGHT, 10),(self.combo_table),
(self.btn_login,2,wx.EXPAND),(self.btn_logout,1,wx.EXPAND),(self.lbl_filler,1,wx.EXPAND),(self.btn_load,1)])
#Create Top Sizer
self.top_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.top_sizer.Add(self.left_fgs,proportion = 1, flag = wx.ALL|wx.EXPAND,border = 30)
self.top_sizer.Add(self.staticbitmap,2,wx.TOP | wx.RIGHT, border = 40) #30
self.top_sizer.Add(self.lc_change,2,wx.RIGHT|wx.EXPAND ,30)
#create Bottom Sizer
self.bottom_sizer = wx.BoxSizer(wx.VERTICAL)
self.bottom_sizer.Add(self.nb,proportion = 5, flag = wx.LEFT |wx.RIGHT | wx.EXPAND,border = 30)
self.mainsizer = wx.BoxSizer(wx.VERTICAL)
self.mainsizer.Add(self.top_sizer,proportion = 0, flag = wx.ALL|wx.EXPAND,border = 5)
self.mainsizer.Add(self.bottom_sizer,proportion = 1,flag = wx.ALL|wx.EXPAND,border = 5)
#self.mainsizer.Add(self.status_sizer,proportion =0,flag = wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, border = 15)
self.p.SetSizerAndFit(self.mainsizer)
def test_reload(self, event):
data = pd.DataFrame() #pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD')
data = pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD'))
#data.reset_index(drop=True, inplace=True)
#self.data = DataTable(data)
self.table.data = self.data
self.grid.Refresh()
#Some more functions.......
if __name__ == '__main__':
import sys
app = wx.App()
frame = MainFrame(None, sys.stdout) # (None, sys.stdout)
frame.Show(True)
app.MainLoop()
I've tried many different variations of the function and can't understand how this should work. From my understanding, I should the table and then call the grid to refresh.
def test_reload(self, event):
data = pd.DataFrame() #pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD')
data = pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD'))
self.table.data = self.data
self.grid.Refresh()
I managed to find a solution. Hopefully this helps someone else out.
To reload the grid, I first create new data. Then I destroy the grid, create a new grid, and insert it in place of the old grid. You must then call Layout(). The Freeze() and Thaw() methods are to prevent screen flickering.
def test_reload(self, event):
self.Freeze()
#Create new data
data = pd.DataFrame(np.random.randint(0,100,size=(40000, 5)),columns=list('EFGHD'))
#Destroy and create grid with new data assigned
self.grid.Destroy()
self.grid = DataGrid(self.page1, data)
#Insert grid into existing sizer
self.p1_sizer.Insert(1,self.grid,1,wx.RIGHT| wx.LEFT|wx.EXPAND, 20)
self.p1_sizer.Layout()
self.Thaw()
I'm sure there is a better method out there, but this works and is instant.

How do I make my wxPython scrolledPanel scroll to the bottom of the window?

Problem: I want to be able to force the scrollbar to the bottom when I call createNewRow(). I can see that the self.Scroll(0, self.scrollRange) is occurring in OnKeyTyped() and the scrollbar moves to the bottom of the window but then the scrollbar moves to the top of the window again. I tried to stop this by binding wx.EVT_SCROLLWIN to OnScroll which calls event.Skip() but it appears that this has not worked. I am out of ideas on how to proceed as I don't know enough about eventHandlers and scroll events in wxPython. Any help on how to proceed would be much appreciated. Full code below.
import os
import wx
import datetime as dt
import wx.lib.scrolledpanel as scrolled
class MyFrame(wx.Frame):
width = 1000
height = 600
today = dt.date.today()
today_date = f"{today:%A - %d %B %Y}"
filename = f"Worklog {today_date}"
wxTHICK_LINE_BORDER = 3
def __init__(self, parent=None, title=filename, size=(width,height - 1)):
wx.Frame.__init__(self, parent=parent, title=title, size=size)
self.parent = parent
self.title = title
self.size = size
self.BuildMenuBar()
def BuildMenuBar(self):
# Menu bar
self.menuBar = wx.MenuBar()
self.fileMenu = wx.Menu()
self.NewOpt = wx.MenuItem(self.fileMenu, wx.ID_NEW, '&New\tCtrl+N')
self.OpenOpt = wx.MenuItem(self.fileMenu, wx.ID_OPEN, '&Open\tCtrl+O')
self.SaveOpt = wx.MenuItem(self.fileMenu, wx.ID_SAVE, '&Save\tCtrl+S')
self.QuitOpt = wx.MenuItem(self.fileMenu, wx.ID_EXIT, '&Quit\tCtrl+Q')
self.fileMenu.Append(self.NewOpt)
self.fileMenu.Append(self.OpenOpt)
self.fileMenu.Append(self.SaveOpt)
self.fileMenu.Append(self.QuitOpt)
self.Bind(wx.EVT_MENU, self.OnQuit, self.QuitOpt)
self.menuBar.Append(self.fileMenu, '&File')
self.SetMenuBar(self.menuBar)
def OnQuit(self, e):
self.Close()
class MyPanel(wx.Panel):
def __init__(self,parent):
wx.Panel.__init__(self, parent=parent)
self.parent = parent
self.size = parent.size
panel_colour = wx.Colour(240, 240, 240, 255)
self.SetBackgroundColour(panel_colour)
self.Refresh()
class MyScrolledPanel(scrolled.ScrolledPanel):
def __init__(self, parent):
scrolled.ScrolledPanel.__init__(self, parent=parent, style = wx.TAB_TRAVERSAL | wx.TB_BOTTOM)
self.parent = parent
# self.size = parent.size
self.width = parent.size[0]
self.height = parent.size[1]
scrollpanel_colour = wx.Colour(255, 255, 255, 255)
self.SetBackgroundColour(scrollpanel_colour)
# Call a refresh to update the UI
self.Refresh()
self.SetAutoLayout(True)
self.SetupScrolling()
self.InitUI()
self.Bind(wx.EVT_SCROLLWIN, self.OnScroll, self)
self.Bind(wx.EVT_SIZE, self.OnSize, self)
def OnScroll(self, e):
e.Skip()
def InitUI(self):
vgap = 0
hgap = 0
self.rowList = []
self.n = 0
self.scrollSizer = wx.GridBagSizer(vgap + 10, hgap + 10)
self.row = self.CreateNewRow(self.n)
self.rowList.append(self.row)
print(f"Row List: {self.rowList[-1]}")
self.scrollSizer.Add(self.row[0], pos = (self.i, 0), flag = wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, border = 10)
self.scrollSizer.Add(self.row[1], pos = (self.i, 1), flag = wx.EXPAND | wx.TOP | wx.RIGHT | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL , border = 10)
self.scrollSizer.AddGrowableCol(1)
self.SetSizer(self.scrollSizer)
self.panelSizer = wx.GridBagSizer(vgap, hgap)
self.panelSizer.AddGrowableRow(0)
self.panelSizer.AddGrowableCol(0)
self.panelSizer.Add(self, pos = (0, 0), flag = wx.EXPAND, border = 0) # Add wx.Window not wx.Sizer
self.parent.SetSizer(self.panelSizer)
def CreateNewRow(self, number):
self.i = number
self.txtStr = "%02d" % (self.i+1) + ". "
self.staticText = wx.StaticText(self, wx.ID_ANY, self.txtStr)
#pos = (x, y)
#self.staticText.SetForegroundColour(wx.Colour(0,0,0))
self.control = wx.TextCtrl(self, self.i)
self.control.SetMaxLength(256)
self.text_history_length = 0
self.control.Bind(wx.EVT_TEXT, self.OnKeyTyped, id = self.i)
#self.control = wx.TextCtrl(self, -1, pos = (x + w + 5,y) )
#style = wx.TE_MULTILINE
elems = [self.staticText, self.control]
return elems
def OnSize(self, e):
self.width, self.height = e.GetSize()
self.SetSize((self.width, self.height))
self.OnSizeChange()
self.Refresh()
def OnSizeChange(self):
# Fit child elements
self.scrollSizer.FitInside(self)
# Resize layout
self.Layout()
# Resize scrolling
self.SetupScrolling()
def OnKeyTyped(self, e):
self.text_length = len(e.GetString())
if (self.text_history_length == 1 and self.text_length == 0):
print(f"History length: {self.text_history_length}")
print(f"Text length: {self.text_length}")
self.text_history_length = self.text_length
pass
elif (self.text_history_length == 0 and self.text_length == 1):
print(f"History length: {self.text_history_length}")
print(f"Text length: {self.text_length}")
self.n += 1
self.row = self.CreateNewRow(self.n)
print(f"Action: {self.row}")
print(f"Row List: {self.rowList[-1]}")
self.rowList.append(self.row)
self.scrollSizer.Add(self.row[0], pos = (self.n, 0), flag = wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, border = 10)
self.scrollSizer.Add(self.row[1], pos = (self.n, 1), flag = wx.EXPAND | wx.TOP | wx.RIGHT | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL , border = 10)
self.SetupScrolling()
self.text_history_length = self.text_length
self.rowList[self.n-1][1].Bind(wx.EVT_TEXT, None, id = self.n-1)
self.text_history_length = 0
else:
print(f"History length: {self.text_history_length}")
print(f"Text length: {self.text_length}")
self.text_history_length = self.text_length
self.rowList[-1][1].SetFocus()
self.scrolledPanelChild = self.GetChildren()[-1] # [ scrollPanel ]
self.ScrollChildIntoView(self.scrolledPanelChild)
self.OnSizeChange()
self.scrollRange = self.GetScrollRange(wx.VERTICAL)
print(f"ScrollRange: {self.scrollRange}")
#self.scrollUnits = self.GetScrollPixelsPerUnit()
#print(f"ScrollUnit: {self.scrollUnits}")
#self.scrollThumb = self.GetScrollThumb(wx.VERTICAL)
#print(f"ScrollThumb: {self.scrollThumb}")
self.Scroll(0, self.scrollRange)
def main():
app = wx.App(False)
app.locale = wx.Locale(wx.Locale.GetSystemLanguage())
frame = MyFrame()
panel = MyPanel(frame)
scrolledPanel = MyScrolledPanel(panel)
frame.Show(True)
app.MainLoop()
if __name__ == "__main__":
main()
In :
def OnSizeChange(self):
# Fit child elements
self.scrollSizer.FitInside(self)
# Resize layout
self.Layout()
# Resize scrolling
self.SetupScrolling()
the SetupScrolling() event causes the scrollbar to reset to the top of the page. So if you comment this the Scroll(0, self.scrollRange) will scroll the scrollbar to the bottom of the page. Improvement would be to get this call to happen after SetupScrolling so that it happens anyway. Maybe the call to SetupScrolling is not necessary in anycase and Layout() is enough.
Old question but still. This can be solved using:
wx.CallAfter(self._scrolled_panel.ScrollChildIntoView, new_text) Or calling any of the other scroll methods from the CallAfter.
or
SetupScrolling(scrollIntoView=True, scrollToTop=False)

WxPython's ScrolledWindow element collapses to minimum size

I am using a Panel within a Frame to display images (the GUI need to switch between multiple panels and hence the hierarchy). As images should be displayed in native size I used ScrolledWindow as the panel parent. The scrolls do appear and work, but it causes the Panel to collapse to minimum size and it needs to be resized using drag&drop every time.
Is there a way around this?
Below is a reduced version of the code, which shows the problem:
import os
import wx
from wx.lib.pubsub import pub
class Edit_Panel(wx.PyScrolledWindow):
def __init__(self, parent):
super(Edit_Panel, self).__init__(parent)
# Display size
width, height = wx.DisplaySize()
self.photoMaxSize = height - 500
# Loaded image
self.loaded_image = None
# Icons
self.open_icon_id = 500
# Generate panel
self.layout()
def layout(self):
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
divider = wx.StaticLine(self, -1, style = wx.LI_HORIZONTAL)
self.main_sizer.Add(divider, 0, wx.ALL | wx.EXPAND)
self.toolbar = self.init_toolbar()
self.main_sizer.Add(self.toolbar, 0, wx.ALL)
img = wx.EmptyImage(self.photoMaxSize, self.photoMaxSize)
self.image_control = wx.StaticBitmap(self, wx.ID_ANY,
wx.BitmapFromImage(img))
self.main_sizer.Add(self.image_control, 0, wx.ALL | wx.CENTER, 5)
self.image_label = wx.StaticText(self, -1, style = wx.ALIGN_CENTRE)
self.main_sizer.Add(self.image_label, 0, wx.ALL | wx.ALIGN_CENTRE, 5)
self.SetSizer(self.main_sizer)
fontsz = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT).GetPixelSize()
self.SetScrollRate(fontsz.x, fontsz.y)
self.EnableScrolling(True, True)
def init_toolbar(self):
toolbar = wx.ToolBar(self)
toolbar.SetToolBitmapSize((16, 16))
open_ico = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, (16, 16))
open_tool = toolbar.AddSimpleTool(self.open_icon_id, open_ico, "Open", "Open an Image Directory")
handler = self.on_open_reference
self.Bind(event = wx.EVT_MENU, handler = handler, source = open_tool)
toolbar.Realize()
return toolbar
def on_open_reference(self, event, wildcard = None):
if wildcard is None:
wildcard = self.get_wildcard()
defaultDir = '~/'
dbox = wx.FileDialog(self, "Choose an image to display", defaultDir = defaultDir, wildcard = wildcard, style = wx.OPEN)
if dbox.ShowModal() == wx.ID_OK:
file_name = dbox.GetPath()
# load image
self.load_image(image = file_name)
dbox.Destroy()
def get_wildcard(self):
wildcard = 'Image files (*.jpg;*.png;*.bmp)|*.png;*.bmp;*.jpg;*.jpeg'
return wildcard
def load_image(self, image):
self.loaded_image = image
# Load image
img = wx.Image(image, wx.BITMAP_TYPE_ANY)
# Label image name
image_name = os.path.basename(image)
self.image_label.SetLabel(image_name)
# scale the image, preserving the aspect ratio
scale_image = True
if scale_image:
W = img.GetWidth()
H = img.GetHeight()
if W > H:
NewW = self.photoMaxSize
NewH = self.photoMaxSize * H / W
else:
NewH = self.photoMaxSize
NewW = self.photoMaxSize * W / H
img = img.Scale(NewW, NewH)
self.image_control.SetBitmap(wx.BitmapFromImage(img))
# Render
self.main_sizer.Layout()
self.main_sizer.Fit(self)
self.Refresh()
pub.sendMessage("resize", msg = "")
class Viewer_Frame(wx.Frame):
def __init__(self, parent, id, title):
super(Viewer_Frame, self).__init__(parent = parent, id = id, title = title)
# Edit panel
self.edit_panel = Edit_Panel(self)
# Default panel
self.main_panel = self.edit_panel
# Render frame
self.render_frame()
# Subscription to re-render
pub.subscribe(self.resize_frame, ("resize"))
def render_frame(self):
# Main Sizer
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
# Add default sizer
self.main_sizer.Add(self.main_panel, 1, wx.EXPAND)
# Render
self.SetSizer(self.main_sizer)
self.Show()
self.main_sizer.Fit(self)
self.Center()
def resize_frame(self, msg):
self.main_sizer.Fit(self)
if __name__ == "__main__":
app = wx.App(False)
frame = Viewer_Frame(parent = None, id = -1, title = 'Toolkit')
app.MainLoop()
You're calling Fit(), so you're explicitly asking the panel to fit its contents, but you don't specify the min/best size of this contents anywhere (AFAICS, there is a lot of code here, so I could be missing something).
If you want to use some minimal size for the panel, just set it using SetMinSize().

Modifying minimal width of left tab style of wx Python's agw LabelBook?

I'm trying to use wx Python's AGW LabelBook (using wxPython 2.8.11.0, Python 2.7.1+, Ubuntu 11.04), such that the tabs (list) are left-aligned; here I have some short texts, and I expected the tablist area would have its width shortened accordingly; but instead I get this:
At that mouse position, I get a sizer pointer - and I can drag it to the right to increase the width of the tablist area as much as I want; but I cannot drag it any further to the left, to make the width shorter. I also tried to use INB_FIT_LABELTEXT, but it doesn't seem to change anything...
Is it possible to somehow instruct LabelBook to set the minimal width of the left tablist area to the approx width of text (say, indicated at the drawn red line)?
This is the code I used to generate the screenshot:
import wx
import wx.lib.agw
import wx.lib.agw.labelbook as LB
from wx.lib.agw.fmresources import *
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "Labelbook test")
self.tlbook = LB.LabelBook(self, -1, size=(400, 200), style = wx.NB_LEFT, agwStyle = INB_LEFT | INB_FIT_LABELTEXT | INB_FIT_BUTTON | INB_SHOW_ONLY_TEXT | INB_USE_PIN_BUTTON)
sizer_1 = wx.BoxSizer(wx.VERTICAL)
self.tlbook_panel_1 = wx.Panel(self.tlbook)
self.tlbook_panel_2 = wx.Panel(self.tlbook)
self.tlbook.AddPage(self.tlbook_panel_1, "Test 1")
self.tlbook.AddPage(self.tlbook_panel_2, "Test 2")
sizer_1.Add(self.tlbook, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
sizer_1.Fit(self)
self.SetSize((450, 250))
self.Layout()
app = wx.App(0)
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()
Ok, I think I got it:
... and the thing is, that the width of the tab area is hardcoded in the source for LabelBook as 100 pixels, but not all in the same class - so some monkeypatching is required, if one wants to leave the source in tact. Here is the code:
import wx
import wx.lib.agw
import wx.lib.agw.labelbook as LB
#~ from wx.lib.agw.labelbook import * # for INB_BOLD_TAB_SELECTION = 16384? nope
INB_BOLD_TAB_SELECTION = 16384
from wx.lib.agw.fmresources import *
WIDTHLIMITPIX=20
class OLabelContainer(LB.LabelContainer): # overloaded version
def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, agwStyle=0, name="LabelContainer"):
super(OLabelContainer, self).__init__(parent, id, pos, size, style, agwStyle, name)
def Resize(self, event): # copy from wx/lib/agw/labelbook.py
# Resize our size
self._tabAreaSize = self.GetSize()
newWidth = self._tabAreaSize.x
x = event.GetX()
if self.HasAGWFlag(INB_BOTTOM) or self.HasAGWFlag(INB_RIGHT):
newWidth -= event.GetX()
else:
newWidth = x
# hack: was 100 here
if newWidth < WIDTHLIMITPIX: #100: # Dont allow width to be lower than that
newWidth = WIDTHLIMITPIX #100
self.SetSizeHints(newWidth, self._tabAreaSize.y)
# Update the tab new area width
self._nTabAreaWidth = newWidth
self.GetParent().Freeze()
self.GetParent().GetSizer().Layout()
self.GetParent().Thaw()
LB.LabelContainer = OLabelContainer # do monkeypatch old class
class MyLabelBook(LB.LabelBook):
def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, agwStyle=0, name="LabelBook"):
super(MyLabelBook, self).__init__(parent, id, pos, size, style, agwStyle, name)
self._fontSizeMultiple = 1.0
self._fontBold = False
print(self._pages) # is OLabelContainer, OK
def GetFontBold(self): # copy from wx/lib/agw/labelbook.py
return self._fontBold
def ResizeTabArea(self): # copy from wx/lib/agw/labelbook.py
agwStyle = self.GetAGWWindowStyleFlag()
if agwStyle & INB_FIT_LABELTEXT == 0:
return
if agwStyle & INB_LEFT or agwStyle & INB_RIGHT:
dc = wx.MemoryDC()
dc.SelectObject(wx.EmptyBitmap(1, 1))
font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
font.SetPointSize(font.GetPointSize()*self._fontSizeMultiple)
if self.GetFontBold() or agwStyle & INB_BOLD_TAB_SELECTION:
font.SetWeight(wx.FONTWEIGHT_BOLD)
dc.SetFont(font)
maxW = 0
for page in xrange(self.GetPageCount()):
caption = self._pages.GetPageText(page)
w, h = dc.GetTextExtent(caption)
maxW = max(maxW, w)
maxW += 24 #TODO this is 6*4 6 is nPadding from drawlabel
if not agwStyle & INB_SHOW_ONLY_TEXT:
maxW += self._pages._nImgSize * 2
maxW = max(maxW, WIDTHLIMITPIX) # hack: was 100 here
self._pages.SetSizeHints(maxW, -1)
self._pages._nTabAreaWidth = maxW
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "Labelbook test")
self.tlbook = MyLabelBook(self, -1, size=(400, 200), style = wx.NB_LEFT, agwStyle = INB_LEFT | INB_FIT_LABELTEXT | INB_FIT_BUTTON | INB_SHOW_ONLY_TEXT | INB_USE_PIN_BUTTON)
sizer_1 = wx.BoxSizer(wx.VERTICAL)
self.tlbook_panel_1 = wx.Panel(self.tlbook)
self.tlbook_panel_2 = wx.Panel(self.tlbook)
self.tlbook.AddPage(self.tlbook_panel_1, "Test 1")
self.tlbook.AddPage(self.tlbook_panel_2, "Test 2")
sizer_1.Add(self.tlbook, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
sizer_1.Fit(self)
self.SetSize((450, 250))
self.Layout()
app = wx.App(0)
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()

wxPython Geometry problem

I'm trying to get the button to be right of the label. I set the tuple and am still not sure why it covers the label.
Also is there a good tutorial available on wxpython geometry?
import wx
import wx.lib.agw.gradientbutton as GB
def GetRoundBitmap( w, h, r ):
maskColor = wx.Color(0,0,0)
shownColor = wx.Color(5,5,5)
b = wx.EmptyBitmap(w,h)
dc = wx.MemoryDC(b)
dc.SetBrush(wx.Brush(maskColor))
dc.DrawRectangle(0,0,w,h)
dc.SetBrush(wx.Brush(shownColor))
dc.SetPen(wx.Pen(shownColor))
dc.DrawRoundedRectangle(0,0,w,h,r)
dc.SelectObject(wx.NullBitmap)
b.SetMaskColour(maskColor)
return b
def GetRoundShape( w, h, r ):
return wx.RegionFromBitmap( GetRoundBitmap(w,h,r) )
class FancyFrame(wx.Frame):
def __init__(self):
style = ( wx.CLIP_CHILDREN | wx.STAY_ON_TOP | wx.FRAME_NO_TASKBAR |
wx.NO_BORDER | wx.FRAME_SHAPED )
wx.Frame.__init__(self, None, title='Fancy', style = style)
self.SetSize( (250, 40) )
self.SetPosition( (500,500) )
self.SetTransparent( 160 )
self.Bind(wx.EVT_KEY_UP, self.On_Esc)
self.Bind(wx.EVT_MOTION, self.OnMouse)
self.Bind(wx.EVT_PAINT, self.OnPaint)
if wx.Platform == '__WXGTK__':
self.Bind(wx.EVT_WINDOW_CREATE, self.SetRoundShape)
else:
self.SetRoundShape()
self.Show(True)
geo = wx.GridBagSizer()
self.label = wx.StaticText(self,-1,label=u'Hello !')
self.label.SetBackgroundColour("#000000")
self.label.SetForegroundColour(wx.WHITE)
self.label.SetSize( (50, 10) )
geo.Add(self.label, (0,0))
self.button = GB.GradientButton(self,label="button")
self.label.SetBackgroundColour("#9e9e9e")
geo.Add(self.button, (0,1))
def SetRoundShape(self, event=None):
w, h = self.GetSizeTuple()
self.SetShape(GetRoundShape( w,h, 10 ) )
def OnPaint(self, event):
dc = wx.PaintDC(self)
dc = wx.GCDC(dc)
w, h = self.GetSizeTuple()
r = 10
dc.SetPen( wx.Pen("#000000", width = 4 ) )
dc.SetBrush( wx.Brush("#9e9e9e") )
dc.DrawRoundedRectangle( 0,0,w,h,r )
def On_Esc(self, event):
"""quit if user press Esc"""
if event.GetKeyCode() == 27 : #27 is Esc
self.Close(force=True)
else:
event.Skip()
def OnMouse(self, event):
"""implement dragging"""
if not event.Dragging():
self._dragPos = None
return
self.CaptureMouse()
if not self._dragPos:
self._dragPos = event.GetPosition()
else:
pos = event.GetPosition()
displacement = self._dragPos - pos
self.SetPosition( self.GetPosition() - displacement )
app = wx.App()
f = FancyFrame()
app.MainLoop()
You forgot to set FancyFrame to have the given layout sizer.
In other words you need to add one line to the end of your FancyFrame's __init__ method.
self.SetSizerAndFit(geo)

Categories

Resources