From 8f0751170385989677392f806762a211f99412ef Mon Sep 17 00:00:00 2001 From: Vikas Kushwaha Date: Thu, 21 Nov 2024 13:23:10 +0530 Subject: First Commit --- .gitignore | 1 + README.md | 24 ++ assets/most-accurate-test.png | Bin 0 -> 1866900 bytes assets/myers-briggs-type-indicator.png | Bin 0 -> 1991881 bytes assets/ptypes/ENFJ1.png | Bin 0 -> 2872041 bytes assets/ptypes/ENFJ2.png | Bin 0 -> 2512192 bytes assets/ptypes/ENFJ3.png | Bin 0 -> 2679985 bytes assets/ptypes/ENFP1.png | Bin 0 -> 2869187 bytes assets/ptypes/ENFP2.png | Bin 0 -> 2486030 bytes assets/ptypes/ENFP3.png | Bin 0 -> 2718904 bytes assets/ptypes/ENTJ1.png | Bin 0 -> 2807317 bytes assets/ptypes/ENTJ2.png | Bin 0 -> 2506196 bytes assets/ptypes/ENTJ3.png | Bin 0 -> 2701728 bytes assets/ptypes/ENTP1.png | Bin 0 -> 2886415 bytes assets/ptypes/ENTP2.png | Bin 0 -> 2503483 bytes assets/ptypes/ENTP3.png | Bin 0 -> 2742121 bytes assets/ptypes/ESFJ1.png | Bin 0 -> 2823146 bytes assets/ptypes/ESFJ2.png | Bin 0 -> 2485077 bytes assets/ptypes/ESFJ3.png | Bin 0 -> 2792487 bytes assets/ptypes/ESFP1.png | Bin 0 -> 2850826 bytes assets/ptypes/ESFP2.png | Bin 0 -> 2557827 bytes assets/ptypes/ESFP3.png | Bin 0 -> 2731584 bytes assets/ptypes/ESTJ1.png | Bin 0 -> 2850233 bytes assets/ptypes/ESTJ2.png | Bin 0 -> 2521830 bytes assets/ptypes/ESTJ3.png | Bin 0 -> 2644923 bytes assets/ptypes/ESTP1.png | Bin 0 -> 2839452 bytes assets/ptypes/ESTP2.png | Bin 0 -> 2502733 bytes assets/ptypes/ESTP3.png | Bin 0 -> 2783233 bytes assets/ptypes/INFJ1.png | Bin 0 -> 2905320 bytes assets/ptypes/INFJ2.png | Bin 0 -> 2468520 bytes assets/ptypes/INFJ3.png | Bin 0 -> 2726341 bytes assets/ptypes/INFP1.png | Bin 0 -> 2826953 bytes assets/ptypes/INFP2.png | Bin 0 -> 2510158 bytes assets/ptypes/INFP3.png | Bin 0 -> 2683299 bytes assets/ptypes/INTJ1.png | Bin 0 -> 2902965 bytes assets/ptypes/INTJ1a.png | Bin 0 -> 2927513 bytes assets/ptypes/INTJ2.png | Bin 0 -> 2585781 bytes assets/ptypes/INTJ3.png | Bin 0 -> 2695543 bytes assets/ptypes/INTP1.png | Bin 0 -> 2810165 bytes assets/ptypes/INTP2.png | Bin 0 -> 2459104 bytes assets/ptypes/INTP3.png | Bin 0 -> 2721620 bytes assets/ptypes/ISFJ1.png | Bin 0 -> 2887111 bytes assets/ptypes/ISFJ2.png | Bin 0 -> 2556213 bytes assets/ptypes/ISFJ3.png | Bin 0 -> 2771930 bytes assets/ptypes/ISFP1.png | Bin 0 -> 2866015 bytes assets/ptypes/ISFP2.png | Bin 0 -> 2507054 bytes assets/ptypes/ISFP3.png | Bin 0 -> 2707965 bytes assets/ptypes/ISTJ1.png | Bin 0 -> 2794189 bytes assets/ptypes/ISTJ2.png | Bin 0 -> 2503150 bytes assets/ptypes/ISTJ3.png | Bin 0 -> 2683103 bytes assets/ptypes/ISTP1.png | Bin 0 -> 2853654 bytes assets/ptypes/ISTP2.png | Bin 0 -> 2460804 bytes assets/ptypes/ISTP3.png | Bin 0 -> 2702652 bytes assets/quiz/Q-13.png | Bin 0 -> 39627 bytes assets/quiz/Q00.png | Bin 0 -> 2482773 bytes assets/quiz/Q01.png | Bin 0 -> 2276983 bytes assets/quiz/Q02.png | Bin 0 -> 2013296 bytes assets/quiz/Q03.png | Bin 0 -> 1041543 bytes assets/quiz/Q10.png | Bin 0 -> 2300678 bytes assets/quiz/Q11.png | Bin 0 -> 2079170 bytes assets/quiz/Q12.png | Bin 0 -> 1792181 bytes assets/quiz/Q13.png | Bin 0 -> 688809 bytes assets/quiz/Q20.png | Bin 0 -> 2923834 bytes assets/quiz/Q21.png | Bin 0 -> 1975917 bytes assets/quiz/Q22.png | Bin 0 -> 1648591 bytes assets/quiz/Q23.png | Bin 0 -> 517435 bytes assets/quiz/Q30.png | Bin 0 -> 2410321 bytes assets/quiz/Q31.png | Bin 0 -> 2046644 bytes assets/quiz/Q32.png | Bin 0 -> 1739417 bytes assets/quiz/Q33.png | Bin 0 -> 525468 bytes assets/short-version.jpg | Bin 0 -> 526865 bytes assets/types.png | Bin 0 -> 446487 bytes frames.py | 405 +++++++++++++++++++++++++++++++++ main.py | 80 +++++++ requirements.txt | 2 + test/README.txt | 1 + test/database.py | 36 +++ test/double-click.py | 34 +++ test/fill-vs-expand.py | 11 + test/fixratio.py | 33 +++ test/frames.py | 16 ++ test/logs.py | 63 +++++ test/optionmenu.py | 30 +++ test/overlapping-widgets.py | 33 +++ test/placeholder.py | 24 ++ test/ptest.sql | 53 +++++ test/resizable-image.py | 84 +++++++ test/table.py | 49 ++++ widgets.py | 97 ++++++++ 89 files changed, 1076 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 assets/most-accurate-test.png create mode 100644 assets/myers-briggs-type-indicator.png create mode 100644 assets/ptypes/ENFJ1.png create mode 100644 assets/ptypes/ENFJ2.png create mode 100644 assets/ptypes/ENFJ3.png create mode 100644 assets/ptypes/ENFP1.png create mode 100644 assets/ptypes/ENFP2.png create mode 100644 assets/ptypes/ENFP3.png create mode 100644 assets/ptypes/ENTJ1.png create mode 100644 assets/ptypes/ENTJ2.png create mode 100644 assets/ptypes/ENTJ3.png create mode 100644 assets/ptypes/ENTP1.png create mode 100644 assets/ptypes/ENTP2.png create mode 100644 assets/ptypes/ENTP3.png create mode 100644 assets/ptypes/ESFJ1.png create mode 100644 assets/ptypes/ESFJ2.png create mode 100644 assets/ptypes/ESFJ3.png create mode 100644 assets/ptypes/ESFP1.png create mode 100644 assets/ptypes/ESFP2.png create mode 100644 assets/ptypes/ESFP3.png create mode 100644 assets/ptypes/ESTJ1.png create mode 100644 assets/ptypes/ESTJ2.png create mode 100644 assets/ptypes/ESTJ3.png create mode 100644 assets/ptypes/ESTP1.png create mode 100644 assets/ptypes/ESTP2.png create mode 100644 assets/ptypes/ESTP3.png create mode 100644 assets/ptypes/INFJ1.png create mode 100644 assets/ptypes/INFJ2.png create mode 100644 assets/ptypes/INFJ3.png create mode 100644 assets/ptypes/INFP1.png create mode 100644 assets/ptypes/INFP2.png create mode 100644 assets/ptypes/INFP3.png create mode 100644 assets/ptypes/INTJ1.png create mode 100644 assets/ptypes/INTJ1a.png create mode 100644 assets/ptypes/INTJ2.png create mode 100644 assets/ptypes/INTJ3.png create mode 100644 assets/ptypes/INTP1.png create mode 100644 assets/ptypes/INTP2.png create mode 100644 assets/ptypes/INTP3.png create mode 100644 assets/ptypes/ISFJ1.png create mode 100644 assets/ptypes/ISFJ2.png create mode 100644 assets/ptypes/ISFJ3.png create mode 100644 assets/ptypes/ISFP1.png create mode 100644 assets/ptypes/ISFP2.png create mode 100644 assets/ptypes/ISFP3.png create mode 100644 assets/ptypes/ISTJ1.png create mode 100644 assets/ptypes/ISTJ2.png create mode 100644 assets/ptypes/ISTJ3.png create mode 100644 assets/ptypes/ISTP1.png create mode 100644 assets/ptypes/ISTP2.png create mode 100644 assets/ptypes/ISTP3.png create mode 100644 assets/quiz/Q-13.png create mode 100644 assets/quiz/Q00.png create mode 100644 assets/quiz/Q01.png create mode 100644 assets/quiz/Q02.png create mode 100644 assets/quiz/Q03.png create mode 100644 assets/quiz/Q10.png create mode 100644 assets/quiz/Q11.png create mode 100644 assets/quiz/Q12.png create mode 100644 assets/quiz/Q13.png create mode 100644 assets/quiz/Q20.png create mode 100644 assets/quiz/Q21.png create mode 100644 assets/quiz/Q22.png create mode 100644 assets/quiz/Q23.png create mode 100644 assets/quiz/Q30.png create mode 100644 assets/quiz/Q31.png create mode 100644 assets/quiz/Q32.png create mode 100644 assets/quiz/Q33.png create mode 100644 assets/short-version.jpg create mode 100644 assets/types.png create mode 100644 frames.py create mode 100644 main.py create mode 100644 requirements.txt create mode 100644 test/README.txt create mode 100644 test/database.py create mode 100644 test/double-click.py create mode 100644 test/fill-vs-expand.py create mode 100644 test/fixratio.py create mode 100644 test/frames.py create mode 100644 test/logs.py create mode 100644 test/optionmenu.py create mode 100644 test/overlapping-widgets.py create mode 100644 test/placeholder.py create mode 100644 test/ptest.sql create mode 100644 test/resizable-image.py create mode 100644 test/table.py create mode 100644 widgets.py 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 Binary files /dev/null and b/assets/most-accurate-test.png differ diff --git a/assets/myers-briggs-type-indicator.png b/assets/myers-briggs-type-indicator.png new file mode 100644 index 0000000..fd01a88 Binary files /dev/null and b/assets/myers-briggs-type-indicator.png differ diff --git a/assets/ptypes/ENFJ1.png b/assets/ptypes/ENFJ1.png new file mode 100644 index 0000000..54a72b1 Binary files /dev/null and b/assets/ptypes/ENFJ1.png differ diff --git a/assets/ptypes/ENFJ2.png b/assets/ptypes/ENFJ2.png new file mode 100644 index 0000000..ce6fb0a Binary files /dev/null and b/assets/ptypes/ENFJ2.png differ diff --git a/assets/ptypes/ENFJ3.png b/assets/ptypes/ENFJ3.png new file mode 100644 index 0000000..79b6994 Binary files /dev/null and b/assets/ptypes/ENFJ3.png differ diff --git a/assets/ptypes/ENFP1.png b/assets/ptypes/ENFP1.png new file mode 100644 index 0000000..34efb28 Binary files /dev/null and b/assets/ptypes/ENFP1.png differ diff --git a/assets/ptypes/ENFP2.png b/assets/ptypes/ENFP2.png new file mode 100644 index 0000000..642d5a9 Binary files /dev/null and b/assets/ptypes/ENFP2.png differ diff --git a/assets/ptypes/ENFP3.png b/assets/ptypes/ENFP3.png new file mode 100644 index 0000000..60e7679 Binary files /dev/null and b/assets/ptypes/ENFP3.png differ diff --git a/assets/ptypes/ENTJ1.png b/assets/ptypes/ENTJ1.png new file mode 100644 index 0000000..6fa3e24 Binary files /dev/null and b/assets/ptypes/ENTJ1.png differ diff --git a/assets/ptypes/ENTJ2.png b/assets/ptypes/ENTJ2.png new file mode 100644 index 0000000..9b7093b Binary files /dev/null and b/assets/ptypes/ENTJ2.png differ diff --git a/assets/ptypes/ENTJ3.png b/assets/ptypes/ENTJ3.png new file mode 100644 index 0000000..acd365b Binary files /dev/null and b/assets/ptypes/ENTJ3.png differ diff --git a/assets/ptypes/ENTP1.png b/assets/ptypes/ENTP1.png new file mode 100644 index 0000000..011215e Binary files /dev/null and b/assets/ptypes/ENTP1.png differ diff --git a/assets/ptypes/ENTP2.png b/assets/ptypes/ENTP2.png new file mode 100644 index 0000000..062c2b9 Binary files /dev/null and b/assets/ptypes/ENTP2.png differ diff --git a/assets/ptypes/ENTP3.png b/assets/ptypes/ENTP3.png new file mode 100644 index 0000000..d3f61ab Binary files /dev/null and b/assets/ptypes/ENTP3.png differ diff --git a/assets/ptypes/ESFJ1.png b/assets/ptypes/ESFJ1.png new file mode 100644 index 0000000..31dc3b8 Binary files /dev/null and b/assets/ptypes/ESFJ1.png differ diff --git a/assets/ptypes/ESFJ2.png b/assets/ptypes/ESFJ2.png new file mode 100644 index 0000000..06c3871 Binary files /dev/null and b/assets/ptypes/ESFJ2.png differ diff --git a/assets/ptypes/ESFJ3.png b/assets/ptypes/ESFJ3.png new file mode 100644 index 0000000..4ab36e3 Binary files /dev/null and b/assets/ptypes/ESFJ3.png differ diff --git a/assets/ptypes/ESFP1.png b/assets/ptypes/ESFP1.png new file mode 100644 index 0000000..52458ac Binary files /dev/null and b/assets/ptypes/ESFP1.png differ diff --git a/assets/ptypes/ESFP2.png b/assets/ptypes/ESFP2.png new file mode 100644 index 0000000..17debc3 Binary files /dev/null and b/assets/ptypes/ESFP2.png differ diff --git a/assets/ptypes/ESFP3.png b/assets/ptypes/ESFP3.png new file mode 100644 index 0000000..d6e8f40 Binary files /dev/null and b/assets/ptypes/ESFP3.png differ diff --git a/assets/ptypes/ESTJ1.png b/assets/ptypes/ESTJ1.png new file mode 100644 index 0000000..8c489a2 Binary files /dev/null and b/assets/ptypes/ESTJ1.png differ diff --git a/assets/ptypes/ESTJ2.png b/assets/ptypes/ESTJ2.png new file mode 100644 index 0000000..4a8fba3 Binary files /dev/null and b/assets/ptypes/ESTJ2.png differ diff --git a/assets/ptypes/ESTJ3.png b/assets/ptypes/ESTJ3.png new file mode 100644 index 0000000..d43eb61 Binary files /dev/null and b/assets/ptypes/ESTJ3.png differ diff --git a/assets/ptypes/ESTP1.png b/assets/ptypes/ESTP1.png new file mode 100644 index 0000000..61f89e4 Binary files /dev/null and b/assets/ptypes/ESTP1.png differ diff --git a/assets/ptypes/ESTP2.png b/assets/ptypes/ESTP2.png new file mode 100644 index 0000000..c06bb9a Binary files /dev/null and b/assets/ptypes/ESTP2.png differ diff --git a/assets/ptypes/ESTP3.png b/assets/ptypes/ESTP3.png new file mode 100644 index 0000000..133390c Binary files /dev/null and b/assets/ptypes/ESTP3.png differ diff --git a/assets/ptypes/INFJ1.png b/assets/ptypes/INFJ1.png new file mode 100644 index 0000000..d498e0e Binary files /dev/null and b/assets/ptypes/INFJ1.png differ diff --git a/assets/ptypes/INFJ2.png b/assets/ptypes/INFJ2.png new file mode 100644 index 0000000..d45385c Binary files /dev/null and b/assets/ptypes/INFJ2.png differ diff --git a/assets/ptypes/INFJ3.png b/assets/ptypes/INFJ3.png new file mode 100644 index 0000000..9978447 Binary files /dev/null and b/assets/ptypes/INFJ3.png differ diff --git a/assets/ptypes/INFP1.png b/assets/ptypes/INFP1.png new file mode 100644 index 0000000..2a5367a Binary files /dev/null and b/assets/ptypes/INFP1.png differ diff --git a/assets/ptypes/INFP2.png b/assets/ptypes/INFP2.png new file mode 100644 index 0000000..b84e2f3 Binary files /dev/null and b/assets/ptypes/INFP2.png differ diff --git a/assets/ptypes/INFP3.png b/assets/ptypes/INFP3.png new file mode 100644 index 0000000..f3edf5e Binary files /dev/null and b/assets/ptypes/INFP3.png differ diff --git a/assets/ptypes/INTJ1.png b/assets/ptypes/INTJ1.png new file mode 100644 index 0000000..b84b831 Binary files /dev/null and b/assets/ptypes/INTJ1.png differ diff --git a/assets/ptypes/INTJ1a.png b/assets/ptypes/INTJ1a.png new file mode 100644 index 0000000..a027dec Binary files /dev/null and b/assets/ptypes/INTJ1a.png differ diff --git a/assets/ptypes/INTJ2.png b/assets/ptypes/INTJ2.png new file mode 100644 index 0000000..ac01ba2 Binary files /dev/null and b/assets/ptypes/INTJ2.png differ diff --git a/assets/ptypes/INTJ3.png b/assets/ptypes/INTJ3.png new file mode 100644 index 0000000..032f07a Binary files /dev/null and b/assets/ptypes/INTJ3.png differ diff --git a/assets/ptypes/INTP1.png b/assets/ptypes/INTP1.png new file mode 100644 index 0000000..eae9cfe Binary files /dev/null and b/assets/ptypes/INTP1.png differ diff --git a/assets/ptypes/INTP2.png b/assets/ptypes/INTP2.png new file mode 100644 index 0000000..2b76379 Binary files /dev/null and b/assets/ptypes/INTP2.png differ diff --git a/assets/ptypes/INTP3.png b/assets/ptypes/INTP3.png new file mode 100644 index 0000000..9366867 Binary files /dev/null and b/assets/ptypes/INTP3.png differ diff --git a/assets/ptypes/ISFJ1.png b/assets/ptypes/ISFJ1.png new file mode 100644 index 0000000..fe802a6 Binary files /dev/null and b/assets/ptypes/ISFJ1.png differ diff --git a/assets/ptypes/ISFJ2.png b/assets/ptypes/ISFJ2.png new file mode 100644 index 0000000..2715c13 Binary files /dev/null and b/assets/ptypes/ISFJ2.png differ diff --git a/assets/ptypes/ISFJ3.png b/assets/ptypes/ISFJ3.png new file mode 100644 index 0000000..ca46002 Binary files /dev/null and b/assets/ptypes/ISFJ3.png differ diff --git a/assets/ptypes/ISFP1.png b/assets/ptypes/ISFP1.png new file mode 100644 index 0000000..544ebfd Binary files /dev/null and b/assets/ptypes/ISFP1.png differ diff --git a/assets/ptypes/ISFP2.png b/assets/ptypes/ISFP2.png new file mode 100644 index 0000000..9469bf5 Binary files /dev/null and b/assets/ptypes/ISFP2.png differ diff --git a/assets/ptypes/ISFP3.png b/assets/ptypes/ISFP3.png new file mode 100644 index 0000000..c65de56 Binary files /dev/null and b/assets/ptypes/ISFP3.png differ diff --git a/assets/ptypes/ISTJ1.png b/assets/ptypes/ISTJ1.png new file mode 100644 index 0000000..070c90e Binary files /dev/null and b/assets/ptypes/ISTJ1.png differ diff --git a/assets/ptypes/ISTJ2.png b/assets/ptypes/ISTJ2.png new file mode 100644 index 0000000..07f17cf Binary files /dev/null and b/assets/ptypes/ISTJ2.png differ diff --git a/assets/ptypes/ISTJ3.png b/assets/ptypes/ISTJ3.png new file mode 100644 index 0000000..cdfcb53 Binary files /dev/null and b/assets/ptypes/ISTJ3.png differ diff --git a/assets/ptypes/ISTP1.png b/assets/ptypes/ISTP1.png new file mode 100644 index 0000000..d1ef8ac Binary files /dev/null and b/assets/ptypes/ISTP1.png differ diff --git a/assets/ptypes/ISTP2.png b/assets/ptypes/ISTP2.png new file mode 100644 index 0000000..969444b Binary files /dev/null and b/assets/ptypes/ISTP2.png differ diff --git a/assets/ptypes/ISTP3.png b/assets/ptypes/ISTP3.png new file mode 100644 index 0000000..6acd9b0 Binary files /dev/null and b/assets/ptypes/ISTP3.png differ diff --git a/assets/quiz/Q-13.png b/assets/quiz/Q-13.png new file mode 100644 index 0000000..58d8201 Binary files /dev/null and b/assets/quiz/Q-13.png differ diff --git a/assets/quiz/Q00.png b/assets/quiz/Q00.png new file mode 100644 index 0000000..bcfada7 Binary files /dev/null and b/assets/quiz/Q00.png differ diff --git a/assets/quiz/Q01.png b/assets/quiz/Q01.png new file mode 100644 index 0000000..5e1f76e Binary files /dev/null and b/assets/quiz/Q01.png differ diff --git a/assets/quiz/Q02.png b/assets/quiz/Q02.png new file mode 100644 index 0000000..fcbaad3 Binary files /dev/null and b/assets/quiz/Q02.png differ diff --git a/assets/quiz/Q03.png b/assets/quiz/Q03.png new file mode 100644 index 0000000..63f3701 Binary files /dev/null and b/assets/quiz/Q03.png differ diff --git a/assets/quiz/Q10.png b/assets/quiz/Q10.png new file mode 100644 index 0000000..3b16e43 Binary files /dev/null and b/assets/quiz/Q10.png differ diff --git a/assets/quiz/Q11.png b/assets/quiz/Q11.png new file mode 100644 index 0000000..11e7052 Binary files /dev/null and b/assets/quiz/Q11.png differ diff --git a/assets/quiz/Q12.png b/assets/quiz/Q12.png new file mode 100644 index 0000000..9bc9084 Binary files /dev/null and b/assets/quiz/Q12.png differ diff --git a/assets/quiz/Q13.png b/assets/quiz/Q13.png new file mode 100644 index 0000000..7a62c7d Binary files /dev/null and b/assets/quiz/Q13.png differ diff --git a/assets/quiz/Q20.png b/assets/quiz/Q20.png new file mode 100644 index 0000000..4850e82 Binary files /dev/null and b/assets/quiz/Q20.png differ diff --git a/assets/quiz/Q21.png b/assets/quiz/Q21.png new file mode 100644 index 0000000..168ada2 Binary files /dev/null and b/assets/quiz/Q21.png differ diff --git a/assets/quiz/Q22.png b/assets/quiz/Q22.png new file mode 100644 index 0000000..fb81b63 Binary files /dev/null and b/assets/quiz/Q22.png differ diff --git a/assets/quiz/Q23.png b/assets/quiz/Q23.png new file mode 100644 index 0000000..07c72bb Binary files /dev/null and b/assets/quiz/Q23.png differ diff --git a/assets/quiz/Q30.png b/assets/quiz/Q30.png new file mode 100644 index 0000000..f5eb802 Binary files /dev/null and b/assets/quiz/Q30.png differ diff --git a/assets/quiz/Q31.png b/assets/quiz/Q31.png new file mode 100644 index 0000000..db52095 Binary files /dev/null and b/assets/quiz/Q31.png differ diff --git a/assets/quiz/Q32.png b/assets/quiz/Q32.png new file mode 100644 index 0000000..5cd6660 Binary files /dev/null and b/assets/quiz/Q32.png differ diff --git a/assets/quiz/Q33.png b/assets/quiz/Q33.png new file mode 100644 index 0000000..ec2a472 Binary files /dev/null and b/assets/quiz/Q33.png differ diff --git a/assets/short-version.jpg b/assets/short-version.jpg new file mode 100644 index 0000000..9d27c7b Binary files /dev/null and b/assets/short-version.jpg differ diff --git a/assets/types.png b/assets/types.png new file mode 100644 index 0000000..fd49aee Binary files /dev/null and b/assets/types.png 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('', self.nextpage) + self.content.background.bind('', self.exit) + self.content.background.bind('', self.prevpage) + self.content.background.bind('', self.nextpage) + self.content.background.bind('', self.nextpage) + self.content.background.bind('', self.prevpage) + self.content.background.bind('', self.prevpage) + self.content.background.bind('', self.nextpage) + self.content.background.bind('', 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('', self.nextpage) + self.content.background.bind('', self.exit) + self.content.background.bind('', self.prevpage) + self.content.background.bind('', self.nextpage) + self.content.background.bind('', self.nextpage) + self.content.background.bind('', self.prevpage) + self.content.background.bind('', self.prevpage) + self.content.background.bind('', self.nextpage) + self.content.background.bind('', 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('', 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('', self.start_test) + self.usernameE.bind('', lambda event: self.focus_set()) + self.bind('', self.exit) + self.bind('', lambda event: self.usernameE.focus()) + self.bind('', 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('', self.select_item) + self.tree.bind('', self.select_item) + self.tree.bind('', self.select_item) + self.tree.bind('', self.exit) + self.bind('', 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("", self.start_test) + self.content.background.bind("", 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("", 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("",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. + + # 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('', 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("", 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('',erase) +e.bind('',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('', self._resize_image) +# self.background.bind('', 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('', self._resize_image) + self.image.bind('', 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('', resizer) +canvas.bind('', 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('<>', 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('', 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('', 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("", erase_placeholder) + self.searchbox.bind("", set_placeholder) + self.searchbox.bind('', lambda event: self.master.focus_set()) + self.master.bind('', lambda event: self.searchbox.focus()) + self.master.focus_set() + + def findtxt(self, event=None): + self.searchbox.focus() + -- cgit v1.2.3