Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions CTkTable/TableGenerator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
from PIL import Image, ImageDraw, ImageFont
from customtkinter import CTkLabel
from PIL import ImageTk
class TableGenerator:
def __init__(self,
values,
cell_widths : list,
cell_height : int,
colors:list,
font_size : int =15,
text_color : str = "white",
rectangle_color :str = "white",
table_to_tkinter : bool = True,
master_for_tkinter : any = None,
)-> None:
self.values = values
self.cell_widths = cell_widths
self.cell_height = cell_height
self.row_count = len(values)
self.column_count = len(values[0])
self.image_width = sum(self.cell_widths) + 1
self.image_height = self.row_count * self.cell_height + 1
self.image = Image.new("RGB", (self.image_width, self.image_height), "black")
self.draw = ImageDraw.Draw(self.image)
self.font_path = "arial.ttf" # Font path
self.get_table = table_to_tkinter
self.text_color = text_color
self.rectangle_color = rectangle_color
self.colors = colors
self.font = self.load_font(font_size)

self.master = master_for_tkinter
print(self.column_count)
print(len(cell_widths))
if len(cell_widths)<self.column_count:
for a in range(self.column_count-len(cell_widths)):
self.cell_widths.append(self.cell_widths[0])
print(len(self.cell_widths))
self.draw_table()
def load_font(self, font_size):
try:
return ImageFont.truetype(self.font_path, font_size)
except IOError:
return ImageFont.load_default()

def draw_table(self)-> None:
self.position = {}
# Sabit bir yazı boyutu
for i in range(self.row_count):
for j in range(self.column_count):
try:
x = sum(self.cell_widths[:j])
except Exception as e:
x = j * self.cell_widths[0]

print(e)
y = i * self.cell_height

try:
text = self.values[i][j]
except:
text = " "
text=str(text)
self.position[x,y] = text
# Yazı hücreye sığana kadar karakter sil
while True:
text_size = self.draw.textbbox(text=text, font=self.font, xy=(0, 0))
if text_size[2]+10 <= self.cell_widths[j]:
break # Yazı hücreye sığıyor, döngüden çık

text = text[:-4]
text = text + "..."
print(text)
if len(text)<4:
break

# Son karakteri sil

# Metni ortala ve çiz
text_x = x + (self.cell_widths[j] - text_size[2]) / 2
text_y = y + (self.cell_height - text_size[3]) / 2

self.draw.rectangle([x, y, x + self.cell_widths[j], y + self.cell_height], outline=self.rectangle_color,fill = self.colors[0] if i==0 else self.colors[i%2+1])
self.draw.text((text_x, text_y), text, fill=self.text_color, font=self.font)
if self.get_table:
self.get_image_label()
def save_image(self, file_name="values.png"):
self.image.save(file_name)

def show_image(self):
self.image.show()
def get_value(self, x: int, y: int) -> dict:

# Koordinatların hangi hücreye ait olduğunu bul
for i in range(self.row_count):
row_start_y = i * self.cell_height
row_end_y = row_start_y + self.cell_height
if row_start_y <= y < row_end_y:
row = i
break
else:
return {"error": "Koordinat satır sınırlarının dışında."}

for j in range(self.column_count):
col_start_x = sum(self.cell_widths[:j])
col_end_x = col_start_x + self.cell_widths[j]
if col_start_x <= x < col_end_x:
col = j
break
else:
return {"error": "Koordinat sütun sınırlarının dışında."}

return {
"row": row,
"column": col,
"value": self.values[row][col]
}
def get_image_label(self) :

# Görseli PIL Image'dan ImageTk formatına dönüştür
image_tk = ImageTk.PhotoImage(self.image)
# CustomTkinter Label oluştur ve görseli ayarla
image_label = CTkLabel(self.master,text="", image=image_tk)

# Görselin bellekte kalmasını sağla (bu adım görselin kaybolmasını engeller)
image_label.image = image_tk

