0

I have been working on Python 3.8 and wxPython 4 (Phoenix) on GNU/Linux for a number of days and I am making very little progress. I need a very simple GUI, with a scrolled canvas taking the majority of a full-screen window and a scrolled panel holding about 4 lines of text below that. I want some margin around the canvas and panel. I would like to be able to the positioning automatically (and not absolutely). Problems I am encountering are 1) the scroll bars are not appearing, 2) I am using absolute positioning and I am not really sure the sizer I place is even functioning.

I have been hacking around, trying all sorts of variations. I have read over the API documentation for all calls I use. I have looked at demos and samples. I have looked at every book I can find on O'Reilly. I still feel like I am quite a bit in the dark on understanding the architecture of wxPython. I have developed many other GUI apps in Python in TkInter and Qt, and in other languages. So, I'm feeling pretty dense here.

Here is what the current app looks like:

current app appearance

And here is my current code:

#!/usr/bin/env python3.8 import wx class MainWindow(wx.Frame): def __init__(self, title): screen_x = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X) screen_y = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y) size_value = wx.Size(screen_x, screen_y) wx.Frame.__init__(self, None, title=title, size=size_value) # why does this not work? # super(MainWindow, self).__init__(self, None, title=title, # size=size_value) canvas1 = wx.ScrolledCanvas(self, size=wx.Size(screen_x-30, 300), pos=wx.Point(15, 15)) canvas1.SetBackgroundColour('#cc20cc') canvas1.AlwaysShowScrollbars(True, True) canvas1.SetAutoLayout(1) canvas1.SetScrollbar(wx.VERTICAL, 0, 10, 100) canvas1.SetScrollbar(wx.HORIZONTAL, 0, 10, 100) canvas1.SetScrollRate(1, 1) # with open('/home/kbuchs/.emacs') as fp: # txt_value = fp.read() # txt = wx.StaticText(canvas1, label=txt_value) canvas2 = wx.ScrolledCanvas(self, size=wx.Size(screen_x-30, 1000), pos=wx.Point(15, 315)) canvas2.SetBackgroundColour('#d0d020') canvas2.AlwaysShowScrollbars(True, True) canvas2.SetAutoLayout(1) canvas2.SetScrollRate(1, 1) with open('/home/kbuchs/.bashrc') as fp: txt_value2 = fp.read() txt2 = wx.StaticText(canvas2, label=txt_value2) sizer = wx.BoxSizer(wx.VERTICAL) self.sizer = sizer sizer.Add(canvas1, wx.ID_ANY, wx.ALL, 20) sizer.Add(canvas2, wx.ID_ANY, wx.ALL, 40) self.Show() app = wx.App() MainWindow('Git Branch History') app.MainLoop() 

Update 6/3 10:30 PM CDT. Here is my latest revision-attempt at the code after the example by Rolf of Saxony. It appears the two txt sections (if uncommented) are not getting written into the canvas/panels, but both are overlapping at the top of the frame. Also, still no scrolling.

