Metadata-Version: 2.4
Name: CTkDataTable
Version: 1.0.1
Summary: A virtualized data table widget for CustomTkinter applications.
Author: Harry Gomm
License-Expression: MIT
Project-URL: Documentation, https://harry-g25.github.io/CTkDataTable
Project-URL: Homepage, https://github.com/Harry-g25/CTkDataTable
Project-URL: Issues, https://github.com/Harry-g25/CTkDataTable/issues
Project-URL: Source, https://github.com/Harry-g25/CTkDataTable
Keywords: customtkinter,tkinter,table,datagrid,widgets
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
Classifier: Topic :: Software Development :: User Interfaces
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: customtkinter<6.1,>=5.2.2
Requires-Dist: CTkScrollableDropdownPP<2.5,>=2.2
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: ruff>=0.11; extra == "dev"
Requires-Dist: twine>=5.1; extra == "dev"
Dynamic: license-file

<div align="center">

<img src="https://capsule-render.vercel.app/api?type=rect&amp;height=180&amp;color=0:020617,50:111827,100:312e81&amp;text=CTkDataTable&amp;fontColor=ffffff&amp;fontSize=52&amp;fontAlignY=42&amp;desc=Modern%20data%20tables%20for%20CustomTkinter%20desktop%20apps&amp;descAlignY=68&amp;descSize=18" />

<br>

<p>
  <img src="https://readme-typing-svg.demolab.com?font=JetBrains+Mono&amp;weight=500&amp;size=20&amp;pause=1200&amp;color=A78BFA&amp;center=true&amp;vCenter=true&amp;width=760&amp;lines=Modern+tables+for+CustomTkinter;Built+for+desktop+apps+and+admin+tools;Display+structured+data+without+ttk.Treeview" />
</p>

<p>
  <a href="https://pypi.org/project/CTkDataTable/">
    <img src="https://img.shields.io/pypi/v/CTkDataTable?style=for-the-badge&amp;logo=pypi&amp;logoColor=white&amp;color=7c3aed" />
  </a>
  <a href="https://pypi.org/project/CTkDataTable/">
    <img src="https://img.shields.io/pypi/pyversions/CTkDataTable?style=for-the-badge&amp;logo=python&amp;logoColor=white&amp;color=2563eb" />
  </a>
  <img src="https://img.shields.io/badge/CustomTkinter-Compatible-111827?style=for-the-badge" />
  <a href="https://harry-g25.github.io/CTkDataTable-Docs-Website/">
  <img src="https://img.shields.io/badge/Docs-View%20Documentation-a855f7?style=for-the-badge&amp;logo=readthedocs&amp;logoColor=white" />
</a>


</p>

</div>

---

## What is CTkDataTable?

`CTkDataTable` is a Python module for building cleaner, more practical data tables inside `customtkinter` desktop applications.

It was created to solve a common problem: CustomTkinter is great for modern desktop interfaces, but displaying structured table data can still be awkward. Standard Tkinter options such as `ttk.Treeview` often feel dated, difficult to style, or out of place in a modern UI.

`CTkDataTable` provides a configurable table widget designed for internal tools, dashboards, admin panels, database applications and workflow software.

---

## Why Use It?

<table>
  <tr>
    <td width="33%">
      <h3>CustomTkinter Friendly</h3>
      <p>Designed to fit naturally into modern CustomTkinter applications.</p>
    </td>
    <td width="33%">
      <h3>Dictionary Based</h3>
      <p>Define columns and rows using simple Python dictionaries.</p>
    </td>
    <td width="33%">
      <h3>Practical</h3>
      <p>Built for dashboards, admin tools, database viewers and internal systems.</p>
    </td>
  </tr>
</table>

---

## Features

* Built for `customtkinter`
* Simple column configuration
* Row data passed as dictionaries
* Configurable column titles
* Configurable column widths
* Text columns
* Number columns
* Badge columns
* Contrast-aware badge and pill labels
* Table-style combobox columns with scrollable, searchable popups
* Stable row IDs and structured edit events
* Per-column and table-wide validation
* Read-only tables and columns
* Cleaner alternative to `ttk.Treeview`
* Resizable columns
* Fill-width layouts
* Horizontal scrolling
* Compact, comfortable and spacious density presets
* Hover, pressed, keyboard-focus and truncation-tooltip feedback
* Useful for desktop dashboards and database-driven apps

---

## Installation

```bash
pip install CTkDataTable
```

`CTkDataTable` requires Python 3.11 or newer. Pip also installs the compatible `customtkinter` and dropdown dependencies.