self.CTkTable = image_label
def update_values(self,values):
self.values=values
if self.row_count !=len(values):
self.row_count = len(values)
self.image_height = self.row_count * self.cell_height + 1
self.image = Image.new("RGB", (self.image_width, self.image_height), "black")
self.draw = ImageDraw.Draw(self.image)
self.get_table = False
self.draw_table()
self.get_table = True
image_tk = ImageTk.PhotoImage(self.image)
self.CTkTable.configure(image=image_tk)
self.CTkTable.image = image_tk
self.CTkTable.update()
if __name__=="__main__":
import customtkinter as ctk
# Örnek tablo
win = ctk.CTk() # Doğru yazımı

values = [
["ID", "Name", "Surname dffsd dsf df", "Age"],
["1", "Ali", "Yilmaz", "30"],
["2", "Ayse", "Demir", "25"],
["3", "Mehmet", "Kaya", "28"]
]

# Sınıfı kullanarak tabloyu oluştur ve görüntüle
Tab = TableGenerator(values=values,cell_widths=[20,200,300,250],cell_height=30,colors=["#3050DD","#303030","#101010"],rectangle_color="black")

Tab.draw_table()
Tab.save_image()
print(Tab.get_value(0,0))

#Tab.show_image()
10 changes: 8 additions & 2 deletions CTkTable/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@
Author: Akash Bora
License: MIT
This is a custom table widget for customtkinter.

TableGenerator is faster
Homepage: https://github.com/Akascape/CTkTable
"""

__version__ = '1.1'
"""
Another Homepage: https://github.com/MustafaHilmiYAVUZHAN
"""
__version__ = '1.1.2'

from .ctktable import CTkTable
from .MiniTable import CTkTableMini
from .TableGenerator import TableGenerator
160 changes: 159 additions & 1 deletion CTkTable/ctktable.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,14 +344,32 @@ def edit_column(self, column, value=None, **kwargs):
self.dynamic_hover(self.corner_buttons[i, column], i, column)
self.update_data()

def update_values(self, values, **kwargs):
def update_values_old(self, values, **kwargs):
""" update all values at once """
for i in self.frame.values():
i.destroy()
self.frame = {}
self.values = values
self.draw_table(**kwargs)
self.update_data()
def update_values(self, values, **kwargs):
""" update all values at once
0.2 second per 250 Button
if Write==False"""
if self.write:
self.update_values_old()
else:
for i in range(self.rows):
for j in range(self.columns):
try:

value = values[i][j]
except IndexError: value = " "
self.frame[i,j].configure(text=value)
#self.frame[i,j].update()
self.values = values
self.draw_table(**kwargs)
self.update_data()

def add_row(self, values, index=None, **kwargs):
""" add a new row """
Expand Down Expand Up @@ -717,3 +735,143 @@ def unbind(self, sequence: str = None, funcid: str = None):
for i in self.frame:
self.frame[i].unbind(sequence, funcid)
self.inside_frame.unbind(sequence, funcid)

from customtkinter import CTkFrame,ThemeManager,CTkButton
class CTkTableMini(CTkFrame):
""" CTkTableMini Widget """

def __init__(
self,
master: any,
row: int = None,
column: int = None,
padx: int = 1,
pady: int = 0,
width: int = 140,
height: int = 28,
values: list = None,
colors: list = [None, None],
orientation: str = "horizontal",
color_phase: str = "horizontal",
border_width: int = 0,
text_color: str or tuple = None,
border_color: str or tuple = None,
font: tuple = None,
header_color: str or tuple = None,
corner_radius: int = 25,
write: str = False,
command = None,
anchor: str = "c",
hover_color: str or tuple = None,
hover: bool = False,
justify: str = "center",
wraplength: int = 1000,
column_widths : list =None,
*arg,
**kwargs):

self.arg=arg
self.command = command
self.values = values
self.column_widths=column_widths
self.rows = row if row else len(values) # number of default rows
self.columns = column if column else len(values[0])
self.hover_color = ThemeManager.theme["CTkButton"]["hover_color"] if hover_color is None else hover_color
self.font=font
self.header=header_color
self.colors=colors
self.border_color = ThemeManager.theme["CTkButton"]["border_color"] if border_color is None else border_color

self.fg_color = ThemeManager.theme["CTkFrame"]["fg_color"] if not self.colors[0] else self.colors[0]
self.fg_color2 = ThemeManager.theme["CTkFrame"]["top_fg_color"] if not self.colors[1] else self.colors[1]

if self.colors[0] is None and self.colors[1] is None:
if self.fg_color==self.master.cget("fg_color"):
self.fg_color = ThemeManager.theme["CTk"]["fg_color"]
if self.fg_color2==self.master.cget("fg_color"):
self.fg_color2 = ThemeManager.theme["CTk"]["fg_color"]
self.fg_color_back=ThemeManager.theme["CTkFrame"]["fg_color"]
super().__init__(master, fg_color=ThemeManager.theme["CTkFrame"]["fg_color"])
super().configure(border_color=self.border_color, border_width=border_width, corner_radius=corner_radius)
self.cells={}
self.draw()
def draw_table(self,columns,column_widths,colors,values,font,us_command,start_row):
frame={}

rows=len(values)
for i in range(rows):

fg=colors[(i+start_row)%2]
for j in range(columns):
width = column_widths[j] if j < len(column_widths) else 20
try:

value = self.values[i+start_row][j]
except IndexError: value = " "



frame[i+start_row,j] = CTkButton(self,
font=font,
text=value,
width=width,
border_width=0,
corner_radius=0,
fg_color=fg,
hover=False,

background_corner_colors=[fg,fg,fg,fg],
command = lambda i=i+start_row,j=j,v=value: us_command(v,i,j))


return frame
def draw(self):
"""result=[]
count_of_5 = self.rows // 5
remainder = self.rows % 5
result = [5] * count_of_5
if remainder != 0:
result.append(remainder)
start_row=0