#!/usr/bin/env python3.8 import wx import wx.lib.scrolledpanel as sp class MainWindow(wx.Frame): def __init__(self, title): screen_x = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X) screen_y = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y) size_value = wx.Size(screen_x, screen_y) super(MainWindow, self).__init__(None, title=title, size=size_value) # canvas1 = wx.ScrolledCanvas(self, id=-1, canvas1 = sp.ScrolledPanel(self, id=-1, size=wx.Size(screen_x, screen_y-200)) # pos=wx.Point(15, 15)) canvas1.SetBackgroundColour('#ccffff') canvas1.AlwaysShowScrollbars(True, True) canvas1.SetAutoLayout(1) canvas1.SetupScrolling() with open('/home/kbuchs/.emacs') as fp: txt_value1 = fp.read() long_line = 900*'-' + '\n' # txt1 = wx.StaticText(canvas1, label=long_line+txt_value1) # txt1.SetBackgroundColour('#eeffff') # txt1Sizer = wx.BoxSizer(wx.VERTICAL) # txt1Sizer.Add(txt1, proportion=0, border=5) canvas1Sizer = wx.BoxSizer(wx.VERTICAL) canvas1Sizer.Add(canvas1, proportion=0, flag=wx.CENTER|wx.ALL|wx.EXPAND, border=5) # canvas1Sizer.Add(txt1Sizer, proportion=0) # canvas1Sizer.Add(txt1, proportion=0, flag=wx.ALL, border=5) # canvas2 = wx.ScrolledCanvas(self, id=-1, canvas2 = sp.ScrolledPanel(self, id=-1, size=wx.Size(screen_x, 200)) # pos=wx.Point(15, 315)) canvas2.SetBackgroundColour('#ffffcc') canvas2.AlwaysShowScrollbars(True, True) canvas2.SetAutoLayout(1) canvas2.SetupScrolling() with open('/home/kbuchs/.bashrc') as fp: txt_value2 = fp.read() # txt2 = wx.StaticText(canvas2, label=long_line+txt_value2) # txt2.SetBackgroundColour('#ffffee') canvas2Sizer = wx.BoxSizer(wx.VERTICAL) canvas2Sizer.Add(canvas2, proportion=0, flag=wx.CENTER|wx.ALL|wx.EXPAND, border=5) # canvas2Sizer.Add(txt2, proportion=0, flag=wx.CENTER|wx.ALL, border=20) sizer = wx.BoxSizer(wx.VERTICAL) self.sizer = sizer sizer.Add(canvas1Sizer, proportion=0, flag=wx.CENTER|wx.ALL|wx.EXPAND, border=5) sizer.Add(canvas2Sizer, proportion=0, flag=wx.CENTER|wx.ALL|wx.EXPAND, border=5) self.Show() app = wx.App() MainWindow('Git Branch History') app.MainLoop() 
3
  • I haven't got time now but you need to assign the sizer i.e. self.SetSizer(sizer) before the Show. Direct positioning with a sizer may give an odd appearence. Sizers can drive you nuts at the beginning ;) Commented Jun 3, 2020 at 11:33
  • Hmm? The sizer stuff was all before the show. Commented Jun 3, 2020 at 16:45
  • Yes it was but you omitted SetSizer, which was my point! Commented Jun 3, 2020 at 16:53

2 Answers 2

1

I'll take another stab at this, as you amended the question but did't make a comment, so I wasn't aware of it.
You seem to have a blindspot for SetSizer, mentioned twice in comments and used in my first answer.
It's like packing your suitcase and then going on holiday with your rucksack.

Here is is your second code example, amended.

import wx import wx.lib.scrolledpanel as sp class MainWindow(wx.Frame): def __init__(self, title): screen_x = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X) screen_y = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y) size_value = wx.Size(screen_x, screen_y) super(MainWindow, self).__init__(None, title=title, size=size_value) canvas1 = sp.ScrolledPanel(self, id=-1,) canvas1.SetBackgroundColour('#ccffff') canvas1.SetupScrolling(scroll_x=True, scroll_y=True, rate_x=20, rate_y=20, scrollToTop=True, scrollIntoView=True) canvas1.AlwaysShowScrollbars(True, True) with open('tips.txt') as fp: txt_value1 = fp.read() long_line = 600*'y' + 'X\n' txt1 = wx.StaticText(canvas1, label=long_line+txt_value1) txt1.SetBackgroundColour('#eeffff') canvas1Sizer = wx.BoxSizer(wx.VERTICAL) canvas1Sizer.Add(txt1, proportion=0, flag=wx.ALL|wx.EXPAND, border=5) canvas2 = sp.ScrolledPanel(self, id=-1) canvas2.SetBackgroundColour('#ffffcc') canvas2.SetupScrolling(scroll_x=True, scroll_y=True, rate_x=20, rate_y=20, scrollToTop=True, scrollIntoView=True) canvas2.AlwaysShowScrollbars(True, True) with open('tips.txt') as fp: txt_value2 = fp.read() txt2 = wx.StaticText(canvas2, label=long_line+txt_value2) txt2.SetBackgroundColour('#ffffee') canvas2Sizer = wx.BoxSizer(wx.VERTICAL) canvas2Sizer.Add(txt2, proportion=0, flag=wx.ALL|wx.EXPAND, border=20) canvas1.SetSizer(canvas1Sizer) canvas2.SetSizer(canvas2Sizer) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(canvas1, proportion=1, flag=wx.ALL|wx.EXPAND, border=5) sizer.Add(canvas2, proportion=1, flag=wx.ALL|wx.EXPAND, border=5) self.SetSizer(sizer) self.Show() app = wx.App() MainWindow('Git Branch History') app.MainLoop() 