---

## Quick Start

```python
import customtkinter as ctk
from CTkDataTable import CTkDataTable

app = ctk.CTk()
app.title("CTkDataTable Example")
app.geometry("900x500")

columns = [
    {
        "key": "id",
        "title": "ID",
        "width": 50,
        "type": "number"
    },
    {
        "key": "first_name",
        "title": "First Name",
        "width": 140,
        "type": "text"
    },
    {
        "key": "last_name",
        "title": "Last Name",
        "width": 140,
        "type": "text"
    },
    {
        "key": "position",
        "title": "Position",
        "width": 180,
        "type": "text"
    },
    {
        "key": "permission",
        "title": "Permission",
        "width": 140,
        "type": "badge",
        "badge_colors": {
            "Admin": ("#fecaca", "#7f1d1d"),
            "Manager": ("#bfdbfe", "#1e3a8a"),
            "Standard": ("#e5e7eb", "#374151")
        }
    }
]

rows = [
    {
        "id": 1,
        "first_name": "Harry",
        "last_name": "Gomm",
        "position": "Manager",
        "permission": "Manager"
    },
    {
        "id": 2,
        "first_name": "Ben",
        "last_name": "Jones",
        "position": "Engineer",
        "permission": "Standard"
    },
    {
        "id": 3,
        "first_name": "Charlie",
        "last_name": "Smith",
        "position": "Admin",
        "permission": "Admin"
    }
]

table = CTkDataTable(
    master=app,
    columns=columns,
    data=rows,
    row_key="id",
    column_width_mode="fill",
    resizable_columns=True
)

table.pack(fill="both", expand=True, padx=20, pady=20)

app.mainloop()
```

---

## How It Works

```mermaid
flowchart LR
    A[Define Columns] --> B[Create Row Data]
    B --> C[Pass Data to CTkDataTable]
    C --> D[Render Table]
    D --> E[Display Structured Data]
```

---

## Column Configuration

Columns are defined using dictionaries.

```python
columns = [
    {
        "key": "first_name",
        "title": "First Name",
        "width": 140,
        "type": "text"
    }
]
```

| Property | Description                              |
| -------- | ---------------------------------------- |
| `key`    | The key used to match data from each row |
| `title`  | The text displayed in the table header   |
| `width`  | The width of the column                  |
| `type`   | The column display type                  |

---

## Supported Column Types

<table>
  <tr>
    <td width="33%">
      <h3>Text</h3>
      <p>For names, labels, descriptions and general values.</p>
    </td>
    <td width="33%">
      <h3>Number</h3>
      <p>For IDs, counts, quantities and numeric data.</p>
    </td>
    <td width="33%">
      <h3>Badge</h3>
      <p>For statuses, permissions, categories and priority labels.</p>
    </td>
  </tr>
</table>

Additional built-in types include percentage, currency, date, datetime, progress, link, pill-list, checkbox, combobox and action columns.

### Text Column

```python
{
    "key": "name",
    "title": "Name",
    "width": 160,
    "type": "text"
}
```

### Number Column

```python
{
    "key": "id",
    "title": "ID",
    "width": 60,
    "type": "number"
}
```

### Badge Column

```python
{
    "key": "permission",
    "title": "Permission",
    "width": 140,
    "type": "badge",
    "badge_colors": {
        "Admin": ("#fecaca", "#7f1d1d"),
        "Manager": ("#bfdbfe", "#1e3a8a"),
        "Standard": ("#e5e7eb", "#374151")
    }
}
```

### Combobox Column

Combobox cells keep a dropdown arrow visible inside the table and open a themed, scrollable `CTkScrollableDropdownPP` popup. Lists with more than ten choices get search automatically. Options may store the same string they display, or use `ComboOption` to separate a friendly label from the value saved to your database.

```python
from CTkDataTable import CellChangeEvent, ComboOption


def status_changed(event: CellChangeEvent) -> None:
    print(event.row_id, event.old_value, "->", event.new_value)


{
    "key": "status",
    "title": "Status",
    "width": 180,
    "type": "combobox",
    "options": [
        ComboOption("Pending", "pending"),
        ComboOption("Active", "active"),
        ComboOption("Complete", "complete"),
    ],
    "allow_custom": False,
    "allow_empty": True,
    "empty_value": None,
    "empty_label": "No status",
    "dropdown_height": 300,
    "dropdown_width": 240,
    "searchable": True,
    "on_change": status_changed
}
```