for i in result:

self.cells.update(self.draw_table(columns=self.columns,column_widths=self.column_widths,colors=self.colors,values=self.values[start_row:start_row+i],font=self.font,us_command=self.us_command,start_row=start_row))
start_row+=i

#maybe Threading"""
self.cells.update(self.draw_table(columns=self.columns,column_widths=self.column_widths,colors=self.colors,values=self.values,font=self.font,us_command=self.us_command,start_row=0))
if self.header is not None:
for j in range(self.columns):
self.cells[0,j].configure(fg_color=self.header)
self.cells[0,0].configure(corner_radius=10,background_corner_colors=[self.fg_color_back,self.header,self.header,self.header])
self.cells[0,self.columns-1].configure(corner_radius=10,background_corner_colors=[self.header,self.fg_color_back,self.header,self.header])
else:
self.cells[0,0].configure(corner_radius=10,background_corner_colors=[self.fg_color_back,self.fg_color,self.fg_color,self.fg_color])
self.cells[0,self.columns-1].configure(corner_radius=10,background_corner_colors=[self.fg_color,self.fg_color_back,self.fg_color,self.fg_color])


for i in range(self.rows):
for j in range(self.columns):
self.cells[i,j].grid(column=j, row=i, padx=1, pady=1, sticky="nsew")

def us_command(self,value,i,j):
self.command({"value":value,"row":i+1,"column":j+1})

def update_values_old(self,values):
for i in self.cells.values():
i.destroy()
self.frame = {}
self.values = values
self.rows = len(values) # number of default rows
self.columns = len(values[0])
self.draw()
def update_values(self,values):
for i in range(self.rows):
for j in range(self.columns):
try:

value = values[i][j]
except IndexError: value = " "
self.cells[i,j].configure(text=value)
self.cells[i,j].update()
Loading