├── README.md ├── forest-dark.tcl ├── forest-light.tcl ├── main.py └── people.xlsx /README.md: -------------------------------------------------------------------------------- 1 | # tkinter-excel-app 2 | Source code for Youtube video: https://youtu.be/8m4uDS_nyCk 3 | 4 | Tkinter theme used: https://github.com/rdbende/Forest-ttk-theme 5 | -------------------------------------------------------------------------------- /forest-dark.tcl: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 rdbende 2 | 3 | # The Forest theme is a beautiful and modern ttk theme inspired by Excel. 4 | 5 | package require Tk 8.6 6 | 7 | namespace eval ttk::theme::forest-dark { 8 | 9 | variable version 1.0 10 | package provide ttk::theme::forest-dark $version 11 | variable colors 12 | array set colors { 13 | -fg "#eeeeee" 14 | -bg "#313131" 15 | -disabledfg "#595959" 16 | -disabledbg "#ffffff" 17 | -selectfg "#ffffff" 18 | -selectbg "#217346" 19 | } 20 | 21 | proc LoadImages {imgdir} { 22 | variable I 23 | foreach file [glob -directory $imgdir *.png] { 24 | set img [file tail [file rootname $file]] 25 | set I($img) [image create photo -file $file -format png] 26 | } 27 | } 28 | 29 | LoadImages [file join [file dirname [info script]] forest-dark] 30 | 31 | # Settings 32 | ttk::style theme create forest-dark -parent default -settings { 33 | ttk::style configure . \ 34 | -background $colors(-bg) \ 35 | -foreground $colors(-fg) \ 36 | -troughcolor $colors(-bg) \ 37 | -focuscolor $colors(-selectbg) \ 38 | -selectbackground $colors(-selectbg) \ 39 | -selectforeground $colors(-selectfg) \ 40 | -insertwidth 1 \ 41 | -insertcolor $colors(-fg) \ 42 | -fieldbackground $colors(-selectbg) \ 43 | -font {TkDefaultFont 10} \ 44 | -borderwidth 1 \ 45 | -relief flat 46 | 47 | ttk::style map . -foreground [list disabled $colors(-disabledfg)] 48 | 49 | tk_setPalette background [ttk::style lookup . -background] \ 50 | foreground [ttk::style lookup . -foreground] \ 51 | highlightColor [ttk::style lookup . -focuscolor] \ 52 | selectBackground [ttk::style lookup . -selectbackground] \ 53 | selectForeground [ttk::style lookup . -selectforeground] \ 54 | activeBackground [ttk::style lookup . -selectbackground] \ 55 | activeForeground [ttk::style lookup . -selectforeground] 56 | 57 | option add *font [ttk::style lookup . -font] 58 | 59 | 60 | # Layouts 61 | ttk::style layout TButton { 62 | Button.button -children { 63 | Button.padding -children { 64 | Button.label -side left -expand true 65 | } 66 | } 67 | } 68 | 69 | ttk::style layout Toolbutton { 70 | Toolbutton.button -children { 71 | Toolbutton.padding -children { 72 | Toolbutton.label -side left -expand true 73 | } 74 | } 75 | } 76 | 77 | ttk::style layout TMenubutton { 78 | Menubutton.button -children { 79 | Menubutton.padding -children { 80 | Menubutton.indicator -side right 81 | Menubutton.label -side right -expand true 82 | } 83 | } 84 | } 85 | 86 | ttk::style layout TOptionMenu { 87 | OptionMenu.button -children { 88 | OptionMenu.padding -children { 89 | OptionMenu.indicator -side right 90 | OptionMenu.label -side right -expand true 91 | } 92 | } 93 | } 94 | 95 | ttk::style layout Accent.TButton { 96 | AccentButton.button -children { 97 | AccentButton.padding -children { 98 | AccentButton.label -side left -expand true 99 | } 100 | } 101 | } 102 | 103 | ttk::style layout TCheckbutton { 104 | Checkbutton.button -children { 105 | Checkbutton.padding -children { 106 | Checkbutton.indicator -side left 107 | Checkbutton.label -side right -expand true 108 | } 109 | } 110 | } 111 | 112 | ttk::style layout Switch { 113 | Switch.button -children { 114 | Switch.padding -children { 115 | Switch.indicator -side left 116 | Switch.label -side right -expand true 117 | } 118 | } 119 | } 120 | 121 | ttk::style layout ToggleButton { 122 | ToggleButton.button -children { 123 | ToggleButton.padding -children { 124 | ToggleButton.label -side left -expand true 125 | } 126 | } 127 | } 128 | 129 | ttk::style layout TRadiobutton { 130 | Radiobutton.button -children { 131 | Radiobutton.padding -children { 132 | Radiobutton.indicator -side left 133 | Radiobutton.label -side right -expand true 134 | } 135 | } 136 | } 137 | 138 | ttk::style layout Vertical.TScrollbar { 139 | Vertical.Scrollbar.trough -sticky ns -children { 140 | Vertical.Scrollbar.thumb -expand true 141 | } 142 | } 143 | 144 | ttk::style layout Horizontal.TScrollbar { 145 | Horizontal.Scrollbar.trough -sticky ew -children { 146 | Horizontal.Scrollbar.thumb -expand true 147 | } 148 | } 149 | 150 | ttk::style layout TCombobox { 151 | Combobox.field -sticky nswe -children { 152 | Combobox.padding -expand true -sticky nswe -children { 153 | Combobox.textarea -sticky nswe 154 | } 155 | } 156 | Combobox.button -side right -sticky ns -children { 157 | Combobox.arrow -sticky nsew 158 | } 159 | } 160 | 161 | ttk::style layout TSpinbox { 162 | Spinbox.field -sticky nsew -children { 163 | Spinbox.padding -expand true -sticky nswe -children { 164 | Spinbox.textarea -sticky nsew 165 | } 166 | 167 | } 168 | null -side right -sticky nsew -children { 169 | Spinbox.uparrow -side right -sticky nsew -children { 170 | Spinbox.symuparrow 171 | } 172 | Spinbox.downarrow -side left -sticky nsew -children { 173 | Spinbox.symdownarrow 174 | } 175 | } 176 | } 177 | 178 | ttk::style layout Horizontal.TSeparator { 179 | Horizontal.separator -sticky nswe 180 | } 181 | 182 | ttk::style layout Vertical.TSeparator { 183 | Vertical.separator -sticky nswe 184 | } 185 | 186 | ttk::style layout Card { 187 | Card.field { 188 | Card.padding -expand 1 189 | } 190 | } 191 | 192 | ttk::style layout TLabelframe { 193 | Labelframe.border { 194 | Labelframe.padding -expand 1 -children { 195 | Labelframe.label -side left 196 | } 197 | } 198 | } 199 | 200 | ttk::style layout TNotebook { 201 | Notebook.border -children { 202 | TNotebook.Tab -expand 1 -side top 203 | Notebook.client -sticky nsew 204 | } 205 | } 206 | 207 | ttk::style layout TNotebook.Tab { 208 | Notebook.tab -children { 209 | Notebook.padding -side top -children { 210 | Notebook.label 211 | } 212 | } 213 | } 214 | 215 | ttk::style layout Treeview.Item { 216 | Treeitem.padding -sticky nswe -children { 217 | Treeitem.indicator -side left -sticky {} 218 | Treeitem.image -side left -sticky {} 219 | Treeitem.text -side left -sticky {} 220 | } 221 | } 222 | 223 | 224 | # Elements 225 | 226 | # Button 227 | ttk::style configure TButton -padding {8 4 8 4} -width -10 -anchor center 228 | 229 | ttk::style element create Button.button image \ 230 | [list $I(rect-basic) \ 231 | {selected disabled} $I(rect-basic) \ 232 | disabled $I(rect-basic) \ 233 | selected $I(rect-basic) \ 234 | pressed $I(rect-basic) \ 235 | active $I(rect-hover) \ 236 | ] -border 4 -sticky nsew 237 | 238 | # Toolbutton 239 | ttk::style configure Toolbutton -padding {8 4 8 4} -width -10 -anchor center 240 | 241 | ttk::style element create Toolbutton.button image \ 242 | [list $I(empty) \ 243 | {selected disabled} $I(empty) \ 244 | disabled $I(empty) \ 245 | selected $I(rect-basic) \ 246 | pressed $I(rect-basic) \ 247 | active $I(rect-basic) \ 248 | ] -border 4 -sticky nsew 249 | 250 | # Menubutton 251 | ttk::style configure TMenubutton -padding {8 4 4 4} 252 | 253 | ttk::style element create Menubutton.button image \ 254 | [list $I(rect-basic) \ 255 | disabled $I(rect-basic) \ 256 | pressed $I(rect-basic) \ 257 | active $I(rect-hover) \ 258 | ] -border 4 -sticky nsew 259 | 260 | ttk::style element create Menubutton.indicator image \ 261 | [list $I(down) \ 262 | active $I(down) \ 263 | pressed $I(down) \ 264 | disabled $I(down) \ 265 | ] -width 15 -sticky e 266 | 267 | # OptionMenu 268 | ttk::style configure TOptionMenu -padding {8 4 4 4} 269 | 270 | ttk::style element create OptionMenu.button image \ 271 | [list $I(rect-basic) \ 272 | disabled $I(rect-basic) \ 273 | pressed $I(rect-basic) \ 274 | active $I(rect-hover) \ 275 | ] -border 4 -sticky nsew 276 | 277 | ttk::style element create OptionMenu.indicator image \ 278 | [list $I(down) \ 279 | active $I(down) \ 280 | pressed $I(down) \ 281 | disabled $I(down) \ 282 | ] -width 15 -sticky e 283 | 284 | # AccentButton 285 | ttk::style configure Accent.TButton -padding {8 4 8 4} -width -10 -anchor center -foreground #eeeeee 286 | 287 | ttk::style element create AccentButton.button image \ 288 | [list $I(rect-accent) \ 289 | {selected disabled} $I(rect-accent-hover) \ 290 | disabled $I(rect-accent-hover) \ 291 | selected $I(rect-accent) \ 292 | pressed $I(rect-accent) \ 293 | active $I(rect-accent-hover) \ 294 | ] -border 4 -sticky nsew 295 | 296 | # Checkbutton 297 | ttk::style configure TCheckbutton -padding 4 298 | 299 | ttk::style element create Checkbutton.indicator image \ 300 | [list $I(check-unsel-accent) \ 301 | {alternate disabled} $I(check-tri-basic) \ 302 | {selected disabled} $I(check-basic) \ 303 | disabled $I(check-unsel-basic) \ 304 | {pressed alternate} $I(check-tri-hover) \ 305 | {active alternate} $I(check-tri-hover) \ 306 | alternate $I(check-tri-accent) \ 307 | {pressed selected} $I(check-hover) \ 308 | {active selected} $I(check-hover) \ 309 | selected $I(check-accent) \ 310 | {pressed !selected} $I(check-unsel-pressed) \ 311 | active $I(check-unsel-hover) \ 312 | ] -width 26 -sticky w 313 | 314 | # Switch 315 | ttk::style element create Switch.indicator image \ 316 | [list $I(off-accent) \ 317 | {selected disabled} $I(on-basic) \ 318 | disabled $I(off-basic) \ 319 | {pressed selected} $I(on-accent) \ 320 | {active selected} $I(on-hover) \ 321 | selected $I(on-accent) \ 322 | {pressed !selected} $I(off-accent) \ 323 | active $I(off-hover) \ 324 | ] -width 46 -sticky w 325 | 326 | # ToggleButton 327 | ttk::style configure ToggleButton -padding {8 4 8 4} -width -10 -anchor center 328 | 329 | ttk::style element create ToggleButton.button image \ 330 | [list $I(rect-basic) \ 331 | {selected disabled} $I(rect-accent-hover) \ 332 | disabled $I(rect-basic) \ 333 | {pressed selected} $I(rect-basic) \ 334 | {active selected} $I(rect-accent-hover) \ 335 | selected $I(rect-accent) \ 336 | {pressed !selected} $I(rect-accent) \ 337 | active $I(rect-hover) \ 338 | ] -border 4 -sticky nsew 339 | 340 | # Radiobutton 341 | ttk::style configure TRadiobutton -padding 4 342 | 343 | ttk::style element create Radiobutton.indicator image \ 344 | [list $I(radio-unsel-accent) \ 345 | {alternate disabled} $I(radio-tri-basic) \ 346 | {selected disabled} $I(radio-basic) \ 347 | disabled $I(radio-unsel-basic) \ 348 | {pressed alternate} $I(radio-tri-hover) \ 349 | {active alternate} $I(radio-tri-hover) \ 350 | alternate $I(radio-tri-accent) \ 351 | {pressed selected} $I(radio-hover) \ 352 | {active selected} $I(radio-hover) \ 353 | selected $I(radio-accent) \ 354 | {pressed !selected} $I(radio-unsel-pressed) \ 355 | active $I(radio-unsel-hover) \ 356 | ] -width 26 -sticky w 357 | 358 | # Scrollbar 359 | ttk::style element create Horizontal.Scrollbar.trough image $I(hor-basic) \ 360 | -sticky ew 361 | 362 | ttk::style element create Horizontal.Scrollbar.thumb image \ 363 | [list $I(hor-accent) \ 364 | disabled $I(hor-basic) \ 365 | pressed $I(hor-hover) \ 366 | active $I(hor-hover) \ 367 | ] -sticky ew 368 | 369 | ttk::style element create Vertical.Scrollbar.trough image $I(vert-basic) \ 370 | -sticky ns 371 | 372 | ttk::style element create Vertical.Scrollbar.thumb image \ 373 | [list $I(vert-accent) \ 374 | disabled $I(vert-basic) \ 375 | pressed $I(vert-hover) \ 376 | active $I(vert-hover) \ 377 | ] -sticky ns 378 | 379 | # Scale 380 | ttk::style element create Horizontal.Scale.trough image $I(scale-hor) \ 381 | -border 5 -padding 0 382 | 383 | ttk::style element create Horizontal.Scale.slider image \ 384 | [list $I(thumb-hor-accent) \ 385 | disabled $I(thumb-hor-basic) \ 386 | pressed $I(thumb-hor-hover) \ 387 | active $I(thumb-hor-hover) \ 388 | ] -sticky {} 389 | 390 | ttk::style element create Vertical.Scale.trough image $I(scale-vert) \ 391 | -border 5 -padding 0 392 | 393 | ttk::style element create Vertical.Scale.slider image \ 394 | [list $I(thumb-vert-accent) \ 395 | disabled $I(thumb-vert-basic) \ 396 | pressed $I(thumb-vert-hover) \ 397 | active $I(thumb-vert-hover) \ 398 | ] -sticky {} 399 | 400 | # Progressbar 401 | ttk::style element create Horizontal.Progressbar.trough image $I(hor-basic) \ 402 | -sticky ew 403 | 404 | ttk::style element create Horizontal.Progressbar.pbar image $I(hor-accent) \ 405 | -sticky ew 406 | 407 | ttk::style element create Vertical.Progressbar.trough image $I(vert-basic) \ 408 | -sticky ns 409 | 410 | ttk::style element create Vertical.Progressbar.pbar image $I(vert-accent) \ 411 | -sticky ns 412 | 413 | # Entry 414 | ttk::style element create Entry.field image \ 415 | [list $I(border-basic) \ 416 | {focus hover} $I(border-accent) \ 417 | invalid $I(border-invalid) \ 418 | disabled $I(border-basic) \ 419 | focus $I(border-accent) \ 420 | hover $I(border-hover) \ 421 | ] -border 5 -padding {8} -sticky nsew 422 | 423 | # Combobox 424 | ttk::style map TCombobox -selectbackground [list \ 425 | {!focus} $colors(-selectbg) \ 426 | {readonly hover} $colors(-selectbg) \ 427 | {readonly focus} $colors(-selectbg) \ 428 | ] 429 | 430 | ttk::style map TCombobox -selectforeground [list \ 431 | {!focus} $colors(-selectfg) \ 432 | {readonly hover} $colors(-selectfg) \ 433 | {readonly focus} $colors(-selectfg) \ 434 | ] 435 | 436 | ttk::style element create Combobox.field image \ 437 | [list $I(border-basic) \ 438 | {readonly disabled} $I(rect-basic) \ 439 | {readonly pressed} $I(rect-basic) \ 440 | {readonly focus hover} $I(rect-hover) \ 441 | {readonly focus} $I(rect-hover) \ 442 | {readonly hover} $I(rect-hover) \ 443 | {focus hover} $I(border-accent) \ 444 | readonly $I(rect-basic) \ 445 | invalid $I(border-invalid) \ 446 | disabled $I(border-basic) \ 447 | focus $I(border-accent) \ 448 | hover $I(border-hover) \ 449 | ] -border 5 -padding {8 8 28 8} 450 | 451 | ttk::style element create Combobox.button image \ 452 | [list $I(combo-button-basic) \ 453 | {!readonly focus} $I(combo-button-focus) \ 454 | {readonly focus} $I(combo-button-hover) \ 455 | {readonly hover} $I(combo-button-hover) 456 | ] -border 5 -padding {2 6 6 6} 457 | 458 | ttk::style element create Combobox.arrow image $I(down) -width 15 -sticky e 459 | 460 | # Spinbox 461 | ttk::style element create Spinbox.field image \ 462 | [list $I(border-basic) \ 463 | invalid $I(border-invalid) \ 464 | disabled $I(border-basic) \ 465 | focus $I(border-accent) \ 466 | hover $I(border-hover) \ 467 | ] -border 5 -padding {8 8 54 8} -sticky nsew 468 | 469 | ttk::style element create Spinbox.uparrow image $I(spin-button-up) -border 4 -sticky nsew 470 | 471 | ttk::style element create Spinbox.downarrow image \ 472 | [list $I(spin-button-down-basic) \ 473 | focus $I(spin-button-down-focus) \ 474 | ] -border 4 -sticky nsew 475 | 476 | ttk::style element create Spinbox.symuparrow image $I(up) -width 15 -sticky {} 477 | ttk::style element create Spinbox.symdownarrow image $I(down) -width 17 -sticky {} 478 | 479 | # Sizegrip 480 | ttk::style element create Sizegrip.sizegrip image $I(sizegrip) \ 481 | -sticky nsew 482 | 483 | # Separator 484 | ttk::style element create Horizontal.separator image $I(separator) 485 | 486 | ttk::style element create Vertical.separator image $I(separator) 487 | 488 | # Card 489 | ttk::style element create Card.field image $I(card) \ 490 | -border 10 -padding 4 -sticky nsew 491 | 492 | # Labelframe 493 | ttk::style element create Labelframe.border image $I(card) \ 494 | -border 5 -padding 4 -sticky nsew 495 | 496 | # Notebook 497 | ttk::style configure TNotebook -padding 2 498 | 499 | ttk::style element create Notebook.border image $I(card) -border 5 500 | 501 | ttk::style element create Notebook.client image $I(notebook) -border 5 502 | 503 | ttk::style element create Notebook.tab image \ 504 | [list $I(tab-basic) \ 505 | selected $I(tab-accent) \ 506 | active $I(tab-hover) \ 507 | ] -border 5 -padding {14 4} 508 | 509 | # Treeview 510 | ttk::style element create Treeview.field image $I(card) \ 511 | -border 5 512 | 513 | ttk::style element create Treeheading.cell image \ 514 | [list $I(tree-basic) \ 515 | pressed $I(tree-pressed) 516 | ] -border 5 -padding 6 -sticky nsew 517 | 518 | ttk::style element create Treeitem.indicator image \ 519 | [list $I(right) \ 520 | user2 $I(empty) \ 521 | user1 $I(down) \ 522 | ] -width 17 -sticky {} 523 | 524 | ttk::style configure Treeview -background $colors(-bg) 525 | ttk::style configure Treeview.Item -padding {2 0 0 0} 526 | 527 | ttk::style map Treeview \ 528 | -background [list selected $colors(-selectbg)] \ 529 | -foreground [list selected $colors(-selectfg)] 530 | 531 | # Sashes 532 | #ttk::style map TPanedwindow -background [list hover $colors(-bg)] 533 | } 534 | } 535 | -------------------------------------------------------------------------------- /forest-light.tcl: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 rdbende 2 | 3 | # The Forest theme is a beautiful and modern ttk theme inspired by Excel. 4 | 5 | package require Tk 8.6 6 | 7 | namespace eval ttk::theme::forest-light { 8 | 9 | variable version 1.0 10 | package provide ttk::theme::forest-light $version 11 | variable colors 12 | array set colors { 13 | -fg "#313131" 14 | -bg "#ffffff" 15 | -disabledfg "#595959" 16 | -disabledbg "#ffffff" 17 | -selectfg "#ffffff" 18 | -selectbg "#217346" 19 | } 20 | 21 | proc LoadImages {imgdir} { 22 | variable I 23 | foreach file [glob -directory $imgdir *.png] { 24 | set img [file tail [file rootname $file]] 25 | set I($img) [image create photo -file $file -format png] 26 | } 27 | } 28 | 29 | LoadImages [file join [file dirname [info script]] forest-light] 30 | 31 | # Settings 32 | ttk::style theme create forest-light -parent default -settings { 33 | ttk::style configure . \ 34 | -background $colors(-bg) \ 35 | -foreground $colors(-fg) \ 36 | -troughcolor $colors(-bg) \ 37 | -focuscolor $colors(-selectbg) \ 38 | -selectbackground $colors(-selectbg) \ 39 | -selectforeground $colors(-selectfg) \ 40 | -insertwidth 1 \ 41 | -insertcolor $colors(-fg) \ 42 | -fieldbackground $colors(-selectbg) \ 43 | -font {TkDefaultFont 10} \ 44 | -borderwidth 1 \ 45 | -relief flat 46 | 47 | ttk::style map . -foreground [list disabled $colors(-disabledfg)] 48 | 49 | tk_setPalette background [ttk::style lookup . -background] \ 50 | foreground [ttk::style lookup . -foreground] \ 51 | highlightColor [ttk::style lookup . -focuscolor] \ 52 | selectBackground [ttk::style lookup . -selectbackground] \ 53 | selectForeground [ttk::style lookup . -selectforeground] \ 54 | activeBackground [ttk::style lookup . -selectbackground] \ 55 | activeForeground [ttk::style lookup . -selectforeground] 56 | 57 | option add *font [ttk::style lookup . -font] 58 | 59 | 60 | # Layouts 61 | ttk::style layout TButton { 62 | Button.button -children { 63 | Button.padding -children { 64 | Button.label -side left -expand true 65 | } 66 | } 67 | } 68 | 69 | ttk::style layout Toolbutton { 70 | Toolbutton.button -children { 71 | Toolbutton.padding -children { 72 | Toolbutton.label -side left -expand true 73 | } 74 | } 75 | } 76 | 77 | ttk::style layout TMenubutton { 78 | Menubutton.button -children { 79 | Menubutton.padding -children { 80 | Menubutton.indicator -side right 81 | Menubutton.label -side right -expand true 82 | } 83 | } 84 | } 85 | 86 | ttk::style layout TOptionMenu { 87 | OptionMenu.button -children { 88 | OptionMenu.padding -children { 89 | OptionMenu.indicator -side right 90 | OptionMenu.label -side right -expand true 91 | } 92 | } 93 | } 94 | 95 | ttk::style layout Accent.TButton { 96 | AccentButton.button -children { 97 | AccentButton.padding -children { 98 | AccentButton.label -side left -expand true 99 | } 100 | } 101 | } 102 | 103 | ttk::style layout TCheckbutton { 104 | Checkbutton.button -children { 105 | Checkbutton.padding -children { 106 | Checkbutton.indicator -side left 107 | Checkbutton.label -side right -expand true 108 | } 109 | } 110 | } 111 | 112 | ttk::style layout Switch { 113 | Switch.button -children { 114 | Switch.padding -children { 115 | Switch.indicator -side left 116 | Switch.label -side right -expand true 117 | } 118 | } 119 | } 120 | 121 | ttk::style layout ToggleButton { 122 | ToggleButton.button -children { 123 | ToggleButton.padding -children { 124 | ToggleButton.label -side left -expand true 125 | } 126 | } 127 | } 128 | 129 | ttk::style layout TRadiobutton { 130 | Radiobutton.button -children { 131 | Radiobutton.padding -children { 132 | Radiobutton.indicator -side left 133 | Radiobutton.label -side right -expand true 134 | } 135 | } 136 | } 137 | 138 | ttk::style layout Vertical.TScrollbar { 139 | Vertical.Scrollbar.trough -sticky ns -children { 140 | Vertical.Scrollbar.thumb -expand true 141 | } 142 | } 143 | 144 | ttk::style layout Horizontal.TScrollbar { 145 | Horizontal.Scrollbar.trough -sticky ew -children { 146 | Horizontal.Scrollbar.thumb -expand true 147 | } 148 | } 149 | 150 | ttk::style layout TCombobox { 151 | Combobox.field -sticky nswe -children { 152 | Combobox.padding -expand true -sticky nswe -children { 153 | Combobox.textarea -sticky nswe 154 | } 155 | } 156 | Combobox.button -side right -sticky ns -children { 157 | Combobox.arrow -sticky nsew 158 | } 159 | } 160 | 161 | ttk::style layout TSpinbox { 162 | Spinbox.field -sticky nsew -children { 163 | Spinbox.padding -expand true -sticky nswe -children { 164 | Spinbox.textarea -sticky nsew 165 | } 166 | 167 | } 168 | null -side right -sticky nsew -children { 169 | Spinbox.uparrow -side right -sticky nsew -children { 170 | Spinbox.symuparrow 171 | } 172 | Spinbox.downarrow -side left -sticky nsew -children { 173 | Spinbox.symdownarrow 174 | } 175 | } 176 | } 177 | 178 | ttk::style layout Horizontal.TSeparator { 179 | Horizontal.separator -sticky nswe 180 | } 181 | 182 | ttk::style layout Vertical.TSeparator { 183 | Vertical.separator -sticky nswe 184 | } 185 | 186 | ttk::style layout Card { 187 | Card.field { 188 | Card.padding -expand 1 189 | } 190 | } 191 | 192 | ttk::style layout TLabelframe { 193 | Labelframe.border { 194 | Labelframe.padding -expand 1 -children { 195 | Labelframe.label -side left 196 | } 197 | } 198 | } 199 | 200 | ttk::style layout TNotebook { 201 | Notebook.border -children { 202 | TNotebook.Tab -expand 1 -side top 203 | Notebook.client -sticky nsew 204 | } 205 | } 206 | 207 | ttk::style layout TNotebook.Tab { 208 | Notebook.tab -children { 209 | Notebook.padding -side top -children { 210 | Notebook.label 211 | } 212 | } 213 | } 214 | 215 | ttk::style layout Treeview.Item { 216 | Treeitem.padding -sticky nswe -children { 217 | Treeitem.indicator -side left -sticky {} 218 | Treeitem.image -side left -sticky {} 219 | Treeitem.text -side left -sticky {} 220 | } 221 | } 222 | 223 | 224 | # Elements 225 | 226 | # Button 227 | ttk::style configure TButton -padding {8 4 8 4} -width -10 -anchor center 228 | 229 | ttk::style element create Button.button image \ 230 | [list $I(rect-basic) \ 231 | {selected disabled} $I(rect-basic) \ 232 | disabled $I(rect-basic) \ 233 | selected $I(rect-basic) \ 234 | pressed $I(rect-basic) \ 235 | active $I(rect-hover) \ 236 | ] -border 4 -sticky nsew 237 | 238 | # Toolbutton 239 | ttk::style configure Toolbutton -padding {8 4 8 4} -width -10 -anchor center 240 | 241 | ttk::style element create Toolbutton.button image \ 242 | [list $I(empty) \ 243 | {selected disabled} $I(empty) \ 244 | disabled $I(empty) \ 245 | selected $I(rect-basic) \ 246 | pressed $I(rect-basic) \ 247 | active $I(rect-basic) \ 248 | ] -border 4 -sticky nsew 249 | 250 | # Menubutton 251 | ttk::style configure TMenubutton -padding {8 4 4 4} 252 | 253 | ttk::style element create Menubutton.button image \ 254 | [list $I(rect-basic) \ 255 | disabled $I(rect-basic) \ 256 | pressed $I(rect-basic) \ 257 | active $I(rect-hover) \ 258 | ] -border 4 -sticky nsew 259 | 260 | ttk::style element create Menubutton.indicator image \ 261 | [list $I(down) \ 262 | active $I(down) \ 263 | pressed $I(down) \ 264 | disabled $I(down) \ 265 | ] -width 15 -sticky e 266 | 267 | # OptionMenu 268 | ttk::style configure TOptionMenu -padding {8 4 4 4} 269 | 270 | ttk::style element create OptionMenu.button image \ 271 | [list $I(rect-basic) \ 272 | disabled $I(rect-basic) \ 273 | pressed $I(rect-basic) \ 274 | active $I(rect-hover) \ 275 | ] -border 4 -sticky nsew 276 | 277 | ttk::style element create OptionMenu.indicator image \ 278 | [list $I(down) \ 279 | active $I(down) \ 280 | pressed $I(down) \ 281 | disabled $I(down) \ 282 | ] -width 15 -sticky e 283 | 284 | # AccentButton 285 | ttk::style configure Accent.TButton -padding {8 4 8 4} -width -10 -anchor center -foreground #eeeeee 286 | 287 | ttk::style element create AccentButton.button image \ 288 | [list $I(rect-accent) \ 289 | {selected disabled} $I(rect-accent-hover) \ 290 | disabled $I(rect-accent-hover) \ 291 | selected $I(rect-accent) \ 292 | pressed $I(rect-accent) \ 293 | active $I(rect-accent-hover) \ 294 | ] -border 4 -sticky nsew 295 | 296 | # Checkbutton 297 | ttk::style configure TCheckbutton -padding 4 298 | 299 | ttk::style element create Checkbutton.indicator image \ 300 | [list $I(check-unsel-accent) \ 301 | {alternate disabled} $I(check-tri-basic) \ 302 | {selected disabled} $I(check-basic) \ 303 | disabled $I(check-unsel-basic) \ 304 | {pressed alternate} $I(check-tri-hover) \ 305 | {active alternate} $I(check-tri-hover) \ 306 | alternate $I(check-tri-accent) \ 307 | {pressed selected} $I(check-hover) \ 308 | {active selected} $I(check-hover) \ 309 | selected $I(check-accent) \ 310 | {pressed !selected} $I(check-unsel-pressed) \ 311 | active $I(check-unsel-hover) \ 312 | ] -width 26 -sticky w 313 | 314 | # Switch 315 | ttk::style element create Switch.indicator image \ 316 | [list $I(off-accent) \ 317 | {selected disabled} $I(on-basic) \ 318 | disabled $I(off-basic) \ 319 | {pressed selected} $I(on-accent) \ 320 | {active selected} $I(on-hover) \ 321 | selected $I(on-accent) \ 322 | {pressed !selected} $I(off-accent) \ 323 | active $I(off-hover) \ 324 | ] -width 46 -sticky w 325 | 326 | # ToggleButton 327 | ttk::style configure ToggleButton -padding {8 4 8 4} -width -10 -anchor center -foregound $colors(-fg) 328 | 329 | ttk::style map ToggleButton -foreground \ 330 | [list {pressed selected} $colors(-fg) \ 331 | {pressed !selected} #ffffff \ 332 | selected #ffffff] 333 | 334 | ttk::style element create ToggleButton.button image \ 335 | [list $I(rect-basic) \ 336 | {selected disabled} $I(rect-accent-hover) \ 337 | disabled $I(rect-basic) \ 338 | {pressed selected} $I(rect-basic) \ 339 | {active selected} $I(rect-accent-hover) \ 340 | selected $I(rect-accent) \ 341 | {pressed !selected} $I(rect-accent) \ 342 | active $I(rect-hover) \ 343 | ] -border 4 -sticky nsew 344 | 345 | # Radiobutton 346 | ttk::style configure TRadiobutton -padding 4 347 | 348 | ttk::style element create Radiobutton.indicator image \ 349 | [list $I(radio-unsel-accent) \ 350 | {alternate disabled} $I(radio-tri-basic) \ 351 | {selected disabled} $I(radio-basic) \ 352 | disabled $I(radio-unsel-basic) \ 353 | {pressed alternate} $I(radio-tri-hover) \ 354 | {active alternate} $I(radio-tri-hover) \ 355 | alternate $I(radio-tri-accent) \ 356 | {pressed selected} $I(radio-hover) \ 357 | {active selected} $I(radio-hover) \ 358 | selected $I(radio-accent) \ 359 | {pressed !selected} $I(radio-unsel-pressed) \ 360 | active $I(radio-unsel-hover) \ 361 | ] -width 26 -sticky w 362 | 363 | # Scrollbar 364 | ttk::style element create Horizontal.Scrollbar.trough image $I(hor-basic) \ 365 | -sticky ew 366 | 367 | ttk::style element create Horizontal.Scrollbar.thumb image \ 368 | [list $I(hor-accent) \ 369 | disabled $I(hor-basic) \ 370 | pressed $I(hor-hover) \ 371 | active $I(hor-hover) \ 372 | ] -sticky ew 373 | 374 | ttk::style element create Vertical.Scrollbar.trough image $I(vert-basic) \ 375 | -sticky ns 376 | 377 | ttk::style element create Vertical.Scrollbar.thumb image \ 378 | [list $I(vert-accent) \ 379 | disabled $I(vert-basic) \ 380 | pressed $I(vert-hover) \ 381 | active $I(vert-hover) \ 382 | ] -sticky ns 383 | 384 | # Scale 385 | ttk::style element create Horizontal.Scale.trough image $I(scale-hor) \ 386 | -border 5 -padding 0 387 | 388 | ttk::style element create Horizontal.Scale.slider image \ 389 | [list $I(thumb-hor-accent) \ 390 | disabled $I(thumb-hor-basic) \ 391 | pressed $I(thumb-hor-hover) \ 392 | active $I(thumb-hor-hover) \ 393 | ] -sticky {} 394 | 395 | ttk::style element create Vertical.Scale.trough image $I(scale-vert) \ 396 | -border 5 -padding 0 397 | 398 | ttk::style element create Vertical.Scale.slider image \ 399 | [list $I(thumb-vert-accent) \ 400 | disabled $I(thumb-vert-basic) \ 401 | pressed $I(thumb-vert-hover) \ 402 | active $I(thumb-vert-hover) \ 403 | ] -sticky {} 404 | 405 | # Progressbar 406 | ttk::style element create Horizontal.Progressbar.trough image $I(hor-basic) \ 407 | -sticky ew 408 | 409 | ttk::style element create Horizontal.Progressbar.pbar image $I(hor-accent) \ 410 | -sticky ew 411 | 412 | ttk::style element create Vertical.Progressbar.trough image $I(vert-basic) \ 413 | -sticky ns 414 | 415 | ttk::style element create Vertical.Progressbar.pbar image $I(vert-accent) \ 416 | -sticky ns 417 | 418 | # Entry 419 | ttk::style element create Entry.field image \ 420 | [list $I(border-basic) \ 421 | {focus hover} $I(border-accent) \ 422 | invalid $I(border-invalid) \ 423 | disabled $I(border-basic) \ 424 | focus $I(border-accent) \ 425 | hover $I(border-hover) \ 426 | ] -border 5 -padding {8} -sticky nsew 427 | 428 | # Combobox 429 | ttk::style map TCombobox -selectbackground [list \ 430 | {!focus} $colors(-selectbg) \ 431 | {readonly hover} $colors(-selectbg) \ 432 | {readonly focus} $colors(-selectbg) \ 433 | ] 434 | 435 | ttk::style map TCombobox -selectforeground [list \ 436 | {!focus} $colors(-selectfg) \ 437 | {readonly hover} $colors(-selectfg) \ 438 | {readonly focus} $colors(-selectfg) \ 439 | ] 440 | 441 | ttk::style element create Combobox.field image \ 442 | [list $I(border-basic) \ 443 | {readonly disabled} $I(rect-basic) \ 444 | {readonly pressed} $I(rect-basic) \ 445 | {readonly focus hover} $I(rect-hover) \ 446 | {readonly focus} $I(rect-hover) \ 447 | {readonly hover} $I(rect-hover) \ 448 | {focus hover} $I(border-accent) \ 449 | readonly $I(rect-basic) \ 450 | invalid $I(border-invalid) \ 451 | disabled $I(border-basic) \ 452 | focus $I(border-accent) \ 453 | hover $I(border-hover) \ 454 | ] -border 5 -padding {8 8 28 8} 455 | 456 | ttk::style element create Combobox.button image \ 457 | [list $I(combo-button-basic) \ 458 | {!readonly focus} $I(combo-button-focus) \ 459 | {readonly focus} $I(combo-button-hover) \ 460 | {readonly hover} $I(combo-button-hover) 461 | ] -border 5 -padding {2 6 6 6} 462 | 463 | ttk::style element create Combobox.arrow image $I(down) -width 15 -sticky e 464 | 465 | # Spinbox 466 | ttk::style element create Spinbox.field image \ 467 | [list $I(border-basic) \ 468 | invalid $I(border-invalid) \ 469 | disabled $I(border-basic) \ 470 | focus $I(border-accent) \ 471 | hover $I(border-hover) \ 472 | ] -border 5 -padding {8 8 54 8} -sticky nsew 473 | 474 | ttk::style element create Spinbox.uparrow image $I(spin-button-up) -border 4 -sticky nsew 475 | 476 | ttk::style element create Spinbox.downarrow image \ 477 | [list $I(spin-button-down-basic) \ 478 | focus $I(spin-button-down-focus) \ 479 | ] -border 4 -sticky nsew 480 | 481 | ttk::style element create Spinbox.symuparrow image $I(up) -width 15 -sticky {} 482 | ttk::style element create Spinbox.symdownarrow image $I(down) -width 17 -sticky {} 483 | 484 | # Sizegrip 485 | ttk::style element create Sizegrip.sizegrip image $I(sizegrip) \ 486 | -sticky nsew 487 | 488 | # Separator 489 | ttk::style element create Horizontal.separator image $I(separator) 490 | 491 | ttk::style element create Vertical.separator image $I(separator) 492 | 493 | # Card 494 | ttk::style element create Card.field image $I(card) \ 495 | -border 10 -padding 4 -sticky nsew 496 | 497 | # Labelframe 498 | ttk::style element create Labelframe.border image $I(card) \ 499 | -border 5 -padding 4 -sticky nsew 500 | 501 | # Notebook 502 | ttk::style configure TNotebook -padding 2 503 | 504 | ttk::style element create Notebook.border image $I(card) -border 5 505 | 506 | ttk::style element create Notebook.client image $I(notebook) -border 5 507 | 508 | ttk::style element create Notebook.tab image \ 509 | [list $I(tab-basic) \ 510 | selected $I(tab-accent) \ 511 | active $I(tab-hover) \ 512 | ] -border 5 -padding {14 4} 513 | 514 | # Treeview 515 | ttk::style element create Treeview.field image $I(card) \ 516 | -border 5 517 | 518 | ttk::style element create Treeheading.cell image \ 519 | [list $I(tree-basic) \ 520 | pressed $I(tree-pressed) 521 | ] -border 5 -padding 6 -sticky nsew 522 | 523 | ttk::style element create Treeitem.indicator image \ 524 | [list $I(right) \ 525 | user2 $I(empty) \ 526 | {user1 focus} $I(down-focus) \ 527 | focus $I(right-focus) \ 528 | user1 $I(down) \ 529 | ] -width 17 -sticky {} 530 | 531 | ttk::style configure Treeview -background $colors(-bg) 532 | ttk::style configure Treeview.Item -padding {2 0 0 0} 533 | 534 | ttk::style map Treeview \ 535 | -background [list selected $colors(-selectbg)] \ 536 | -foreground [list selected $colors(-selectfg)] 537 | 538 | # Sashes 539 | #ttk::style map TPanedwindow -background [list hover $colors(-bg)] 540 | } 541 | } 542 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from tkinter import ttk 3 | import openpyxl 4 | 5 | 6 | def load_data(): 7 | path = "D:\codefirst.io\Tkinter Excel App\people.xlsx" 8 | workbook = openpyxl.load_workbook(path) 9 | sheet = workbook.active 10 | 11 | list_values = list(sheet.values) 12 | print(list_values) 13 | for col_name in list_values[0]: 14 | treeview.heading(col_name, text=col_name) 15 | 16 | for value_tuple in list_values[1:]: 17 | treeview.insert('', tk.END, values=value_tuple) 18 | 19 | 20 | def insert_row(): 21 | name = name_entry.get() 22 | age = int(age_spinbox.get()) 23 | subscription_status = status_combobox.get() 24 | employment_status = "Employed" if a.get() else "Unemployed" 25 | 26 | print(name, age, subscription_status, employment_status) 27 | 28 | # Insert row into Excel sheet 29 | path = "D:\codefirst.io\Tkinter Excel App\people.xlsx" 30 | workbook = openpyxl.load_workbook(path) 31 | sheet = workbook.active 32 | row_values = [name, age, subscription_status, employment_status] 33 | sheet.append(row_values) 34 | workbook.save(path) 35 | 36 | # Insert row into treeview 37 | treeview.insert('', tk.END, values=row_values) 38 | 39 | # Clear the values 40 | name_entry.delete(0, "end") 41 | name_entry.insert(0, "Name") 42 | age_spinbox.delete(0, "end") 43 | age_spinbox.insert(0, "Age") 44 | status_combobox.set(combo_list[0]) 45 | checkbutton.state(["!selected"]) 46 | 47 | 48 | 49 | 50 | def toggle_mode(): 51 | if mode_switch.instate(["selected"]): 52 | style.theme_use("forest-light") 53 | else: 54 | style.theme_use("forest-dark") 55 | 56 | root = tk.Tk() 57 | 58 | style = ttk.Style(root) 59 | root.tk.call("source", "forest-light.tcl") 60 | root.tk.call("source", "forest-dark.tcl") 61 | style.theme_use("forest-dark") 62 | 63 | combo_list = ["Subscribed", "Not Subscribed", "Other"] 64 | 65 | frame = ttk.Frame(root) 66 | frame.pack() 67 | 68 | widgets_frame = ttk.LabelFrame(frame, text="Insert Row") 69 | widgets_frame.grid(row=0, column=0, padx=20, pady=10) 70 | 71 | name_entry = ttk.Entry(widgets_frame) 72 | name_entry.insert(0, "Name") 73 | name_entry.bind("", lambda e: name_entry.delete('0', 'end')) 74 | name_entry.grid(row=0, column=0, padx=5, pady=(0, 5), sticky="ew") 75 | 76 | age_spinbox = ttk.Spinbox(widgets_frame, from_=18, to=100) 77 | age_spinbox.insert(0, "Age") 78 | age_spinbox.grid(row=1, column=0, padx=5, pady=5, sticky="ew") 79 | 80 | status_combobox = ttk.Combobox(widgets_frame, values=combo_list) 81 | status_combobox.current(0) 82 | status_combobox.grid(row=2, column=0, padx=5, pady=5, sticky="ew") 83 | 84 | a = tk.BooleanVar() 85 | checkbutton = ttk.Checkbutton(widgets_frame, text="Employed", variable=a) 86 | checkbutton.grid(row=3, column=0, padx=5, pady=5, sticky="nsew") 87 | 88 | button = ttk.Button(widgets_frame, text="Insert", command=insert_row) 89 | button.grid(row=4, column=0, padx=5, pady=5, sticky="nsew") 90 | 91 | separator = ttk.Separator(widgets_frame) 92 | separator.grid(row=5, column=0, padx=(20, 10), pady=10, sticky="ew") 93 | 94 | mode_switch = ttk.Checkbutton( 95 | widgets_frame, text="Mode", style="Switch", command=toggle_mode) 96 | mode_switch.grid(row=6, column=0, padx=5, pady=10, sticky="nsew") 97 | 98 | treeFrame = ttk.Frame(frame) 99 | treeFrame.grid(row=0, column=1, pady=10) 100 | treeScroll = ttk.Scrollbar(treeFrame) 101 | treeScroll.pack(side="right", fill="y") 102 | 103 | cols = ("Name", "Age", "Subscription", "Employment") 104 | treeview = ttk.Treeview(treeFrame, show="headings", 105 | yscrollcommand=treeScroll.set, columns=cols, height=13) 106 | treeview.column("Name", width=100) 107 | treeview.column("Age", width=50) 108 | treeview.column("Subscription", width=100) 109 | treeview.column("Employment", width=100) 110 | treeview.pack() 111 | treeScroll.config(command=treeview.yview) 112 | load_data() 113 | 114 | 115 | root.mainloop() 116 | -------------------------------------------------------------------------------- /people.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codefirstio/tkinter-excel-app/faf3cbcd0341ef78983a1e465f17e040071a45c6/people.xlsx --------------------------------------------------------------------------------