Set `searchable=True` or `False` to override automatic search, and use `items_per_page` for very long lists. Set `allow_custom=True` to accept typed values. Pressing Enter or clicking elsewhere commits custom text, while Escape cancels it. With `allow_empty=True`, the labelled empty choice and Delete/Backspace use `empty_value`; leaving its default as `None` maps naturally to SQL `NULL`. Existing values outside the configured choices remain visible until the user changes them. Installing `CTkDataTable` installs the dropdown dependency automatically.

### Editing and Saving

Give database-backed tables a stable identity with `row_key="id"`. Every row must then contain a unique, hashable ID. `CellChangeEvent.row_id` remains the record identity even when sorting or filtering changes the row's visible position.

`get_data()`, `get_cell()`, and the other getters are pure reads: they never commit an editor as a side effect. Put the edit boundary in your Save button:

```python
def save_to_database() -> None:
    if not table.commit_edit():
        print("Cannot save:", table.edit_validation_error)
        return

    rows = table.get_data()
    # Run parameterized INSERT/UPDATE statements, then commit your transaction.
```

Use `cancel_edit()` to discard the active typed edit. For targeted access, call `get_cell(source_index, "status")`, `get_cell_by_id(row_id, "status")`, `update_cell(...)`, or `update_cell_by_id(...)`. Programmatic updates validate but are quiet by default; pass `notify=True` to emit a `CellChangeEvent` with `origin="api"`. Stable-ID row helpers include `get_row_by_id()`, `update_row_by_id()`, and `delete_row_by_id()`.

Editable checkbox and combobox columns accept `editable=False`, `validator=...`, and `on_change=...`. The table accepts `read_only=True`, `cell_validator=...`, and `on_cell_change=...`. Validators receive a `CellEditRequest` and return `None` to accept or an error message to reject. A rejected typed edit stays open so the user can correct it.

For each successful change, the model and view update first, then the column's `on_change`, then the table's `on_cell_change`. `CellChangeEvent` includes `widget`, `row_id`, a read-only row snapshot, `source_index`, `view_index_before`, `view_index_after`, `column_key`, `old_value`, `new_value`, and `origin`. `on_selection_change` similarly receives a `SelectionChangeEvent` with current, added, and removed rows/IDs/indices. Selection can also be controlled with `select_row()`, `select_row_by_id()`, and `clear_selection()`. The existing `on_checkbox_toggle(TableRowEvent)` callback remains supported for compatibility and runs after the new cell-change callbacks.

The widget intentionally does not own a database connection or transaction. If a SQL save fails, keep your original rows or reload them with `set_data()` after rolling back.

---

## Row Data

Rows are passed as a list of dictionaries.

```python
rows = [
    {
        "id": 1,
        "first_name": "Harry",
        "last_name": "Gomm",
        "position": "Manager",
        "permission": "Manager"
    }
]
```

Each row key should match the `key` value defined in the column configuration.

---

## Use Cases

`CTkDataTable` can be used for:

* Admin panels
* User management screens
* Database viewers
* Desktop dashboards
* CRUD applications
* Job management tools
* Stock or asset registers
* Reporting interfaces

---

## Project Status

`CTkDataTable` is available on PyPI for production use and actively maintained through practical use in real CustomTkinter desktop applications. Review the changelog when upgrading. Feedback, issues and suggestions are welcome.

---

## Contributing

Contributions are welcome.

If you find a bug, have an idea for a feature, or want to improve the documentation, feel free to open an issue or submit a pull request.

---

## Licence

This project is released under the MIT Licence.

---

## Links

<p>
  <a href="https://pypi.org/project/CTkDataTable/">
    <img src="https://img.shields.io/badge/PyPI-CTkDataTable-7c3aed?style=for-the-badge&amp;logo=pypi&amp;logoColor=white" />
  </a>
  <a href="https://github.com/Harry-g25/CTkDataTable">
    <img src="https://img.shields.io/badge/GitHub-Repository-111827?style=for-the-badge&amp;logo=github&amp;logoColor=white" />
  </a>
  <a href="https://www.harrygomm.co.uk">
    <img src="https://img.shields.io/badge/Portfolio-harrygomm.co.uk-312e81?style=for-the-badge&amp;logo=google-chrome&amp;logoColor=white" />
  </a>
</p>

---

<div align="center">

### Built for clean, practical CustomTkinter applications.

<img src="https://capsule-render.vercel.app/api?type=rect&amp;height=90&amp;section=footer&amp;color=0:312e81,50:111827,100:020617" />

</div>
