aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--README.md24
-rw-r--r--assets/most-accurate-test.pngbin0 -> 1866900 bytes
-rw-r--r--assets/myers-briggs-type-indicator.pngbin0 -> 1991881 bytes
-rw-r--r--assets/ptypes/ENFJ1.pngbin0 -> 2872041 bytes
-rw-r--r--assets/ptypes/ENFJ2.pngbin0 -> 2512192 bytes
-rw-r--r--assets/ptypes/ENFJ3.pngbin0 -> 2679985 bytes
-rw-r--r--assets/ptypes/ENFP1.pngbin0 -> 2869187 bytes
-rw-r--r--assets/ptypes/ENFP2.pngbin0 -> 2486030 bytes
-rw-r--r--assets/ptypes/ENFP3.pngbin0 -> 2718904 bytes
-rw-r--r--assets/ptypes/ENTJ1.pngbin0 -> 2807317 bytes
-rw-r--r--assets/ptypes/ENTJ2.pngbin0 -> 2506196 bytes
-rw-r--r--assets/ptypes/ENTJ3.pngbin0 -> 2701728 bytes
-rw-r--r--assets/ptypes/ENTP1.pngbin0 -> 2886415 bytes
-rw-r--r--assets/ptypes/ENTP2.pngbin0 -> 2503483 bytes
-rw-r--r--assets/ptypes/ENTP3.pngbin0 -> 2742121 bytes
-rw-r--r--assets/ptypes/ESFJ1.pngbin0 -> 2823146 bytes
-rw-r--r--assets/ptypes/ESFJ2.pngbin0 -> 2485077 bytes
-rw-r--r--assets/ptypes/ESFJ3.pngbin0 -> 2792487 bytes
-rw-r--r--assets/ptypes/ESFP1.pngbin0 -> 2850826 bytes
-rw-r--r--assets/ptypes/ESFP2.pngbin0 -> 2557827 bytes
-rw-r--r--assets/ptypes/ESFP3.pngbin0 -> 2731584 bytes
-rw-r--r--assets/ptypes/ESTJ1.pngbin0 -> 2850233 bytes
-rw-r--r--assets/ptypes/ESTJ2.pngbin0 -> 2521830 bytes
-rw-r--r--assets/ptypes/ESTJ3.pngbin0 -> 2644923 bytes
-rw-r--r--assets/ptypes/ESTP1.pngbin0 -> 2839452 bytes
-rw-r--r--assets/ptypes/ESTP2.pngbin0 -> 2502733 bytes
-rw-r--r--assets/ptypes/ESTP3.pngbin0 -> 2783233 bytes
-rw-r--r--assets/ptypes/INFJ1.pngbin0 -> 2905320 bytes
-rw-r--r--assets/ptypes/INFJ2.pngbin0 -> 2468520 bytes
-rw-r--r--assets/ptypes/INFJ3.pngbin0 -> 2726341 bytes
-rw-r--r--assets/ptypes/INFP1.pngbin0 -> 2826953 bytes
-rw-r--r--assets/ptypes/INFP2.pngbin0 -> 2510158 bytes
-rw-r--r--assets/ptypes/INFP3.pngbin0 -> 2683299 bytes
-rw-r--r--assets/ptypes/INTJ1.pngbin0 -> 2902965 bytes
-rw-r--r--assets/ptypes/INTJ1a.pngbin0 -> 2927513 bytes
-rw-r--r--assets/ptypes/INTJ2.pngbin0 -> 2585781 bytes
-rw-r--r--assets/ptypes/INTJ3.pngbin0 -> 2695543 bytes
-rw-r--r--assets/ptypes/INTP1.pngbin0 -> 2810165 bytes
-rw-r--r--assets/ptypes/INTP2.pngbin0 -> 2459104 bytes
-rw-r--r--assets/ptypes/INTP3.pngbin0 -> 2721620 bytes
-rw-r--r--assets/ptypes/ISFJ1.pngbin0 -> 2887111 bytes
-rw-r--r--assets/ptypes/ISFJ2.pngbin0 -> 2556213 bytes
-rw-r--r--assets/ptypes/ISFJ3.pngbin0 -> 2771930 bytes
-rw-r--r--assets/ptypes/ISFP1.pngbin0 -> 2866015 bytes
-rw-r--r--assets/ptypes/ISFP2.pngbin0 -> 2507054 bytes
-rw-r--r--assets/ptypes/ISFP3.pngbin0 -> 2707965 bytes
-rw-r--r--assets/ptypes/ISTJ1.pngbin0 -> 2794189 bytes
-rw-r--r--assets/ptypes/ISTJ2.pngbin0 -> 2503150 bytes
-rw-r--r--assets/ptypes/ISTJ3.pngbin0 -> 2683103 bytes
-rw-r--r--assets/ptypes/ISTP1.pngbin0 -> 2853654 bytes
-rw-r--r--assets/ptypes/ISTP2.pngbin0 -> 2460804 bytes
-rw-r--r--assets/ptypes/ISTP3.pngbin0 -> 2702652 bytes
-rw-r--r--assets/quiz/Q-13.pngbin0 -> 39627 bytes
-rw-r--r--assets/quiz/Q00.pngbin0 -> 2482773 bytes
-rw-r--r--assets/quiz/Q01.pngbin0 -> 2276983 bytes
-rw-r--r--assets/quiz/Q02.pngbin0 -> 2013296 bytes
-rw-r--r--assets/quiz/Q03.pngbin0 -> 1041543 bytes
-rw-r--r--assets/quiz/Q10.pngbin0 -> 2300678 bytes
-rw-r--r--assets/quiz/Q11.pngbin0 -> 2079170 bytes
-rw-r--r--assets/quiz/Q12.pngbin0 -> 1792181 bytes
-rw-r--r--assets/quiz/Q13.pngbin0 -> 688809 bytes
-rw-r--r--assets/quiz/Q20.pngbin0 -> 2923834 bytes
-rw-r--r--assets/quiz/Q21.pngbin0 -> 1975917 bytes
-rw-r--r--assets/quiz/Q22.pngbin0 -> 1648591 bytes
-rw-r--r--assets/quiz/Q23.pngbin0 -> 517435 bytes
-rw-r--r--assets/quiz/Q30.pngbin0 -> 2410321 bytes
-rw-r--r--assets/quiz/Q31.pngbin0 -> 2046644 bytes
-rw-r--r--assets/quiz/Q32.pngbin0 -> 1739417 bytes
-rw-r--r--assets/quiz/Q33.pngbin0 -> 525468 bytes
-rw-r--r--assets/short-version.jpgbin0 -> 526865 bytes
-rw-r--r--assets/types.pngbin0 -> 446487 bytes
-rw-r--r--frames.py405
-rw-r--r--main.py80
-rw-r--r--requirements.txt2
-rw-r--r--test/README.txt1
-rw-r--r--test/database.py36
-rw-r--r--test/double-click.py34
-rw-r--r--test/fill-vs-expand.py11
-rw-r--r--test/fixratio.py33
-rw-r--r--test/frames.py16
-rw-r--r--test/logs.py63
-rw-r--r--test/optionmenu.py30
-rw-r--r--test/overlapping-widgets.py33
-rw-r--r--test/placeholder.py24
-rw-r--r--test/ptest.sql53
-rw-r--r--test/resizable-image.py84
-rw-r--r--test/table.py49
-rw-r--r--widgets.py97
89 files changed, 1076 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bee8a64
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+__pycache__
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b071795
--- /dev/null
+++ b/README.md
@@ -0,0 +1,24 @@
+# Personality Test
+
+This was my first year's end term university project. This is not complete or featurefull but it intended to serve as a memory for me. It was an interesting idea back then none the less.
+
+This application presents a quiz containing 4 question that test your personality.
+
+## Install
+
+1. Clone this repository or download the source files on your local machine.
+2. Install the required dependencies
+ - `pillow`
+ - `mariadb-connector`
+ - `tkinter`
+
+## Run
+
+From the project's root folder, run the following command.
+`python main.py`
+
+Vallah! A nice looking application screen pops up.
+
+## Known Bugs
+
+The 'Show Records' screen only shows up when atleast one user has attemped the test.
diff --git a/assets/most-accurate-test.png b/assets/most-accurate-test.png
new file mode 100644
index 0000000..7cf6209
--- /dev/null
+++ b/assets/most-accurate-test.png
Binary files differ
diff --git a/assets/myers-briggs-type-indicator.png b/assets/myers-briggs-type-indicator.png
new file mode 100644
index 0000000..fd01a88
--- /dev/null
+++ b/assets/myers-briggs-type-indicator.png
Binary files differ
diff --git a/assets/ptypes/ENFJ1.png b/assets/ptypes/ENFJ1.png
new file mode 100644
index 0000000..54a72b1
--- /dev/null
+++ b/assets/ptypes/ENFJ1.png
Binary files differ
diff --git a/assets/ptypes/ENFJ2.png b/assets/ptypes/ENFJ2.png
new file mode 100644
index 0000000..ce6fb0a
--- /dev/null
+++ b/assets/ptypes/ENFJ2.png
Binary files differ
diff --git a/assets/ptypes/ENFJ3.png b/assets/ptypes/ENFJ3.png
new file mode 100644
index 0000000..79b6994
--- /dev/null
+++ b/assets/ptypes/ENFJ3.png
Binary files differ
diff --git a/assets/ptypes/ENFP1.png b/assets/ptypes/ENFP1.png
new file mode 100644
index 0000000..34efb28
--- /dev/null
+++ b/assets/ptypes/ENFP1.png
Binary files differ
diff --git a/assets/ptypes/ENFP2.png b/assets/ptypes/ENFP2.png
new file mode 100644
index 0000000..642d5a9
--- /dev/null
+++ b/assets/ptypes/ENFP2.png
Binary files differ
diff --git a/assets/ptypes/ENFP3.png b/assets/ptypes/ENFP3.png
new file mode 100644
index 0000000..60e7679
--- /dev/null
+++ b/assets/ptypes/ENFP3.png
Binary files differ
diff --git a/assets/ptypes/ENTJ1.png b/assets/ptypes/ENTJ1.png
new file mode 100644
index 0000000..6fa3e24
--- /dev/null
+++ b/assets/ptypes/ENTJ1.png
Binary files differ
diff --git a/assets/ptypes/ENTJ2.png b/assets/ptypes/ENTJ2.png
new file mode 100644
index 0000000..9b7093b
--- /dev/null
+++ b/assets/ptypes/ENTJ2.png
Binary files differ
diff --git a/assets/ptypes/ENTJ3.png b/assets/ptypes/ENTJ3.png
new file mode 100644
index 0000000..acd365b
--- /dev/null
+++ b/assets/ptypes/ENTJ3.png
Binary files differ
diff --git a/assets/ptypes/ENTP1.png b/assets/ptypes/ENTP1.png
new file mode 100644
index 0000000..011215e
--- /dev/null
+++ b/assets/ptypes/ENTP1.png
Binary files differ
diff --git a/assets/ptypes/ENTP2.png b/assets/ptypes/ENTP2.png
new file mode 100644
index 0000000..062c2b9
--- /dev/null
+++ b/assets/ptypes/ENTP2.png
Binary files differ
diff --git a/assets/ptypes/ENTP3.png b/assets/ptypes/ENTP3.png
new file mode 100644
index 0000000..d3f61ab
--- /dev/null
+++ b/assets/ptypes/ENTP3.png
Binary files differ
diff --git a/assets/ptypes/ESFJ1.png b/assets/ptypes/ESFJ1.png
new file mode 100644
index 0000000..31dc3b8
--- /dev/null
+++ b/assets/ptypes/ESFJ1.png
Binary files differ
diff --git a/assets/ptypes/ESFJ2.png b/assets/ptypes/ESFJ2.png
new file mode 100644
index 0000000..06c3871
--- /dev/null
+++ b/assets/ptypes/ESFJ2.png
Binary files differ
diff --git a/assets/ptypes/ESFJ3.png b/assets/ptypes/ESFJ3.png
new file mode 100644
index 0000000..4ab36e3
--- /dev/null
+++ b/assets/ptypes/ESFJ3.png
Binary files differ
diff --git a/assets/ptypes/ESFP1.png b/assets/ptypes/ESFP1.png
new file mode 100644
index 0000000..52458ac
--- /dev/null
+++ b/assets/ptypes/ESFP1.png
Binary files differ
diff --git a/assets/ptypes/ESFP2.png b/assets/ptypes/ESFP2.png
new file mode 100644
index 0000000..17debc3
--- /dev/null
+++ b/assets/ptypes/ESFP2.png
Binary files differ
diff --git a/assets/ptypes/ESFP3.png b/assets/ptypes/ESFP3.png
new file mode 100644
index 0000000..d6e8f40
--- /dev/null
+++ b/assets/ptypes/ESFP3.png
Binary files differ
diff --git a/assets/ptypes/ESTJ1.png b/assets/ptypes/ESTJ1.png
new file mode 100644
index 0000000..8c489a2
--- /dev/null
+++ b/assets/ptypes/ESTJ1.png
Binary files differ
diff --git a/assets/ptypes/ESTJ2.png b/assets/ptypes/ESTJ2.png
new file mode 100644
index 0000000..4a8fba3
--- /dev/null
+++ b/assets/ptypes/ESTJ2.png
Binary files differ
diff --git a/assets/ptypes/ESTJ3.png b/assets/ptypes/ESTJ3.png
new file mode 100644
index 0000000..d43eb61
--- /dev/null
+++ b/assets/ptypes/ESTJ3.png
Binary files differ
diff --git a/assets/ptypes/ESTP1.png b/assets/ptypes/ESTP1.png
new file mode 100644
index 0000000..61f89e4
--- /dev/null
+++ b/assets/ptypes/ESTP1.png
Binary files differ
diff --git a/assets/ptypes/ESTP2.png b/assets/ptypes/ESTP2.png
new file mode 100644
index 0000000..c06bb9a
--- /dev/null
+++ b/assets/ptypes/ESTP2.png
Binary files differ
diff --git a/assets/ptypes/ESTP3.png b/assets/ptypes/ESTP3.png
new file mode 100644
index 0000000..133390c
--- /dev/null
+++ b/assets/ptypes/ESTP3.png
Binary files differ
diff --git a/assets/ptypes/INFJ1.png b/assets/ptypes/INFJ1.png
new file mode 100644
index 0000000..d498e0e
--- /dev/null
+++ b/assets/ptypes/INFJ1.png
Binary files differ
diff --git a/assets/ptypes/INFJ2.png b/assets/ptypes/INFJ2.png
new file mode 100644
index 0000000..d45385c
--- /dev/null
+++ b/assets/ptypes/INFJ2.png
Binary files differ
diff --git a/assets/ptypes/INFJ3.png b/assets/ptypes/INFJ3.png
new file mode 100644
index 0000000..9978447
--- /dev/null
+++ b/assets/ptypes/INFJ3.png
Binary files differ
diff --git a/assets/ptypes/INFP1.png b/assets/ptypes/INFP1.png
new file mode 100644
index 0000000..2a5367a
--- /dev/null
+++ b/assets/ptypes/INFP1.png
Binary files differ
diff --git a/assets/ptypes/INFP2.png b/assets/ptypes/INFP2.png
new file mode 100644
index 0000000..b84e2f3
--- /dev/null
+++ b/assets/ptypes/INFP2.png
Binary files differ
diff --git a/assets/ptypes/INFP3.png b/assets/ptypes/INFP3.png
new file mode 100644
index 0000000..f3edf5e
--- /dev/null
+++ b/assets/ptypes/INFP3.png
Binary files differ
diff --git a/assets/ptypes/INTJ1.png b/assets/ptypes/INTJ1.png
new file mode 100644
index 0000000..b84b831
--- /dev/null
+++ b/assets/ptypes/INTJ1.png
Binary files differ
diff --git a/assets/ptypes/INTJ1a.png b/assets/ptypes/INTJ1a.png
new file mode 100644
index 0000000..a027dec
--- /dev/null
+++ b/assets/ptypes/INTJ1a.png
Binary files differ
diff --git a/assets/ptypes/INTJ2.png b/assets/ptypes/INTJ2.png
new file mode 100644
index 0000000..ac01ba2
--- /dev/null
+++ b/assets/ptypes/INTJ2.png
Binary files differ
diff --git a/assets/ptypes/INTJ3.png b/assets/ptypes/INTJ3.png
new file mode 100644
index 0000000..032f07a
--- /dev/null
+++ b/assets/ptypes/INTJ3.png
Binary files differ
diff --git a/assets/ptypes/INTP1.png b/assets/ptypes/INTP1.png
new file mode 100644
index 0000000..eae9cfe
--- /dev/null
+++ b/assets/ptypes/INTP1.png
Binary files differ
diff --git a/assets/ptypes/INTP2.png b/assets/ptypes/INTP2.png
new file mode 100644
index 0000000..2b76379
--- /dev/null
+++ b/assets/ptypes/INTP2.png
Binary files differ
diff --git a/assets/ptypes/INTP3.png b/assets/ptypes/INTP3.png
new file mode 100644
index 0000000..9366867
--- /dev/null
+++ b/assets/ptypes/INTP3.png
Binary files differ
diff --git a/assets/ptypes/ISFJ1.png b/assets/ptypes/ISFJ1.png
new file mode 100644
index 0000000..fe802a6
--- /dev/null
+++ b/assets/ptypes/ISFJ1.png
Binary files differ
diff --git a/assets/ptypes/ISFJ2.png b/assets/ptypes/ISFJ2.png
new file mode 100644
index 0000000..2715c13
--- /dev/null
+++ b/assets/ptypes/ISFJ2.png
Binary files differ
diff --git a/assets/ptypes/ISFJ3.png b/assets/ptypes/ISFJ3.png
new file mode 100644
index 0000000..ca46002
--- /dev/null
+++ b/assets/ptypes/ISFJ3.png
Binary files differ
diff --git a/assets/ptypes/ISFP1.png b/assets/ptypes/ISFP1.png
new file mode 100644
index 0000000..544ebfd
--- /dev/null
+++ b/assets/ptypes/ISFP1.png
Binary files differ
diff --git a/assets/ptypes/ISFP2.png b/assets/ptypes/ISFP2.png
new file mode 100644
index 0000000..9469bf5
--- /dev/null
+++ b/assets/ptypes/ISFP2.png
Binary files differ
diff --git a/assets/ptypes/ISFP3.png b/assets/ptypes/ISFP3.png
new file mode 100644
index 0000000..c65de56
--- /dev/null
+++ b/assets/ptypes/ISFP3.png
Binary files differ
diff --git a/assets/ptypes/ISTJ1.png b/assets/ptypes/ISTJ1.png
new file mode 100644
index 0000000..070c90e
--- /dev/null
+++ b/assets/ptypes/ISTJ1.png
Binary files differ
diff --git a/assets/ptypes/ISTJ2.png b/assets/ptypes/ISTJ2.png
new file mode 100644
index 0000000..07f17cf
--- /dev/null
+++ b/assets/ptypes/ISTJ2.png
Binary files differ
diff --git a/assets/ptypes/ISTJ3.png b/assets/ptypes/ISTJ3.png
new file mode 100644
index 0000000..cdfcb53
--- /dev/null
+++ b/assets/ptypes/ISTJ3.png
Binary files differ
diff --git a/assets/ptypes/ISTP1.png b/assets/ptypes/ISTP1.png
new file mode 100644
index 0000000..d1ef8ac
--- /dev/null
+++ b/assets/ptypes/ISTP1.png
Binary files differ
diff --git a/assets/ptypes/ISTP2.png b/assets/ptypes/ISTP2.png
new file mode 100644
index 0000000..969444b
--- /dev/null
+++ b/assets/ptypes/ISTP2.png
Binary files differ
diff --git a/assets/ptypes/ISTP3.png b/assets/ptypes/ISTP3.png
new file mode 100644
index 0000000..6acd9b0
--- /dev/null
+++ b/assets/ptypes/ISTP3.png
Binary files differ
diff --git a/assets/quiz/Q-13.png b/assets/quiz/Q-13.png
new file mode 100644
index 0000000..58d8201
--- /dev/null
+++ b/assets/quiz/Q-13.png
Binary files differ
diff --git a/assets/quiz/Q00.png b/assets/quiz/Q00.png
new file mode 100644
index 0000000..bcfada7
--- /dev/null
+++ b/assets/quiz/Q00.png
Binary files differ
diff --git a/assets/quiz/Q01.png b/assets/quiz/Q01.png
new file mode 100644
index 0000000..5e1f76e
--- /dev/null
+++ b/assets/quiz/Q01.png
Binary files differ
diff --git a/assets/quiz/Q02.png b/assets/quiz/Q02.png
new file mode 100644
index 0000000..fcbaad3
--- /dev/null
+++ b/assets/quiz/Q02.png
Binary files differ
diff --git a/assets/quiz/Q03.png b/assets/quiz/Q03.png
new file mode 100644
index 0000000..63f3701
--- /dev/null
+++ b/assets/quiz/Q03.png
Binary files differ
diff --git a/assets/quiz/Q10.png b/assets/quiz/Q10.png
new file mode 100644
index 0000000..3b16e43
--- /dev/null
+++ b/assets/quiz/Q10.png
Binary files differ
diff --git a/assets/quiz/Q11.png b/assets/quiz/Q11.png
new file mode 100644
index 0000000..11e7052
--- /dev/null
+++ b/assets/quiz/Q11.png
Binary files differ
diff --git a/assets/quiz/Q12.png b/assets/quiz/Q12.png
new file mode 100644
index 0000000..9bc9084
--- /dev/null
+++ b/assets/quiz/Q12.png
Binary files differ
diff --git a/assets/quiz/Q13.png b/assets/quiz/Q13.png
new file mode 100644
index 0000000..7a62c7d
--- /dev/null
+++ b/assets/quiz/Q13.png
Binary files differ
diff --git a/assets/quiz/Q20.png b/assets/quiz/Q20.png
new file mode 100644
index 0000000..4850e82
--- /dev/null
+++ b/assets/quiz/Q20.png
Binary files differ
diff --git a/assets/quiz/Q21.png b/assets/quiz/Q21.png
new file mode 100644
index 0000000..168ada2
--- /dev/null
+++ b/assets/quiz/Q21.png
Binary files differ
diff --git a/assets/quiz/Q22.png b/assets/quiz/Q22.png
new file mode 100644
index 0000000..fb81b63
--- /dev/null
+++ b/assets/quiz/Q22.png
Binary files differ
diff --git a/assets/quiz/Q23.png b/assets/quiz/Q23.png
new file mode 100644
index 0000000..07c72bb
--- /dev/null
+++ b/assets/quiz/Q23.png
Binary files differ
diff --git a/assets/quiz/Q30.png b/assets/quiz/Q30.png
new file mode 100644
index 0000000..f5eb802
--- /dev/null
+++ b/assets/quiz/Q30.png
Binary files differ
diff --git a/assets/quiz/Q31.png b/assets/quiz/Q31.png
new file mode 100644
index 0000000..db52095
--- /dev/null
+++ b/assets/quiz/Q31.png
Binary files differ
diff --git a/assets/quiz/Q32.png b/assets/quiz/Q32.png
new file mode 100644
index 0000000..5cd6660
--- /dev/null
+++ b/assets/quiz/Q32.png
Binary files differ
diff --git a/assets/quiz/Q33.png b/assets/quiz/Q33.png
new file mode 100644
index 0000000..ec2a472
--- /dev/null
+++ b/assets/quiz/Q33.png
Binary files differ
diff --git a/assets/short-version.jpg b/assets/short-version.jpg
new file mode 100644
index 0000000..9d27c7b
--- /dev/null
+++ b/assets/short-version.jpg
Binary files differ
diff --git a/assets/types.png b/assets/types.png
new file mode 100644
index 0000000..fd49aee
--- /dev/null
+++ b/assets/types.png
Binary files differ
diff --git a/frames.py b/frames.py
new file mode 100644
index 0000000..216efa8
--- /dev/null
+++ b/frames.py
@@ -0,0 +1,405 @@
+import re
+from widgets import *
+from tkinter import ttk
+
+
+def showframe(frame):
+ frame.pack(fill=BOTH, expand=TRUE)
+ if hasattr(frame, 'content'):
+ frame.content.background.focus_set()
+ else:
+ frame.focus_set()
+
+
+# Result page
+class PTypePage(Frame):
+ ptypes = {'E':'Extrovert', 'S':'Sensing', 'T':'Thinking', 'J':'Judging',
+ 'I':'Introvert', 'N':'Intutive', 'F':'Feeling', 'P':'Perceiving'}
+ def __init__(self, lastframe, master, cursor, answers, *pargs):
+ Frame.__init__(self, master, *pargs)
+ # WIN_HEIGHT, WIN_WIDTH = 1200, 710
+ # self.master.geometry(f"{WIN_HEIGHT}x{WIN_WIDTH}")
+ # self.master.minsize(WIN_HEIGHT, WIN_WIDTH)
+ os.chdir(HOME)
+ os.chdir('ptypes')
+
+ self.lastframe = lastframe
+ self.cursor = cursor
+ self.answers = answers
+ self.fullanswers = ' , '.join([self.ptypes[x] for x in answers])
+ self.page_index = 0
+ self.hints = ("Well done {}! Tap anywhere to continue...".format(USERNAME),
+ "%s ( %s )" % (self.answers, self.fullanswers),
+ "That's it! Thanks for taking this test.")
+ self.hint = StringVar()
+ self.hint.set(self.hints[self.page_index])
+
+ self.statusbar = StatusBar(self, self.hint)
+ self.content = ContentBox(self, '%s%d.png' %(self.answers, self.page_index+1))
+ self.content.background.bind('<Button-1>', self.nextpage)
+ self.content.background.bind('<Button-2>', self.exit)
+ self.content.background.bind('<Button-3>', self.prevpage)
+ self.content.background.bind('<Return>', self.nextpage)
+ self.content.background.bind('<space>', self.nextpage)
+ self.content.background.bind('<BackSpace>', self.prevpage)
+ self.content.background.bind('<Left>', self.prevpage)
+ self.content.background.bind('<Right>', self.nextpage)
+ self.content.background.bind('<Escape>', self.exit)
+ self.content.background.focus_set()
+ self.content.pack(fill=BOTH, expand=True)
+ self.statusbar.pack(side=BOTTOM, fill=X)
+
+ def change_position(self):
+ os.chdir(HOME)
+ os.chdir('ptypes')
+ self.content.set('%s%d.png' %(self.answers, self.page_index+1))
+ self.hint.set(self.hints[self.page_index])
+
+ def prevpage(self, event=None):
+ if self.page_index > 0:
+ self.page_index -= 1
+ self.change_position()
+ else:
+ self.exit()
+
+ def nextpage(self, event=None):
+ if self.page_index < 2:
+ self.page_index += 1
+ self.change_position()
+ else:
+ self.exit(title="You are done!", message="Exit to main the main screen?")
+
+ def exit(self, event=None, title=None, message=None):
+ if title:
+ if messagebox.askokcancel(title, message):
+ self.destroy()
+ HomePage(self.master, self.cursor).pack(fill=BOTH, expand=TRUE)
+ else:
+ self.destroy()
+ showframe(self.lastframe)
+
+
+# Quiz page (4 questions)
+class TestPage(Frame):
+ options = (('E', 'S', 'T', 'J'), ('I', 'N', 'F', 'P'))
+ hints = ("Tap anywhere to continue...",
+ "First Option",
+ "Second Option",
+ "Choose your answer...")
+
+ def __init__(self, lastframe, master, cursor, *pargs):
+ Frame.__init__(self, master, *pargs)
+ self.lastframe = lastframe
+ self.master = master
+ self.cursor = cursor
+ # WIN_HEIGHT, WIN_WIDTH = 1200, 710
+ # self.master.geometry(f"{WIN_HEIGHT}x{WIN_WIDTH}")
+ # self.master.minsize(WIN_HEIGHT, WIN_WIDTH)
+ os.chdir(HOME)
+ os.chdir('quiz')
+
+ self.content = ContentBox(self, "Q-13.png")
+ self.content.background.bind('<Button-1>', self.nextpage)
+ self.content.background.bind('<Button-2>', self.exit)
+ self.content.background.bind('<Button-3>', self.prevpage)
+ self.content.background.bind('<Return>', self.nextpage)
+ self.content.background.bind('<space>', self.nextpage)
+ self.content.background.bind('<BackSpace>', self.prevpage)
+ self.content.background.bind('<Left>', self.prevpage)
+ self.content.background.bind('<Right>', self.nextpage)
+ self.content.background.bind('<Escape>', self.exit)
+ self.content.background.focus_set()
+
+ self.answers = ['']*4
+ self.answer = StringVar(self)
+ self.hint = StringVar(self)
+ self.position = StringVar(self)
+ self.positions = (" Intro ", "QUESTION #1", "QUESTION #2",
+ "QUESTION #3", "QUESTION #4")
+ self.statusbar = StatusBar(self, self.hint)
+ self.statusbar.addmenu(self.position, self.positions,
+ command=self.change_position)
+
+ self.content.pack(fill=BOTH, expand=YES)
+ self.statusbar.pack(side=BOTTOM, fill=X)
+
+ self.quest_index = -1
+ self.page_index = 3
+
+ global USERNAME
+ self.hint.set("Welcome {}! Tap anywhere to continue...".format(USERNAME))
+ self.position.set(self.positions[self.quest_index+1])
+
+ def get_selection(self):
+ if hasattr(self, 'selection'):
+ return
+ #self.selection.destroy()
+
+ bgcolor='#fdcc03'
+ fgcolor='black'
+ msgfont=("Times New Roman", 16, 'bold')
+ optfont=("Monospace", 12, 'bold')
+ self.answer.set(self.answers[self.quest_index])
+
+ def submit():
+ self.answers[self.quest_index] = self.answer.get()
+ self.nextpage()
+
+ self.selection = Frame(self, background=bgcolor)
+ message = Label(self.selection, text="I will go with...", font=msgfont,
+ width=40, height=2, background=bgcolor, foreground=fgcolor)
+ optA = Radiobutton(self.selection, text="First Option ", variable=self.answer,
+ value=self.options[0][self.quest_index], background=bgcolor, foreground=fgcolor, font=optfont,
+ highlightthickness=0, height=2, width=30)
+ optB = Radiobutton(self.selection, text="Second Option", variable=self.answer,
+ value=self.options[1][self.quest_index], background=bgcolor, foreground=fgcolor, font=optfont,
+ highlightthickness=0, height=2, width=30)
+ submitB = Button(self.selection, text="Submit", font=('', 12), width=10,
+ command=submit,
+ background=fgcolor, foreground=bgcolor, borderwidth=0, height=2)
+
+ message.pack(padx=40, pady=20)
+ optA.pack()
+ optB.pack()
+ submitB.pack(padx=20, pady=20)
+ self.selection.bind('<Button-3>', self.prevpage)
+ self.selection.place(relx=0.5, rely=0.5, x=-40, y=-40, anchor=CENTER)
+
+ def change_position(self, position=None):
+ os.chdir(HOME)
+ os.chdir('quiz')
+ if position:
+ self.quest_index = self.positions.index(position) - 1
+ self.page_index = 0
+ if self.quest_index == -1:
+ self.page_index = 3
+ self.hint.set("Tap anywhere to continue...")
+ else:
+ self.hint.set(self.hints[self.page_index])
+ # print('\n', self.quest_index, self.page_index, self.answers, self.answer)
+ if self.quest_index > 0 and self.page_index == 0:
+ answered = (4 - self.answers.count(''))
+ if answered < self.quest_index:
+ # print('no answer @', self.quest_index, self.page_index)
+ self.hint.set("Please sumbmit an answer to continue!")
+ self.statusbar.message.configure(foreground='darkred')
+ self.quest_index = answered
+ self.page_index = 3
+
+ if self.quest_index == 4:
+ self.quest_index = 3
+ self.page_index = 3
+ final = ''.join(self.answers)
+ self.cursor.execute("SELECT userid FROM records WHERE userid='{}'".format(USERNAME))
+ if self.cursor.fetchall():
+ self.cursor.execute(
+ "UPDATE records set ptype = '{}' WHERE userid='{}'".format(final, USERNAME))
+ else:
+ self.cursor.execute("INSERT INTO records values ('{}', '{}')".format(USERNAME, final))
+ self.pack_forget()
+ ptypepage = PTypePage(self, self.master, self.cursor, final)
+ ptypepage.pack(fill=BOTH, expand=TRUE)
+ return
+
+ self.position.set(self.positions[self.quest_index+1])
+ #print(self.quest_index, self.page_index, self.answers, self.answer)
+ self.content.set("Q%s%s.png" %
+ (self.quest_index, self.page_index))
+ if self.quest_index != -1 and self.page_index == 3:
+ self.get_selection()
+ elif hasattr(self, 'selection'):
+ self.selection.destroy()
+ del self.selection
+ self.statusbar.message.config(foreground='black')
+
+ def prevpage(self, event=None):
+ if self.quest_index == -1 and self.page_index == 3:
+ self.exit()
+ return
+ if self.page_index > 0:
+ self.page_index -= 1
+ self.change_position()
+ else:
+ self.page_index = 3
+ self.quest_index -= 1
+ self.change_position()
+
+ def nextpage(self, event=None):
+ if self.page_index < 3:
+ self.page_index += 1
+ self.change_position()
+ else:
+ self.page_index = 0
+ self.quest_index += 1
+ self.change_position()
+ self.content.background.focus_set()
+
+ def exit(self, event=None):
+ if messagebox.askokcancel("Exit",
+ "Do you really want to exit?\nAll answer data will be lost!"):
+ self.destroy()
+ showframe(self.lastframe)
+
+
+# Get user name
+class UserPage(Frame):
+ def __init__(self, lastframe, master, cursor, *pargs):
+ self.bgcolor='#ffcc33'
+ self.cursor = cursor
+ self.lastframe = lastframe
+ Frame.__init__(self, master, bg=self.bgcolor, *pargs)
+ self.master.configure(background=self.bgcolor)
+
+ self.username = StringVar()
+ self.usernameL = Label(self, font=20, background=self.bgcolor,
+ text="Enter User Name : ")
+ self.usernameE = Entry(self, font=30, textvariable=self.username)
+ self.message = Label(self, font=16, background=self.bgcolor,
+ text="User Name must be unique")
+ self.startB = Button(self, font=20, text="Start test",
+ background='black', foreground='white', command=self.start_test)
+ self.cancelB = Button(self, font=20, text="Cancel",
+ background='black', foreground='white', command=self.exit)
+
+ self.usernameL.place(relx=0.2, rely=0.4, height=40, width=200)
+ self.usernameE.place(relx=0.4, rely=0.4, height=40, width=400)
+ self.message.place(relx=0.4, rely=0.3)
+ self.startB.place(relx=0.4, rely=0.6, height=60, width=200)
+ self.cancelB.place(relx=0.6, rely=0.6, height=60, width=200)
+
+ self.usernameE.bind('<Return>', self.start_test)
+ self.usernameE.bind('<Escape>', lambda event: self.focus_set())
+ self.bind('<Escape>', self.exit)
+ self.bind('<Return>', lambda event: self.usernameE.focus())
+ self.bind('<space>', lambda event: self.usernameE.focus())
+ self.focus_set()
+
+ def start_test(self, event=None):
+ def print_warning(message):
+ Label(self, font=24, background=self.bgcolor, foreground='red',
+ text=message).place(relx=0.4, rely=0.2)
+ uname = self.username.get()
+ if uname == "":
+ print_warning("Please enter an user ID")
+ return
+ self.cursor.execute("SELECT * FROM records")
+ for user in self.cursor.fetchall():
+ if uname in user:
+ print_warning("A user with this ID already exists!" +\
+ "\nPlease try a different user ID.")
+ return
+
+ global USERNAME
+ USERNAME = uname
+ self.pack_forget()
+ TestPage(self, self.master, self.cursor).pack(fill=BOTH, expand=YES)
+
+ def exit(self, event=None):
+ self.destroy()
+ showframe(self.lastframe)
+
+
+class RecordsPage(Frame):
+ def __init__(self, lastframe, master, cursor, *pargs):
+ Frame.__init__(self, master, background='white', *pargs)
+ self.lastframe = lastframe
+ self.cursor = cursor
+
+ self.cursor.execute('DESCRIBE records')
+ columns = list()
+ for column in self.cursor.fetchall():
+ columns.append(column[0])
+
+ top = Frame(self)
+ bottom = Frame(self)
+ self.tree = ttk.Treeview(bottom, columns=columns, show='headings')
+ self.scrollbar = Scrollbar(bottom, orient=VERTICAL, borderwidth=0,
+ background='lightblue', troughcolor='white', highlightthickness=0,
+ activebackground='#0033aa', command=self.tree.yview)
+ self.tree.configure(yscroll=self.scrollbar.set)
+ self.search = StringVar()
+ self.searchbox = SearchBox(top, self.search, self.filter)
+ self.exitB = Button(top, text="❌", background='white', borderwidth=0,
+ highlightthickness=0, command=self.exit)
+
+ self.searchbox.pack(side=LEFT, fill=X, expand=TRUE)
+ self.exitB.pack(side=RIGHT)
+ self.tree.pack(side=LEFT, fill=BOTH, expand=TRUE)
+ self.scrollbar.pack(side=RIGHT, fill=Y)
+ top.pack(fill=X)
+ bottom.pack(fill=BOTH, expand=TRUE)
+
+ col_names = ('User ID', 'Personality Type')
+ for i in range(len(columns)):
+ self.tree.heading(columns[i], text=col_names[i])
+
+ self.cursor.execute('SELECT * FROM records')
+ self.records = self.cursor.fetchall()
+ for record in self.records:
+ self.tree.insert('', END, values=record)
+
+ self.tree.bind('<Double-1>', self.select_item)
+ self.tree.bind('<Return>', self.select_item)
+ self.tree.bind('<space>', self.select_item)
+ self.tree.bind('<Escape>', self.exit)
+ self.bind('<Escape>', self.exit)
+ self.tree.selection_set('I001')
+ self.focus_set()
+
+ def filter(self, event=None):
+ print(event)
+ filtertxt = self.search.get()
+ self.tree.delete(*self.tree.get_children())
+ for record in self.records:
+ for field in record:
+ if re.search(filtertxt, field.lower()):
+ self.tree.insert('', END, values=record)
+ break
+
+ def select_item(self, event=None):
+ selection = self.tree.selection()
+ item = self.tree.item(selection)
+ record = item['values']
+ print(record)
+ self.pack_forget()
+ global USERNAME
+ USERNAME = record[0]
+ PTypePage(self, self.master, self.cursor, record[1]).pack(
+ fill=BOTH, expand=TRUE)
+
+ def exit(self, event=None):
+ self.destroy()
+ showframe(self.lastframe)
+
+
+# Start app
+class HomePage(Frame):
+ def __init__(self, master, cursor, *pargs):
+ Frame.__init__(self, master, *pargs)
+ self.cursor = cursor
+ os.chdir(HOME)
+ WIN_HEIGHT, WIN_WIDTH = 1200, 675
+ self.master.geometry(f"{WIN_HEIGHT}x{WIN_WIDTH}")
+ self.master.minsize(WIN_HEIGHT, WIN_WIDTH)
+
+ self.content = ContentBox(self, "most-accurate-test.png")
+ self.content.pack(fill=BOTH, expand=YES)
+ self.mainmenu = ButtonMenu(self)
+ self.mainmenu.additem('SHOW RECORDS ', self.show_database)
+ self.mainmenu.additem('START TEST', self.start_test)
+ self.mainmenu.additem('QUIT', self.master.destroy)
+ self.content.background.bind("<space>", self.start_test)
+ self.content.background.bind("<Return>", self.start_test)
+ self.content.background.bind("1", self.show_database)
+ self.content.background.bind("2", self.start_test)
+ self.content.background.bind("3", lambda event: self.master.destroy())
+ self.content.background.focus_set()
+
+ def start_test(self, event=None):
+ print(self)
+ self.pack_forget()
+ UserPage(self, self.master, self.cursor).pack(fill=BOTH, expand=YES)
+
+ def show_database(self, event=None):
+ self.pack_forget()
+ RecordsPage(self, self.master, self.cursor).pack(fill=BOTH, expand=YES)
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..261a9fe
--- /dev/null
+++ b/main.py
@@ -0,0 +1,80 @@
+#!/bin/python3
+
+from frames import *
+from getpass import getuser
+import mariadb
+#import pdb
+
+
+fields = (('userid', 'varchar(100)', 'PRIMARY KEY'),
+ ('ptype', 'varchar(4)', 'NOT NULL'))
+
+
+def start():
+ with mariadb.connect(host="localhost", user=getuser(), password='') as connection:
+ with connection.cursor() as cursor:
+
+ # check if databse exist
+ cursor.execute('SHOW DATABASES')
+ for dbs in cursor.fetchall():
+ if 'ptest' in dbs:
+ break
+ else:
+ print('Creating database ptest.')
+ cursor.execute("CREATE DATABASE ptest")
+ cursor.execute("USE ptest")
+
+ # check if table exist and is in proper format
+ cursor.execute('SHOW TABLES')
+ for tables in cursor.fetchall():
+ if 'records' in tables:
+ cursor.execute("DESCRIBE records")
+ columns = cursor.fetchall()
+ l_fields = len(fields)
+ l_columns = len(columns)
+
+ table_ok = True
+ if l_fields != l_columns:
+ table_ok = False
+ for i in range(l_fields):
+ if fields[i][0] != columns[i][0] or fields[i][1] != columns[i][1]:
+ table_ok = False
+
+ if table_ok == False:
+ cursor.execute("DROP TABLE records")
+ continue
+ break
+ else:
+ print('Creating table records.')
+ columns = ''
+ for i in range(len(fields)):
+ if i == 0:
+ columns += ' '.join(fields[i])
+ else:
+ columns += ', ' + ' '.join(fields[i])
+ cursor.execute("CREATE TABLE records({})".format(columns))
+
+ root = Tk()
+ root.title("Personality Test")
+
+ WIN_HEIGHT, WIN_WIDTH = 1200, 675
+ root.geometry(f"{WIN_HEIGHT}x{WIN_WIDTH}")
+ #root.minsize(WIN_HEIGHT, WIN_WIDTH)
+ #root.resizable(width=False, height=False)
+ root.configure(background="black")
+ root.bind_all("<Button-1>", lambda event: event.widget.focus_set())
+
+ #startpage = RecordsPage(HomePage(root, cursor), root, cursor)
+ startpage = HomePage(root, cursor)
+ startpage.pack(fill=BOTH, expand=TRUE)
+ startpage.mainloop()
+
+ connection.commit()
+
+
+start()
+
+# try:
+# except Error as e:
+# messagebox.showerror(title='Oops!', message=e)
+#
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..7e9b898
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+pillow==9.4.0
+
diff --git a/test/README.txt b/test/README.txt
new file mode 100644
index 0000000..72a96ff
--- /dev/null
+++ b/test/README.txt
@@ -0,0 +1 @@
+Just randomly testing stuff used in my main application.
diff --git a/test/database.py b/test/database.py
new file mode 100644
index 0000000..38b4f70
--- /dev/null
+++ b/test/database.py
@@ -0,0 +1,36 @@
+from tkinter.messagebox import showerror
+from getpass import *
+from mysql.connector import connect, Error
+
+def initialize_db():
+
+ with connect(host="localhost", user=getuser(), password='') as connection:
+ with connection.cursor() as cursor:
+
+ cursor.execute('SHOW DATABASES')
+ for dbs in cursor.fetchall():
+ if 'ptest' in dbs:
+ break
+ else:
+ print('createing')
+ cursor.execute("CREATE DATABASE ptest")
+
+ cursor.execute("USE ptest")
+
+ cursor.execute('SHOW TABLES')
+ for tables in cursor.fetchall():
+ if 'records' in tables:
+ break
+ else:
+ cursor.execute("""CREATE TABLE records(
+ id INT(3) AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(50), type VARCHAR(4)
+ )""")
+
+ cursor.execute("DESCRIBE records")
+ print(cursor.fetchall())
+
+try:
+ initialize_db()
+except Error as e:
+ showerror(title='Oops!', message=e)
diff --git a/test/double-click.py b/test/double-click.py
new file mode 100644
index 0000000..a2d178e
--- /dev/null
+++ b/test/double-click.py
@@ -0,0 +1,34 @@
+from tkinter import *
+from tkinter import messagebox
+from tkinter.ttk import *
+
+def doubleClick(event):
+ e = event.widget # Get event controls
+ iid = e.identify("item",event.x,event.y) # Get the double-click item id
+ state = e.item(iid,"text") # Get state
+ city = e.item(iid,"values")[0] # Get city
+ outputStr = "{0} : {1}".format(state,city) # Formatting
+ messagebox.showinfo("Double Clicked",outputStr) # Output
+
+root = Tk()
+root.title("ch18_12")
+
+stateCity = {"Illinois": "Chicago", "California": "Los Angeles",
+ "Texas": "Houston", "Washington": "Seattle",
+ "Jiangsu": "Nanjing", "Shandong": "Qingdao",
+ "Guangdong": "Guangzhou", "Fujian": "Xiamen"}
+
+# Create Treeview
+tree = Treeview(root,columns=("cities"))
+# Create column headings
+tree.heading("#0",text="State") # Icon bar
+tree.heading("cities",text="City")
+# Format field
+tree.column("cities",anchor=CENTER)
+# Create Content
+for state in stateCity.keys():
+ tree.insert("",index=END,text=state,values=stateCity[state])
+tree.bind("<Double-1>",doubleClick) # Double-click binding doubleClick method
+tree.pack()
+
+root.mainloop()
diff --git a/test/fill-vs-expand.py b/test/fill-vs-expand.py
new file mode 100644
index 0000000..6793214
--- /dev/null
+++ b/test/fill-vs-expand.py
@@ -0,0 +1,11 @@
+#!/bin/python2
+
+import tkinter as tk
+
+root = tk.Tk()
+root.geometry('200x200+200+200')
+
+tk.Label(root, text='Label', bg='green').pack(expand=False, fill=tk.Y)
+tk.Label(root, text='Label2', bg='red').pack(expand=True, fill=tk.BOTH)
+
+root.mainloop()
diff --git a/test/fixratio.py b/test/fixratio.py
new file mode 100644
index 0000000..a9393cd
--- /dev/null
+++ b/test/fixratio.py
@@ -0,0 +1,33 @@
+import tkinter as tk
+WIDTH, HEIGHT = 400, 300 # Defines aspect ratio of window.
+
+def maintain_aspect_ratio(event, aspect_ratio):
+ """ Event handler to override root window resize events to maintain the
+ specified width to height aspect ratio.
+ """
+ if event.widget.master: # Not root window?
+ return # Ignore.
+
+ # <Configure> events contain the widget's new width and height in pixels.
+ new_aspect_ratio = event.width / event.height
+
+ # Decide which dimension controls.
+ if new_aspect_ratio > aspect_ratio:
+ # Use width as the controlling dimension.
+ desired_width = event.width
+ desired_height = int(event.width / aspect_ratio)
+ else:
+ # Use height as the controlling dimension.
+ desired_height = event.height
+ desired_width = int(event.height * aspect_ratio)
+
+ # Override if necessary.
+ if event.width != desired_width or event.height != desired_height:
+ # Manually give it the proper dimensions.
+ event.widget.geometry(f'{desired_width}x{desired_height}')
+ return "break" # Block further processing of this event.
+
+root = tk.Tk()
+root.geometry(f'{WIDTH}x{HEIGHT}')
+root.bind('<Configure>', lambda event: maintain_aspect_ratio(event, WIDTH/HEIGHT))
+root.mainloop()
diff --git a/test/frames.py b/test/frames.py
new file mode 100644
index 0000000..8870fa7
--- /dev/null
+++ b/test/frames.py
@@ -0,0 +1,16 @@
+import tkinter
+from tkinter import *
+root = tkinter.Tk()
+root.geometry("1920x1080")
+
+TopFrame = Frame(root, width=1920, height=200, bg= "green")
+MiddleRightFrame = Frame(root, width=1120, height=730, bg="orange")
+MiddleLeftFrame = Frame(root, width=800, height=730, bg="black")
+BottomFrame = Frame(root, width=1920, height=150, bg="blue")
+
+TopFrame.pack(side=TOP)
+BottomFrame.pack(side=BOTTOM)
+MiddleRightFrame.pack(side=RIGHT)
+MiddleLeftFrame.pack(side=LEFT)
+
+root.mainloop()
diff --git a/test/logs.py b/test/logs.py
new file mode 100644
index 0000000..6e602be
--- /dev/null
+++ b/test/logs.py
@@ -0,0 +1,63 @@
+#!/bin/python2
+
+import Tkinter
+import logging
+import datetime
+
+# this item "module_logger" is visible only in this module,
+# (but you can create references to the same logger object from other modules
+# by calling getLogger with an argument equal to the name of this module)
+# this way, you can share or isolate loggers as desired across modules and across threads
+# ...so it is module-level logging and it takes the name of this module (by using __name__)
+# recommended per https://docs.python.org/2/library/logging.html
+module_logger = logging.getLogger(__name__)
+
+class simpleapp_tk(Tkinter.Tk):
+ def __init__(self,parent):
+ Tkinter.Tk.__init__(self,parent)
+ self.parent = parent
+
+ self.grid()
+
+ self.mybutton = Tkinter.Button(self, text="ClickMe")
+ self.mybutton.grid(column=0,row=0,sticky='EW')
+ self.mybutton.bind("<ButtonRelease-1>", self.button_callback)
+
+ self.mytext = Tkinter.Text(self, state="disabled")
+ self.mytext.grid(column=0, row=1)
+
+ def button_callback(self, event):
+ now = datetime.datetime.now()
+ module_logger.info(now)
+
+class MyHandlerText(logging.StreamHandler):
+ def __init__(self, textctrl):
+ logging.StreamHandler.__init__(self) # initialize parent
+ self.textctrl = textctrl
+
+ def emit(self, record):
+ msg = self.format(record)
+ self.textctrl.config(state="normal")
+ self.textctrl.insert("end", msg + "\n")
+ self.flush()
+ self.textctrl.config(state="disabled")
+
+if __name__ == "__main__":
+
+ # create Tk object instance
+ app = simpleapp_tk(None)
+ app.title('my application')
+
+ # setup logging handlers using the Tk instance created above
+ # the pattern below can be used in other threads...
+ # ...to allow other thread to send msgs to the gui
+ # in this example, we set up two handlers just for demonstration (you could add a fileHandler, etc)
+ stderrHandler = logging.StreamHandler() # no arguments => stderr
+ module_logger.addHandler(stderrHandler)
+ guiHandler = MyHandlerText(app.mytext)
+ module_logger.addHandler(guiHandler)
+ module_logger.setLevel(logging.INFO)
+ module_logger.info("from main")
+
+ # start Tk
+ app.mainloop()
diff --git a/test/optionmenu.py b/test/optionmenu.py
new file mode 100644
index 0000000..47c06d4
--- /dev/null
+++ b/test/optionmenu.py
@@ -0,0 +1,30 @@
+
+from tkinter import *
+
+ws = Tk()
+ws.title('PythonGuides')
+ws.geometry('400x300')
+ws.config(bg='#F26849')
+
+def change_width(choice):
+ choice = variable.get()
+ dropdown.config(width=choice)
+
+# width choices available.
+width_size = [10, 15, 20, 25, 30]
+
+# setting variable for Integers
+variable = IntVar()
+
+# creating widget
+dropdown = OptionMenu(
+ ws,
+ variable,
+ *width_size,
+ command=change_width
+)
+# positioning widget
+dropdown.pack(expand=True)
+
+# infinite loop
+ws.mainloop()
diff --git a/test/overlapping-widgets.py b/test/overlapping-widgets.py
new file mode 100644
index 0000000..a810434
--- /dev/null
+++ b/test/overlapping-widgets.py
@@ -0,0 +1,33 @@
+import tkinter as tk
+
+class Example(tk.Frame):
+ def __init__(self, parent):
+ tk.Frame.__init__(self, parent)
+ self.text = tk.Text(self, wrap="word")
+ self.vsb = tk.Scrollbar(self, orient="vertical", command=self.text.yview)
+ self.text.configure(yscrollcommand=self.text_yview)
+ self.vsb.pack(side="right", fill="y")
+ self.text.pack(side="left", fill="both", expand=True)
+
+ # create an info window in the bottom right corner and
+ # inset a couple of pixels
+ self.info = tk.Label(self.text, width=20, borderwidth=1, relief="solid")
+ self.info.place(relx=1.0, rely=1.0, x=-2, y=-2,anchor="se")
+
+ def text_yview(self, *args):
+ '''
+ This gets called whenever the yview changes. For this example
+ we'll update the label to show the line number of the first
+ visible row.
+ '''
+ # first, update the scrollbar to reflect the state of the widget
+ self.vsb.set(*args)
+
+ # get index of first visible line, and put that in the label
+ index = self.text.index("@0,0")
+ self.info.configure(text=index)
+
+if __name__ == "__main__":
+ root = tk.Tk()
+ Example(root).pack(side="top", fill="both", expand=True)
+ root.mainloop()
diff --git a/test/placeholder.py b/test/placeholder.py
new file mode 100644
index 0000000..7b425c0
--- /dev/null
+++ b/test/placeholder.py
@@ -0,0 +1,24 @@
+import tkinter as tk
+
+root = tk.Tk()
+
+placeholder = 'Your text here'
+
+def erase(event=None):
+ if e.get() == placeholder:
+ e.delete(0,'end')
+def add(event=None):
+ if e.get() == '':
+ e.insert(0,placeholder)
+
+e = tk.Entry(root)
+e.pack(padx=10,pady=10)
+
+dummy = tk.Entry(root) #dummy widget just to see other widget lose focus
+dummy.pack(padx=10,pady=10)
+
+add()
+e.bind('<FocusIn>',erase)
+e.bind('<FocusOut>',add)
+
+root.mainloop()
diff --git a/test/ptest.sql b/test/ptest.sql
new file mode 100644
index 0000000..b2a48d4
--- /dev/null
+++ b/test/ptest.sql
@@ -0,0 +1,53 @@
+-- MariaDB dump 10.19 Distrib 10.11.2-MariaDB, for Linux (x86_64)
+--
+-- Host: localhost Database: ptest
+-- ------------------------------------------------------
+-- Server version 10.11.2-MariaDB
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8mb4 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Table structure for table `records`
+--
+
+DROP TABLE IF EXISTS `records`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `records` (
+ `userid` varchar(100) NOT NULL,
+ `ptype` varchar(4) NOT NULL,
+ PRIMARY KEY (`userid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `records`
+--
+
+LOCK TABLES `records` WRITE;
+/*!40000 ALTER TABLE `records` DISABLE KEYS */;
+INSERT INTO `records` VALUES
+('Akash','ISTP'),
+('vikas','INTJ');
+/*!40000 ALTER TABLE `records` ENABLE KEYS */;
+UNLOCK TABLES;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+-- Dump completed on 2023-03-25 7:22:23
diff --git a/test/resizable-image.py b/test/resizable-image.py
new file mode 100644
index 0000000..f298d3a
--- /dev/null
+++ b/test/resizable-image.py
@@ -0,0 +1,84 @@
+from tkinter import *
+from PIL import ImageTk, Image
+
+# class Content(Frame):
+# def __init__(self, master, *pargs):
+# Frame.__init__(self, master, *pargs)
+#
+# def set(self, image_file):
+# self.image = Image.open(image_file)
+# self.img_copy= self.image.copy()
+# self.background_image = ImageTk.PhotoImage(self.image)
+#
+# self.background = Label(self, image=self.background_image)
+# self.background.pack(fill=BOTH, expand=YES)
+# self.background.bind('<Configure>', self._resize_image)
+# self.background.bind('<Button-1>', self.destruct)
+#
+# def destruct(self, *pargs):
+# self.destroy()
+#
+# def _resize_image(self, event):
+# self.image = self.img_copy.resize((event.width, event.height))
+# self.background_image = ImageTk.PhotoImage(self.image)
+# self.background.configure(image=self.background_image)
+
+
+class Content(Canvas):
+ def __init__(self, master, *pargs):
+ Canvas.__init__(self, master, *pargs)
+
+ def set(self, image_file):
+ self.image = Image.open(image_file)
+ self.img_copy= self.image.copy()
+ self.background_image = ImageTk.PhotoImage(self.image)
+
+ self.image = self.create_image(0, 0, self.background_image)
+ self.image.bind('<Configure>', self._resize_image)
+ self.image.bind('<Button-1>', self.destruct)
+
+ def destruct(self, *pargs):
+ self.destroy()
+
+ def _resize_image(self, event):
+ self.image = self.img_copy.resize((event.width, event.height))
+ self.background_image = ImageTk.PhotoImage(self.image)
+ self.background.itemconfigure(self.image, image=self.background_image)
+
+root = Tk()
+root.geometry('800x450')
+file = "assets/most-accurate-test.png"
+
+image = ImageTk.PhotoImage(Image.open(file))
+canvas = Canvas(root)
+canvas.pack(fill='both', expand=TRUE)
+
+image_id = canvas.create_image(0, 0, image=image, anchor='nw')
+def resizer(e):
+ global image1, resized_image, new_image
+ image1 = Image.open(file)
+ resized_image = image1.resize((e.width, e.height), Image.Resampling.LANCZOS)
+ new_image = ImageTk.PhotoImage(resized_image)
+ canvas.itemconfigure(image_id, image=new_image)
+
+def change(e):
+ global image1, resized_image, new_image, canvas, image, file
+ file = "assets/types.png"
+ image = ImageTk.PhotoImage(Image.open(file))
+ print(canvas.winfo_width(), canvas.winfo_height())
+ image1 = Image.open(file)
+ resized_image = image1.resize((canvas.winfo_width(), canvas.winfo_height()), Image.Resampling.LANCZOS)
+ new_image = ImageTk.PhotoImage(resized_image)
+ canvas.itemconfigure(image_id, image=new_image)
+
+canvas.bind('<Configure>', resizer)
+canvas.bind('<Button-1>', change)
+
+# content = Content(root)
+# content.set(file)
+# content.pack()
+# exit()
+
+root.mainloop()
+
+
diff --git a/test/table.py b/test/table.py
new file mode 100644
index 0000000..875d25c
--- /dev/null
+++ b/test/table.py
@@ -0,0 +1,49 @@
+from tkinter import *
+
+import tkinter as tk
+from tkinter import ttk
+from tkinter.messagebox import showinfo
+
+root = tk.Tk()
+root.title('Treeview demo')
+root.geometry('620x200')
+
+# define columns
+columns = ('first_name', 'last_name', 'email')
+
+tree = ttk.Treeview(root, columns=columns, show='headings')
+
+# define headings
+tree.heading('first_name', text='First Name')
+tree.heading('last_name', text='Last Name')
+tree.heading('email', text='Email')
+
+# generate sample data
+contacts = []
+for n in range(1, 100):
+ contacts.append((f'first {n}', f'last {n}', f'email{n}@example.com'))
+
+# add data to the treeview
+for contact in contacts:
+ tree.insert('', tk.END, values=contact)
+
+
+def item_selected(event):
+ for selected_item in tree.selection():
+ item = tree.item(selected_item)
+ record = item['values']
+ # show a message
+ showinfo(title='Information', message=','.join(record))
+
+
+tree.bind('<<TreeviewSelect>>', item_selected)
+
+tree.grid(row=0, column=0, sticky='nsew')
+
+# add a scrollbar
+scrollbar = ttk.Scrollbar(root, orient=tk.VERTICAL, command=tree.yview)
+tree.configure(yscroll=scrollbar.set)
+scrollbar.grid(row=0, column=1, sticky='ns')
+
+# run the app
+root.mainloop()
diff --git a/widgets.py b/widgets.py
new file mode 100644
index 0000000..afc715a
--- /dev/null
+++ b/widgets.py
@@ -0,0 +1,97 @@
+
+from tkinter import *
+from tkinter import messagebox
+from PIL import ImageTk, Image
+
+import os
+os.chdir('assets')
+HOME = os.getcwd()
+
+global USERNAME
+USERNAME = ""
+
+
+class ContentBox(Frame):
+ def __init__(self, master, image_file, *pargs):
+ Frame.__init__(self, master, *pargs)
+
+ self.background = Canvas(self, highlightthickness=0)
+ self.background.pack(fill=BOTH, expand=YES)
+ self.background.bind('<Configure>', self._resize_image)
+
+ self.image = Image.open(image_file)
+ self.img_copy = self.image.copy()
+ self.background_image = ImageTk.PhotoImage(self.image)
+ self.image_id = self.background.create_image(0, 0, image=self.background_image, anchor='nw')
+
+ def set(self, image_file):
+ self.image = Image.open(image_file)
+ self.img_copy = self.image.copy()
+ self.image = self.img_copy.resize((self.background.winfo_width(),
+ self.background.winfo_height()))
+ self.background_image = ImageTk.PhotoImage(self.image)
+ self.background.itemconfigure(self.image_id, image=self.background_image)
+
+ def _resize_image(self, event):
+ self.image = self.img_copy.resize((event.width, event.height))
+ self.background_image = ImageTk.PhotoImage(self.image)
+ self.background.itemconfigure(self.image_id, image=self.background_image)
+
+
+class ButtonMenu(Frame):
+ def __init__(self, master, *pargs):
+ Frame.__init__(self, master, *pargs)
+ self.place(relx=0.5, rely=0.85, anchor=CENTER)
+ def additem(self, name, command):
+ Button(self, text=name, command=command, font=('', 12, 'bold'),
+ height=2, width=16, borderwidth=0,
+ background='black', foreground='white').pack(side=LEFT)
+
+
+class StatusBar(Frame):
+ def __init__(self, master, msgvar, *pargs):
+ self.bgcolor='#fdcc03'
+ self.fgcolor='black'
+ self.msgfont=('', 12)
+ self.optfont=('monospace', 12, 'bold')
+ Frame.__init__(self, master, background=self.bgcolor, *pargs)
+ self.message = Label(self, textvariable=msgvar, background=self.bgcolor, font=self.msgfont, foreground=self.fgcolor)
+ global USERNAME
+ self.username = Label(self, text=USERNAME, font=self.msgfont, background=self.bgcolor, foreground=self.fgcolor)
+ self.username.pack(side=LEFT)
+ self.message.pack(side=LEFT, fill=X, expand=TRUE)
+ def addmenu(self, optvar, opts, command=None):
+ self.menu = OptionMenu(self, optvar, *opts, command=command)
+ self.menu.config(width=12, borderwidth=0, font=self.optfont,
+ background=self.bgcolor, foreground='darkblue',
+ highlightthickness=0)
+ self.menu.pack(side=RIGHT)
+
+
+class SearchBox(Frame):
+ def __init__(self, master, search, command, *pargs):
+ Frame.__init__(self, master, background='white', *pargs)
+
+ self.placeholder = " 🔍 Search ... "
+ self.search = search
+ self.searchbox = Entry(self, textvariable=self.search, borderwidth=0, highlightthickness=0)
+ self.searchbox.pack(fill=BOTH, expand=TRUE, padx=10, pady=5)
+ self.searchbox.bind('<Key>', command)
+ def erase_placeholder(event=None):
+ if self.search.get() == self.placeholder:
+ self.searchbox.delete(0, END)
+ self.searchbox.configure(fg='black')
+ def set_placeholder(event=None):
+ if self.search.get() == "":
+ self.searchbox.insert(0, self.placeholder)
+ self.searchbox.configure(fg='grey')
+ set_placeholder()
+ self.searchbox.bind("<FocusIn>", erase_placeholder)
+ self.searchbox.bind("<FocusOut>", set_placeholder)
+ self.searchbox.bind('<Escape>', lambda event: self.master.focus_set())
+ self.master.bind('<Control-f>', lambda event: self.searchbox.focus())
+ self.master.focus_set()
+
+ def findtxt(self, event=None):
+ self.searchbox.focus()
+