Display strings in different colors within the cells of GridColTitles

600 views
Skip to first unread message

Johan Lundström

unread,
Feb 19, 2015, 10:29:32 AM2/19/15
to npys...@googlegroups.com
I've been fiddling around with npyscreen for about a day now and it works quite nicely.

I have, however, not been able to display colored text in the cells of my GridColTitles widget.
I'm using a GridColTitles to display test results across different devices and versions of my software.

I'm going to put output similar to the one below on a big screen in the office and it would be great if I could color the text in the different cells differently depending on the results of my test.

│ iOS Beatrix
│                     v0.2        v0.3        v0.4        v0.5
│         ────────────────────────────────────────────────────────────
│         iPhone 4    FAIL        PASS        PASS        FAIL
│         iPhone 4s   PASS        FAIL        FAIL        FAIL
│         iPhone 5    FAIL        FAIL        PASS        FAIL
│         iPhone 5s   FAIL        PASS        PASS        FAIL
│         iPhone 6    PASS        FAIL        FAIL        PASS
│         iPad 2      FAIL        PASS        FAIL        FAIL
│         iPad 3      FAIL        FAIL        PASS        PASS
│         iPad Air    FAIL        FAIL        FAIL        PASS
│         iPad Air 2  PASS        PASS        FAIL        FAIL
│         iPad Mini   PASS        FAIL        FAIL        FAIL

I've tried a bunch of different libraries and approaches but it always ends with npyscreen printing the whole color code as a string rather than interpreting it as a color.

I read through this mailing list in search for posts about color and found a few, but none that seem to apply to my issue.

Any and all help would be very appreciated.

Best,
/Johan

I'm currently only prototyping so I copied some example code and edited it. Never mind the hardcoded mumbo jumbo or the random pass/fails. Here is was it looks like right now.
import npyscreen
import time
import random
import curses

def myFunction(*args):
    F = npyscreen.Form(name='TTS viewer')
    myFW = F.add(npyscreen.TitleText, name="iOS Beatrix")
    gd = F.add(npyscreen.GridColTitles, relx = 10, rely=3, width=60, col_margin=1, columns=5, always_show_cursor = False, col_titles = ['','v0.2','v0.3','v0.4','v0.5'])
    gd.values = []
    for x in range(10):
        row = []
        for y in range(5):
            if bool(random.getrandbits(1)):
                row.append("PASS")
            else:
                row.append("FAIL")
        gd.values.append(row)
    gd.values[0][0]="iPhone 4"
    gd.values[1][0]="iPhone 4s"
    gd.values[2][0]="iPhone 5"
    gd.values[3][0]="iPhone 5s"
    gd.values[4][0]="iPhone 6"
    gd.values[5][0]="iPad 2"
    gd.values[6][0]="iPad 3"
    gd.values[7][0]="iPad Air"
    gd.values[8][0]="iPad Air 2"
    gd.values[9][0]="iPad Mini"
    F.display()
    time.sleep(60)
    return myFW.value

if __name__ == '__main__':
    print npyscreen.wrapper_basic(myFunction)


Nicholas Cole

unread,
Feb 19, 2015, 11:32:18 AM2/19/15
to npys...@googlegroups.com
Johan,

Thanks. There are lots of ways you could do this. You could, for
example, create a grid using custom widgets inside. But I wanted to
give you a simpler way.

I've just uploaded version 4.8.2.

The Grid class here has a new method:

def custom_print_cell(self, actual_cell, cell_display_value):
pass

This is intended for you to overload. It is called when the value of
a cell has been set, just before it is actually displayed.
actual_cell is the cell object itself (by default, this is a Textfield
object) and cell_display_value is the object that is actually being
displayed in the cell. This will be the output of display_value and
will by default be a string.

Overloading this method will let you change the color of the cell
depending on the value being displayed, or even (if you wanted to get
more complicated) alter other attributes.

I hope that helps. I won't add this to the documentation until you
are happy with it, in case you have a better idea.

Best wishes,

Nicholas
> --
> You received this message because you are subscribed to the Google Groups
> "npyscreen" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to npyscreen+...@googlegroups.com.
> To post to this group, send email to npys...@googlegroups.com.
> Visit this group at http://groups.google.com/group/npyscreen.
> For more options, visit https://groups.google.com/d/optout.

