Textualize / textual

The lean application framework for Python. Build sophisticated user interfaces with a simple Python API. Run your apps in the terminal and a web browser.
https://textual.textualize.io/
MIT License
25.1k stars 767 forks source link

DataTable Cell Borders? #5014

Open arcreigh opened 1 day ago

arcreigh commented 1 day ago

Couldn't find any reference on how to style cells in a DataTable. I'd love to be able to have borders around the cells themselves to better distinguish between the data contained in the cells much like how excel will distinguish the various cells as an individual container.

github-actions[bot] commented 1 day ago

We found the following entry in the FAQ which you may find helpful:

Feel free to close this issue if you found an answer in the FAQ. Otherwise, please give us a little time to review.

This is an automated reply, generated by FAQtory

TomJGooding commented 1 day ago

There's no way of adding borders to the cells of the DataTable AFAIK.

Bear in mind that adding borders would make the table considerably less compact, as each border would require an additional row in the terminal.

For example, a table currently renders like this:

 lane  swimmer               country        time  
 4     Joseph Schooling      Singapore      50.39 
 2     Michael Phelps        United States  51.14 
 5     Chad le Clos          South Africa   51.14 
 6     László Cseh           Hungary        51.14 
 3     Li Zhuhao             China          51.26 
 8     Mehdy Metella         France         51.58 
 7     Tom Shields           United States  51.73 
 1     Aleksandr Sadovnikov  Russia         51.84 
 10    Darren Burns          Scotland       51.84 

If borders were added, it would look something like this:

┌──────┬──────────────────────┬───────────────┬───────┐
│ lane │ swimmer              │ country       │ time  │
├──────┼──────────────────────┼───────────────┼───────┤
│ 4    │ Joseph Schooling     │ Singapore     │ 50.39 │
├──────┼──────────────────────┼───────────────┼───────┤
│ 2    │ Michael Phelps       │ United States │ 51.14 │
├──────┼──────────────────────┼───────────────┼───────┤
│ 5    │ Chad le Clos         │ South Africa  │ 51.14 │
├──────┼──────────────────────┼───────────────┼───────┤
│ 6    │ László Cseh          │ Hungary       │ 51.14 │
├──────┼──────────────────────┼───────────────┼───────┤
│ 3    │ Li Zhuhao            │ China         │ 51.26 │
├──────┼──────────────────────┼───────────────┼───────┤
│ 8    │ Mehdy Metella        │ France        │ 51.58 │
├──────┼──────────────────────┼───────────────┼───────┤
│ 7    │ Tom Shields          │ United States │ 51.73 │
├──────┼──────────────────────┼───────────────┼───────┤
│ 1    │ Aleksandr Sadovnikov │ Russia        │ 51.84 │
├──────┼──────────────────────┼───────────────┼───────┤
│ 10   │ Darren Burns         │ Scotland      │ 51.84 │
└──────┴──────────────────────┴───────────────┴───────┘
arcreigh commented 1 day ago

The need stems from a data dense display of source / destination / ports for firewall rules. Being able to very clearly distinguish one policy from another in the table is quite important as is the ability to dynamically expand / contract the height / width of a cell to fit that content at least in my particular need.

TomJGooding commented 1 day ago

Perhaps someone in the Textual community has a clever workaround for adding borders, but in the meantime, would some extra padding in the cells be a helpful alternative?

from textual.app import App, ComposeResult
from textual.widgets import DataTable

ROWS = [
    ("lane", "swimmer", "country", "time"),
    (4, "Joseph Schooling", "Singapore", 50.39),
    (2, "Michael Phelps", "United States", 51.14),
    (5, "Chad le Clos", "South Africa", 51.14),
    (6, "László Cseh", "Hungary", 51.14),
    (3, "Li Zhuhao", "China", 51.26),
    (8, "Mehdy Metella", "France", 51.58),
    (7, "Tom Shields", "United States", 51.73),
    (1, "Aleksandr Sadovnikov", "Russia", 51.84),
    (10, "Darren Burns", "Scotland", 51.84),
]

class TableApp(App):
    def compose(self) -> ComposeResult:
        yield DataTable(cell_padding=4)

    def on_mount(self) -> None:
        table = self.query_one(DataTable)
        table.add_columns(*ROWS[0])
        for row in ROWS[1:]:
            table.add_row(*row, height=2)

if __name__ == "__main__":
    app = TableApp()
    app.run()
willmcgugan commented 1 day ago

Do you need the table widget? You can easily build something table-like with widgets. That way you can have borders and collapsible sections without any effort.

arcreigh commented 1 day ago

I am honestly not quite sure if it is, I was reading through the docs as a very unseasoned programmer trying to resolve some headaches at work. Generally I like that the DataTable exposes a way to select a row and that I can trigger events off of it for editing. Just wish there was some more flexibility in the styling of the table itself. It is also great that I can sort on columns. So the overall featureset of the DataTable is appealing to my use case. However the kind of data I work with on a day to day basis can be rather large from a list of ip addresses / subnets standpoint.

One firewall policy may only have a few addresses and the next may have 20+ or even more and it can expand over time as other admins modify a policy. I don't want to run into a scenario where my data overruns the viewable area of a cell like discussed in some other issues here.