enter image description here

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, Rolf. I was thinking you were referring to setting the sizer for the MainWindow, wx.Frame. For that, I had self.sizer = sizer, which I understand is exactly what self.SetSizer does. I see that I got myself confused with the separate sizers required for each canvas, because I actually added those sizers to the wx.Frame. But I see that I should have added the canvases to the frame and set the sizer for each canvas. I guess I had a mental image problem, thinking of a sizer as containing the things which it sizes (like Tk).
It is interesting how there is only one thing in each of those canvas sizers, the StaticText. Are those sizers even necessary under that case?
Answering my own question - yes those sizers are necessary.
0

I'm going to throw your canvas away and replace it with TextCtrl, you could use whatever fits your requirements.
Hopefully, this will point you in the right direction, it has enough in there to show the way.

import wx class MainWindow(wx.Frame): def __init__(self, parent, title): screen_x = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X) screen_y = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y) size_value = wx.Size(screen_x, screen_y) super(MainWindow, self).__init__(parent, title=title, size=size_value) #Define widgets tc1 = wx.TextCtrl(self, size=wx.Size(screen_x-30, 200), style= wx.TE_MULTILINE|wx.TE_PROCESS_ENTER|wx.TE_DONTWRAP|wx.TE_AUTO_URL) tc1.SetBackgroundColour('#cc2000') # Some Control buttons self.b1 = wx.Button(self, -1, "Button 1") self.b2 = wx.Button(self, -1, "Button 2") self.b3 = wx.Button(self, -1, "Quit") tc2 = wx.TextCtrl(self, size=wx.Size(screen_x-30, 1000), style= wx.TE_MULTILINE|wx.TE_PROCESS_ENTER|wx.TE_DONTWRAP) tc2.SetBackgroundColour('#d0d020') #Bind events to functions self.b3.Bind(wx.EVT_BUTTON, self.OnQuit) #Load initial data try: with open('tips.txt') as fp: txt_value2 = fp.read() except: txt_value2 = "tips.txt file not found" txt_value2 = txt_value2 * 20 tc1.AppendText("No data yet\n") tc1.AppendText("www.nodatayet.com\n") tc1.AppendText(" "*20) tc1.AppendText("X\n") tc2.write(txt_value2) #Define sizers sizer = wx.BoxSizer(wx.VERTICAL) button_sizer = wx.BoxSizer(wx.HORIZONTAL) #Populate sizers button_sizer.Add(self.b1) button_sizer.Add(self.b2) button_sizer.Add(self.b3) sizer.Add(tc1, proportion=0, flag=wx.ALL, border=20) sizer.Add(button_sizer, proportion=0, flag=wx.LEFT, border=40) sizer.Add(tc2, proportion=1, flag=wx.ALL, border=40) self.SetSizer(sizer) self.Show() def OnQuit(self, event): self.Destroy() app = wx.App() MainWindow(None,'Git Branch History') app.MainLoop() 

enter image description here

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.