Johan Lundström

unread,
Feb 20, 2015, 12:03:26 PM2/20/15
to npys...@googlegroups.com
Hello Nicholas and thank you for your swift reply.

I updated to 4.8.2 and gave it a go.

I know my custome_print_cell get's called (the commented out raw_input will halt execution) but it appears as I didn't quite understand what I am supposed to do.

I tried altering values. I tried printing things. I tried returning things but nothing seems to change what is actually being displayed when all is said and done.

What am I missing here?

Best,
/Johan

import npyscreen
import time
import random
import curses

class MyGrid(npyscreen.GridColTitles):
    def custom_print_cell(self, actual_cell, cell_display_value):
        print actual_cell.value
        print cell_display_value
        cell_display_value = 'foo'
        print cell_display_value
        #raw_input("take a look")
        return cell_display_value
        #return "bar"

def myFunction(*args):
    F = npyscreen.Form(name='TTS viewer')
    myFW = F.add(npyscreen.TitleText, name="iOS Beatrix")
    gd = F.add(MyGrid, relx = 10, rely=3, width=60, col_margin=1, columns=5, always_show_cursor = False, col_titles = ['','v0.2','v0.3','v0.4','v0.5'])
    gd.values = []
    for x in range(2):
        row = []
        for y in range(5):
            if bool(random.getrandbits(1)):
                row.append("PASS")
            else:
                row.append("FAIL")
        gd.values.append(row)
    gd.values[0][0]="iPhone 4"
    gd.values[1][0]="iPhone 4s"
    F.display()
    time.sleep(60)
    return myFW.value

if __name__ == '__main__':
    print npyscreen.wrapper_basic(myFunction)

Nicholas Cole

unread,
Feb 20, 2015, 2:24:43 PM2/20/15
to npys...@googlegroups.com
Hi

Try this and see if it does what you need::

class MyGrid(npyscreen.GridColTitles):
def custom_print_cell(self, actual_cell, cell_display_value):
if cell_display_value =='FAIL':
actual_cell.color = 'DANGER'
elif cell_display_value == 'PASS':
actual_cell.color = 'GOOD'
else:
actual_cell.color = 'DEFAULT'




On Fri, Feb 20, 2015 at 5:03 PM, Johan Lundström

Johan Lundström

unread,
Feb 23, 2015, 4:39:52 AM2/23/15
to npys...@googlegroups.com
Glorious success!

I didn't realize actual_cell had a color property. Might I suggest that we put this sample code in the documentation (it really does explain pretty much everything)?

class MyGrid(npyscreen.GridColTitles):
    # You need to override custom_print_cell to manipulate how
    # a cell is printed. In this example we change the color of the
    # text depending on the string value of cell.
    def custom_print_cell(self, actual_cell, cell_display_value):
        if cell_display_value =='FAIL': 
           actual_cell.color = 'DANGER' 
        elif cell_display_value == 'PASS': 
           actual_cell.color = 'GOOD' 
        else: 
           actual_cell.color = 'DEFAULT' 

def myFunction(*args):
    # making an example Form
    F = npyscreen.Form(name='Example viewer')
    myFW = F.add(npyscreen.TitleText)
    gd = F.add(MyGrid)
    
    # Adding values to the Grid, this code just randomly
    # fills a 2 x 4 grid with random PASS/FAIL strings.
    gd.values = []
    for x in range(2):
        row = []
        for y in range(4):
            if bool(random.getrandbits(1)):
                row.append("PASS")
            else:
                row.append("FAIL")
        gd.values.append(row)
    F.edit()

if __name__ == '__main__':
    npyscreen.wrapper_basic(myFunction)

Using this approach to reach my goal is fine, it works and doesn't require much coding at all.
However, if I was to do this on my own I probably would have opted for a more low level approach by allowing ANSI escape sequences in the values about to get printed to screen.

Now, I haven't gone through much of your code at all so I don't know how tricky that approach would be. I know you have the theme manager and such which makes a lot of sense considering what you designed this library for. I, on the other hand use it to display a neat table of data on a big screen so all things considered, your solution is probably preferable.

Thanks a lot for the help, I really do appreciate it. I looked for a donate button but found none, if you have one or if you have a favorite organization I can donate to instead, please let me know.

Best,
/Johan
Reply all
Reply to author
Forward
0 new messages