Search code examples
pythonlayoutpyqtcairographic

Best Module to Layout Text in Python


I am looking to write a program which outputs a bunch (around 30) of boxes like in this image:

market watchlist

I have been researching for weeks, I thought that to layout text in a graphically pleasing way I could use QTableWidget in PyQT, but I now realise that it is far too difficult to learn for such a simple task, there must be a quicker way. So I am thinking now to pass to Tkinter or maybe just draw the information with a Drawing Module like PyCairo and only then place each image in a PyQT interface. Sorting out all the positioning in a drawing module would be much quicker than learning how to do the same in PyQT.

But I feel I am missing something, I would have thought a much easier task to layout in a nice way a bunch of numbers in a repetitive format.

Some of the boxes will need also some graphical content has bars and charts for which I though to use plotly or cairo.


Solution

  • Whilst you're probably better off doing this with HTML and CSS as has been mentioned above, this isn't too difficult to do with Python and can be achieved with the use of just tkinter. Please see my code below for an example of how this could work:

    from tkinter import *
    
    root = Tk()
    frame1 = []
    frame2 = []
    c = 0
    numberofboxes = 8 #change this to increase the number of boxes
    
    for i in range(numberofboxes):
        if i % 4 == 0: #checks if the current box is the fourth in row
            c = c + 1 #if the current box is the forth in the row then this runs and increases a counter which we later use to determine the row
        if len(frame1) != c: #checks if the number of rows currently existing matches the number there should be
            frame1.append(Frame(root)) #if the numbers don't match this runs and creates a new frame which acts as another row
            frame1[c-1].pack(expand="True", fill="both") #packs the new row
        frame2.append(Frame(frame1[c-1], bg="green")) #this is where the boxes are created
        frame2[i].pack(ipadx="50", ipady="50", side="left", padx="10", pady="10", expand="True", fill="both") #this is where the boxes are placed on the screen
    
    for i in range(len(frame2)): #this for loop places the items inside each box, all of this can be replaced with whatever is needed
        Label(frame2[i], text="CO"+str(i), bg="green", fg="white").pack(side="top", anchor="w")
        Label(frame2[i], text="12165.1"+str(i), bg="green", fg="white").pack(side="top", anchor="w")
        Label(frame2[i], text="+60.7"+str(i), bg="green", fg="white").pack(side="bottom", anchor="e")
        Label(frame2[i], text="+1.2"+str(i)+"%", bg="green", fg="white").pack(side="bottom", anchor="e")
    
    root.mainloop()
    

    So essentially, we create a frame for each row and each box is a frame which has elements packed inside it and is fitted in the "row frame" 4 to each row.

    You should take a close look at all of the options for .pack() during this script as well as they are necessary to achieve the desired layout and results.

    For your triangles you would most likely need to either import an image or draw them within a canvas positioned properly or (as was pointed out by Bryan Oakley below) you could use unicode characters for the arrows, which would be an awful lot simpler.