Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I align the text in a StatusBar to the right in wxPython?

I want to achieve a status bar with 2 fields. The first one left-aligned and the second one right-aligned. Illustration of what I want:

|                                                                               |
|                                                                               |
=================================================================================
| Some status text.                                                   v. 1.0.32 |

My current code:

self.CreateStatusBar(2)
self.SetStatusWidths([-1, -1])

But the right field is left aligned, so it looks like this:

|                                                                               |
|                                                                               |
=================================================================================
| Some status text.                      v. 1.0.32                              |

Is there any way to get text in the right field to align to the right?

like image 830
Hubro Avatar asked Nov 03 '12 15:11

Hubro


2 Answers

Ok, I've solved the problem (even though it feels like a hack.) I created a custom toolbar that defines two fields. The left field can be controlled like normal, and the right field contains a StaticText control, containing the version number, that is manually positioned. The code for positioning the text is platform specific since it looked a tad different on windows. Here are some screenshots:

Windows 7:

Windows 7

OSX 10.8.1 Mountain Lion:

OSX

Here is the code for the custom status bar:

class CustomStatusBar(wx.StatusBar):
    """A custom status bar for displaying the application version in the bottom
    right corner."""
    def __init__(self, parent):
        wx.StatusBar.__init__(self, parent, -1)

        self.SetFieldsCount(2)
        self.SetStatusWidths([-1, -1])

        # Set up the version label.
        self.version_label = wx.StaticText(self, -1, 'Version: ' + VERSION)
        self.reposition_version_label()

        # Listen to the resize event.
        self.Bind(wx.EVT_SIZE, self.on_resize)

    def on_resize(self, event):
        self.reposition_version_label()

    def reposition_version_label(self):
        # Get the rect of the second field.
        field_rect = self.GetFieldRect(1)
        label_rect = self.version_label.GetRect()

        # Reduce the width of the field rect to the width of the label rect and
        # increase it's x value by the same about. This will result in it being
        # right aligned.
        width_diff = field_rect.width - label_rect.width

        field_rect.width = label_rect.width
        field_rect.x += width_diff

        # On windows, the text is a little too high up, so increase the Y value
        # a little.
        if sys.platform == 'win32':
            field_rect.y += 3

        # Set the resulting rect to the label.
        self.version_label.SetRect(field_rect)

This code is in my Frame's constructor to create and place the status bar:

self.statusbar = CustomStatusBar(self)
self.SetStatusBar(self.statusbar)

And I added this function to my frame for easy status updates:

def set_status_text(text):
    self.statusbar.SetStatusText(text, 0)

I hope this helps somebody else down the line.

like image 195
Hubro Avatar answered Sep 29 '22 07:09

Hubro


The hacky version wasn't exactly ideal for what I was looking for. I found setting static width size based on the pixel size of the string worked great for me. Adapted to the environment nicely and can be changed dynamically. This was done with Python 3 and wxPython Phoenix, so maybe this method wasn't available before.

Here is a simple version.

import wx

class MainWindow(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)

        version = "v. 1.0.32 (2012-11-03)"
        # Returns a Size object of the pixel dimensions of a string
        version_size = wx.Window.GetTextExtent(self, version)

        # Create a status bar with two sections
        self.CreateStatusBar(2)
        # Set the left side to a negative number indicating it's fluid width
        # The right side will be the exact size of the version string
        self.SetStatusWidths([-1, version_size.width])
        # Set the left side of the status bar to some text. 0 is first section
        self.SetStatusText("left status bar text", 0)
        # Set right side to version number.  1 is second section
        self.SetStatusText(version, 1)

        self.Show()

app = wx.App()
frame = MainWindow(None)
app.MainLoop()

To show how it can be updated dynamically here is a bit more complex version with threaded random updates.

import wx
import time
import random
import threading

class MainWindow(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)

        version = "v. 1.0.32 (2012-11-03)"
        # Returns a Size object of the pixel dimensions of a string
        version_size = wx.Window.GetTextExtent(self, version)

        # Create a status bar with two section
        self.CreateStatusBar(2)
        # Set the left side to a negative number indicating it's fluid width
        # The right side will be the exact size of the version string
        self.SetStatusWidths([-1, version_size.width])
        # Set the left side of the status bar to some text. 0 is first section
        self.SetStatusText("left status bar text", 0)
        # Set right side to version number.  1 is second section
        self.SetStatusText(version, 1)

        self.Show()

        # Thread to update status bar with causing the GUI to hang
        run_version_updates = threading.Thread(target=self.thread_version_updating)
        run_version_updates.start()

    def thread_version_updating(self):
        for i in range(10):
            time.sleep(1)
            # Create a random string of 1-20 characters containing only "ABC123"
            random_string = "".join(random.choice("ABC123") for _ in range(random.randrange(1,20)))
            self.update_version(random_string)

    def update_version(self, version):
        # Get width of string, set status bar width, then update the text
        size = wx.Window.GetTextExtent(self, version)
        self.SetStatusWidths([-1, size.width])
        self.SetStatusText(version, 1)

app = wx.App()
frame = MainWindow(None)
app.MainLoop()

I only have the one operating system, but here is what it looked like with different Windows 7 themes.

Win 7 Aero
enter image description here

Win 7 classic
enter image description here

like image 37
Stack of Pancakes Avatar answered Sep 29 '22 07:09

Stack of Pancakes